diff --git a/CVE-2016-0777_CVE-2016-0778.patch b/CVE-2016-0777_CVE-2016-0778.patch new file mode 100644 index 0000000..ca2c704 --- /dev/null +++ b/CVE-2016-0777_CVE-2016-0778.patch @@ -0,0 +1,34 @@ +References: https://lists.mindrot.org/pipermail/openssh-unix-announce/2016-January/000124.html https://bugzilla.suse.com/show_bug.cgi?id=961645 https://bugzilla.suse.com/show_bug.cgi?id=961642 +--- readconf.c 30 Jul 2015 00:01:34 -0000 1.239 ++++ readconf.c 13 Jan 2016 23:17:23 -0000 +@@ -1648,7 +1648,7 @@ initialize_options(Options * options) + options->tun_remote = -1; + options->local_command = NULL; + options->permit_local_command = -1; +- options->use_roaming = -1; ++ options->use_roaming = 0; + options->visual_host_key = -1; + options->ip_qos_interactive = -1; + options->ip_qos_bulk = -1; +@@ -1819,8 +1819,7 @@ fill_default_options(Options * options) + options->tun_remote = SSH_TUNID_ANY; + if (options->permit_local_command == -1) + options->permit_local_command = 0; +- if (options->use_roaming == -1) +- options->use_roaming = 1; ++ options->use_roaming = 0; + if (options->visual_host_key == -1) + options->visual_host_key = 0; + if (options->ip_qos_interactive == -1) +--- ssh.c 30 Jul 2015 00:01:34 -0000 1.420 ++++ ssh.c 13 Jan 2016 23:17:23 -0000 +@@ -1882,9 +1882,6 @@ ssh_session2(void) + fork_postauth(); + } + +- if (options.use_roaming) +- request_roaming(); +- + return client_loop(tty_flag, tty_flag ? + options.escape_char : SSH_ESCAPECHAR_NONE, id); + } diff --git a/README.SUSE b/README.SuSE similarity index 90% rename from README.SUSE rename to README.SuSE index 1552003..10b49da 100644 --- a/README.SUSE +++ b/README.SuSE @@ -1,4 +1,4 @@ -This is OpenSSH version compiled for SUSE. +This is OpenSSH version 5.6p1. There are following changes in default settings of ssh client: diff --git a/openssh-6.6p1-audit1-remove_duplicit_audit.patch b/openssh-6.6p1-audit1-remove_duplicit_audit.patch new file mode 100644 index 0000000..96d9c54 --- /dev/null +++ b/openssh-6.6p1-audit1-remove_duplicit_audit.patch @@ -0,0 +1,33 @@ +# Don't audit SSH_INVALID_USER twice. +# PRIVSEP(getpwnamallow()) a few lines above already did this. +# +# based on: +# https://bugzilla.mindrot.org/show_bug.cgi?id=1402 +# https://bugzilla.mindrot.org/attachment.cgi?id=2010 +# by jchadima@redhat.com +# +# PRIVSEP(getpwnamallow()) a few lines above already did this. + +diff --git a/openssh-6.6p1/auth2.c b/openssh-6.6p1/auth2.c +--- a/openssh-6.6p1/auth2.c ++++ b/openssh-6.6p1/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-6.6p1-audit2-better_audit_of_user_actions.patch b/openssh-6.6p1-audit2-better_audit_of_user_actions.patch new file mode 100644 index 0000000..656bbe3 --- /dev/null +++ b/openssh-6.6p1-audit2-better_audit_of_user_actions.patch @@ -0,0 +1,867 @@ +# extended auditing of user actions +# based on: +# https://bugzilla.mindrot.org/show_bug.cgi?id=1402 +# https://bugzilla.mindrot.org/attachment.cgi?id=2011 +# by jchadima@redhat.com + +diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c +--- a/openssh-6.6p1/audit-bsm.c ++++ b/openssh-6.6p1/audit-bsm.c +@@ -370,20 +370,33 @@ 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 */ + } + +diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c +--- a/openssh-6.6p1/audit-linux.c ++++ b/openssh-6.6p1/audit-linux.c +@@ -30,97 +30,210 @@ + #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 "servconf.h" + #include "canohost.h" + ++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)); ++ } ++} ++ ++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); + } + } + + #endif /* USE_LINUX_AUDIT */ +diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c +--- a/openssh-6.6p1/audit.c ++++ b/openssh-6.6p1/audit.c +@@ -135,16 +135,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 +180,34 @@ 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); ++} ++ + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h +--- a/openssh-6.6p1/audit.h ++++ b/openssh-6.6p1/audit.h +@@ -44,14 +44,16 @@ enum ssh_audit_event_type { + SSH_CONNECTION_CLOSE, /* closed after attempting auth or session */ + SSH_CONNECTION_ABANDON, /* closed without completing auth */ + SSH_AUDIT_UNKNOWN + }; + typedef enum ssh_audit_event_type ssh_audit_event_t; + + 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 *); + + #endif /* _SSH_AUDIT_H */ +diff --git a/openssh-6.6p1/monitor.c b/openssh-6.6p1/monitor.c +--- a/openssh-6.6p1/monitor.c ++++ b/openssh-6.6p1/monitor.c +@@ -175,16 +175,17 @@ 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 *); + #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 *); + #endif + + static int monitor_read_log(struct monitor *); + + static Authctxt *authctxt; + static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ + + /* local state for key verify */ +@@ -255,16 +256,17 @@ struct mon_table mon_dispatch_postauth20 + {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, + {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}, + #endif + {0, 0, NULL} + }; + + struct mon_table mon_dispatch_proto15[] = { + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, + {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, +@@ -297,16 +299,17 @@ struct mon_table mon_dispatch_proto15[] + + struct mon_table mon_dispatch_postauth15[] = { + {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}, + #endif + {0, 0, NULL} + }; + + struct mon_table *mon_dispatch; + + /* Specifies if a certain message is allowed at the moment */ + +@@ -1420,16 +1423,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; +@@ -1742,21 +1751,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) + { +diff --git a/openssh-6.6p1/monitor.h b/openssh-6.6p1/monitor.h +--- a/openssh-6.6p1/monitor.h ++++ b/openssh-6.6p1/monitor.h +@@ -59,16 +59,17 @@ 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_ANS_AUDIT_COMMAND = 114, MONITOR_REQ_AUDIT_END_COMMAND = 115, + + }; + + struct mm_master; + struct monitor { + int m_recvfd; + int m_sendfd; + int m_log_recvfd; +diff --git a/openssh-6.6p1/monitor_wrap.c b/openssh-6.6p1/monitor_wrap.c +--- a/openssh-6.6p1/monitor_wrap.c ++++ b/openssh-6.6p1/monitor_wrap.c +@@ -1184,27 +1184,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) + { +diff --git a/openssh-6.6p1/monitor_wrap.h b/openssh-6.6p1/monitor_wrap.h +--- a/openssh-6.6p1/monitor_wrap.h ++++ b/openssh-6.6p1/monitor_wrap.h +@@ -69,17 +69,18 @@ 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 *); + #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-6.6p1/session.c b/openssh-6.6p1/session.c +--- a/openssh-6.6p1/session.c ++++ b/openssh-6.6p1/session.c +@@ -740,16 +740,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); + ++#ifndef HAVE_OSF_SIA ++ /* do_login in the child did not affect state in this process, ++ compensate. From an architectural standpoint, this is extremely ++ ugly. */ ++ if (!(options.use_login && command == NULL)) ++ audit_count_session_open(); ++#endif ++ + /* Enter interactive session. */ + s->ptymaster = ptymaster; + packet_set_interactive(1, + 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); +@@ -834,25 +842,29 @@ do_exec(Session *s, const char *command) + session_type, + tty == NULL ? "" : " on ", + tty == NULL ? "" : tty, + s->pw->pw_name, + get_remote_ipaddr(), + get_remote_port()); + + #ifdef SSH_AUDIT_EVENTS ++ if (s->command != NULL || s->command_handle != -1) ++ fatal("do_exec: command already set"); + if (command != NULL) +- PRIVSEP(audit_run_command(command)); ++ s->command = xstrdup(command); + else if (s->ttyfd == -1) { + char *shell = s->pw->pw_shell; + + if (shell[0] == '\0') /* empty shell means /bin/sh */ + shell =_PATH_BSHELL; +- PRIVSEP(audit_run_command(shell)); ++ s->command = xstrdup(shell); + } ++ if (s->command != NULL) ++ s->command_handle = PRIVSEP(audit_run_command(s->command)); + #endif + if (s->ttyfd != -1) + ret = do_exec_pty(s, command); + else + ret = do_exec_no_pty(s, command); + + original_command = NULL; + +@@ -1908,16 +1920,17 @@ 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; ++ sessions[id].command_handle = -1; + sessions[id].next_unused = sessions_first_unused; + sessions_first_unused = id; + } + + Session * + session_new(void) + { + Session *s, *tmp; +@@ -1990,16 +2003,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("session_by_id: unknown id %d", 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; +@@ -2506,16 +2532,40 @@ 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) { ++ 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) { ++ 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; + int do_xauth; + + debug("session_close: session %d pid %ld", s->self, (long)s->pid); + +@@ -2546,16 +2596,20 @@ session_close(Session *s) + int status; + + waitpid(pid, &status, 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) { +@@ -2760,16 +2814,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 */ +@@ -2808,10 +2871,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-6.6p1/session.h b/openssh-6.6p1/session.h +--- a/openssh-6.6p1/session.h ++++ b/openssh-6.6p1/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-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -2532,13 +2532,14 @@ cleanup_exit(int i) + if (kill(pmonitor->m_pid, SIGKILL) != 0 && + errno != ESRCH) + error("%s: kill(%d): %s", __func__, + pmonitor->m_pid, strerror(errno)); + } + } + #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-6.6p1-audit3-key_auth_usage-fips.patch b/openssh-6.6p1-audit3-key_auth_usage-fips.patch new file mode 100644 index 0000000..ac95216 --- /dev/null +++ b/openssh-6.6p1-audit3-key_auth_usage-fips.patch @@ -0,0 +1,61 @@ +# HG changeset patch +# Parent 5482d21e8bd06309af51dea77a5f3668859fb2a0 + +diff --git a/openssh-6.6p1/auth-rsa.c b/openssh-6.6p1/auth-rsa.c +--- a/openssh-6.6p1/auth-rsa.c ++++ b/openssh-6.6p1/auth-rsa.c +@@ -94,16 +94,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); + } +@@ -121,22 +125,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); ++ rv = timingsafe_bcmp(response, mdbuf, dgst_len) == 0; ++ ++#ifdef SSH_AUDIT_EVENTS ++ fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX); ++ if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) { ++ debug("unsuccessful audit"); ++ rv = 0; + } +- /* Correct answer. */ +- return (1); ++ free(fp); ++#endif ++ ++ return rv; + } + + /* + * 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-6.6p1-audit3-key_auth_usage.patch b/openssh-6.6p1-audit3-key_auth_usage.patch new file mode 100644 index 0000000..1471ec8 --- /dev/null +++ b/openssh-6.6p1-audit3-key_auth_usage.patch @@ -0,0 +1,506 @@ +# auditing key-based authentication (both server and client) +# based on: +# https://bugzilla.mindrot.org/show_bug.cgi?id=1402 +# https://bugzilla.mindrot.org/attachment.cgi?id=2012 +# (replaces: https://bugzilla.mindrot.org/attachment.cgi?id=1975) +# by jchadima@redhat.com + +diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c +--- a/openssh-6.6p1/audit-bsm.c ++++ b/openssh-6.6p1/audit-bsm.c +@@ -401,16 +401,22 @@ audit_session_open(struct logininfo *li) + } + + 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)) +diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c +--- a/openssh-6.6p1/audit-linux.c ++++ b/openssh-6.6p1/audit-linux.c +@@ -36,16 +36,18 @@ + #include "log.h" + #include "audit.h" + #include "key.h" + #include "hostfile.h" + #include "auth.h" + #include "servconf.h" + #include "canohost.h" + ++#define AUDIT_LOG_SIZE 128 ++ + extern ServerOptions options; + extern Authctxt *the_authctxt; + extern u_int utmp_len; + const char* audit_username(void); + + static void + linux_audit_user_logxxx(int uid, const char *username, + const char *hostname, const char *ip, const char *ttyn, int success, int event) +@@ -125,16 +127,47 @@ linux_audit_user_auth(int uid, const cha + rc = 0; + errno = saved_errno; + if (rc < 0) { + fatal_report: + fatal("linux_audit_write_entry failed: %s", strerror(errno)); + } + } + ++int ++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, rc, saved_errno; ++ ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return 1; /* No audit support in kernel */ ++ else ++ return 0; /* Must prevent login */ ++ } ++ snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port()); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s 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 */ +diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c +--- a/openssh-6.6p1/audit.c ++++ b/openssh-6.6p1/audit.c +@@ -31,16 +31,17 @@ + + #ifdef SSH_AUDIT_EVENTS + + #include "audit.h" + #include "log.h" + #include "key.h" + #include "hostfile.h" + #include "auth.h" ++#include "xmalloc.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; + +@@ -106,16 +107,32 @@ 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 = key_fingerprint(key, key_fp_type_select(), 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); ++} ++ + # 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 +@@ -204,10 +221,22 @@ audit_run_command(const char *command) + */ + void + audit_end_command(int handle, const char *command) + { + debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), + audit_username(), command); + } + ++/* ++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. ++ * ++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. ++ */ ++int ++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) ++{ ++ debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s, result %d", ++ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, ++ fp, rv); ++} + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h +--- a/openssh-6.6p1/audit.h ++++ b/openssh-6.6p1/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 */ +@@ -50,10 +51,12 @@ typedef enum ssh_audit_event_type ssh_au + 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 *); + 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 *); + + #endif /* _SSH_AUDIT_H */ +diff --git a/openssh-6.6p1/auth.h b/openssh-6.6p1/auth.h +--- a/openssh-6.6p1/auth.h ++++ b/openssh-6.6p1/auth.h +@@ -178,16 +178,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 *); +@@ -195,16 +196,17 @@ check_key_in_hostfiles(struct passwd *, + /* hostkey handling */ + Key *get_hostkey_by_index(int); + Key *get_hostkey_public_by_index(int); + Key *get_hostkey_public_by_type(int); + Key *get_hostkey_private_by_type(int); + int get_hostkey_index(Key *); + int ssh1_session_key(BIGNUM *); + void sshd_hostkey_sign(Key *, Key *, u_char **, u_int *, u_char *, u_int); ++int hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); + + /* debug messages during authentication */ + void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); + void auth_debug_send(void); + void auth_debug_reset(void); + + struct passwd *fakepw(void); + +diff --git a/openssh-6.6p1/auth2-hostbased.c b/openssh-6.6p1/auth2-hostbased.c +--- a/openssh-6.6p1/auth2-hostbased.c ++++ b/openssh-6.6p1/auth2-hostbased.c +@@ -124,33 +124,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-6.6p1/auth2-pubkey.c b/openssh-6.6p1/auth2-pubkey.c +--- a/openssh-6.6p1/auth2-pubkey.c ++++ b/openssh-6.6p1/auth2-pubkey.c +@@ -153,17 +153,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)) && +- 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; + buffer_free(&b); + free(sig); + } else { + debug("test whether pkalg/pkblob are acceptable"); + packet_check_eom(); + +@@ -190,16 +190,28 @@ done: + debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); + if (key != NULL) + key_free(key); + free(pkalg); + free(pkblob); + return authenticated; + } + ++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; ++} ++ + void + pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) + { + char *fp, *extra; + va_list ap; + int i; + + extra = NULL; +diff --git a/openssh-6.6p1/monitor.c b/openssh-6.6p1/monitor.c +--- a/openssh-6.6p1/monitor.c ++++ b/openssh-6.6p1/monitor.c +@@ -1340,26 +1340,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); +@@ -1370,17 +1374,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"); + + key_free(key); + free(blob); + free(signature); + free(data); + +diff --git a/openssh-6.6p1/monitor_wrap.c b/openssh-6.6p1/monitor_wrap.c +--- a/openssh-6.6p1/monitor_wrap.c ++++ b/openssh-6.6p1/monitor_wrap.c +@@ -426,30 +426,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__); +@@ -457,16 +458,29 @@ 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); ++} ++ ++ + /* Export key state after authentication */ + Newkeys * + mm_newkeys_from_blob(u_char *blob, int blen) + { + Buffer b; + u_int len; + Newkeys *newkey = NULL; + Enc *enc; +diff --git a/openssh-6.6p1/monitor_wrap.h b/openssh-6.6p1/monitor_wrap.h +--- a/openssh-6.6p1/monitor_wrap.h ++++ b/openssh-6.6p1/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 mm_user_key_allowed(struct passwd *, Key *); + int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); + int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); +-int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); ++int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int); ++int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int); + int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); + int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); + BIGNUM *mm_auth_rsa_generate_challenge(Key *); + + #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 *); diff --git a/openssh-6.6p1-audit4-kex_results-fips.patch b/openssh-6.6p1-audit4-kex_results-fips.patch new file mode 100644 index 0000000..7f781d7 --- /dev/null +++ b/openssh-6.6p1-audit4-kex_results-fips.patch @@ -0,0 +1,82 @@ +# HG changeset patch +# Parent 274a545b591567f1378c1086ad3ba40c911a8bd6 + +diff --git a/openssh-6.6p1/Makefile.in b/openssh-6.6p1/Makefile.in +--- a/openssh-6.6p1/Makefile.in ++++ b/openssh-6.6p1/Makefile.in +@@ -72,17 +72,18 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o + atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ + monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ + kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ + msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ + ssh-pkcs11.o krl.o smult_curve25519_ref.o \ + kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ + ssh-ed25519.o digest-openssl.o hmac.o \ + sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ +- fips.o ++ fips.o \ ++ auditstub.o + + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o \ + roaming_common.o roaming_client.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 \ +diff --git a/openssh-6.6p1/cipher.c b/openssh-6.6p1/cipher.c +--- a/openssh-6.6p1/cipher.c ++++ b/openssh-6.6p1/cipher.c +@@ -54,30 +54,16 @@ + + /* compatibility with old or broken OpenSSL versions */ + #include "openbsd-compat/openssl-compat.h" + + extern const EVP_CIPHER *evp_ssh1_bf(void); + extern const EVP_CIPHER *evp_ssh1_3des(void); + extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); + +-struct Cipher { +- char *name; +- int number; /* for ssh1 only */ +- u_int block_size; +- u_int key_len; +- u_int iv_len; /* defaults to block_size */ +- u_int auth_len; +- u_int discard_len; +- u_int flags; +-#define CFLAG_CBC (1<<0) +-#define CFLAG_CHACHAPOLY (1<<1) +- const EVP_CIPHER *(*evptype)(void); +-}; +- + static const struct Cipher ciphers_all[] = { + { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, + { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, + { "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 }, + + { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, + { "blowfish-cbc", +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -119,16 +119,18 @@ + #endif + #include "monitor_wrap.h" + #include "roaming.h" + #include "ssh-sandbox.h" + #include "version.h" + + #include "fips.h" + ++#include "audit.h" ++ + #ifdef LIBWRAP + #include + #include + int allow_severity; + int deny_severity; + #endif /* LIBWRAP */ + + #ifndef O_NOCTTY diff --git a/openssh-6.6p1-audit4-kex_results.patch b/openssh-6.6p1-audit4-kex_results.patch new file mode 100644 index 0000000..d6bb569 --- /dev/null +++ b/openssh-6.6p1-audit4-kex_results.patch @@ -0,0 +1,701 @@ +# key exhange auditing +# based on: +# https://bugzilla.mindrot.org/show_bug.cgi?id=1402 +# https://bugzilla.mindrot.org/attachment.cgi?id=2013 +# (replaces: https://bugzilla.mindrot.org/attachment.cgi?id=1976) +# by jchadima@redhat.com + +diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c +--- a/openssh-6.6p1/audit-bsm.c ++++ b/openssh-6.6p1/audit-bsm.c +@@ -468,9 +468,21 @@ 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, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} + #endif /* BSM */ +diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c +--- a/openssh-6.6p1/audit-linux.c ++++ b/openssh-6.6p1/audit-linux.c +@@ -35,16 +35,18 @@ + + #include "log.h" + #include "audit.h" + #include "key.h" + #include "hostfile.h" + #include "auth.h" + #include "servconf.h" + #include "canohost.h" ++#include "packet.h" ++#include "cipher.h" + + #define AUDIT_LOG_SIZE 128 + + extern ServerOptions options; + extern Authctxt *the_authctxt; + extern u_int utmp_len; + const char* audit_username(void); + +@@ -264,9 +266,65 @@ audit_event(ssh_audit_event_t event) + 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 ++} ++ ++void ++audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, ++ uid_t uid) ++{ ++#ifdef AUDIT_CRYPTO_SESSION ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ const static char *direction[] = { "from-server", "from-client", "both" }; ++ Cipher *cipher = cipher_by_name(enc); ++ char *s; ++ ++ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", ++ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, ++ (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 ++} ++ + #endif /* USE_LINUX_AUDIT */ +diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c +--- a/openssh-6.6p1/audit.c ++++ b/openssh-6.6p1/audit.c +@@ -23,24 +23,27 @@ + * (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" + + /* + * 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; +@@ -123,16 +126,28 @@ audit_key(int host_user, int *rv, const + crypto_name = "ssh-rsa1"; + else + crypto_name = key_ssh_name(key); + if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0) + *rv = 0; + free(fp); + } + ++void ++audit_unsupported(int what) ++{ ++ PRIVSEP(audit_unsupported_body(what)); ++} ++ ++void ++audit_kex(int ctos, char *enc, char *mac, char *comp) ++{ ++ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid())); ++} ++ + # 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 +@@ -233,10 +248,31 @@ audit_end_command(int handle, const char + */ + int + audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) + { + debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s, result %d", + host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, + fp, rv); + } ++ ++/* ++ * This will be called when the protocol negotiation fails. ++ */ ++void ++audit_unsupported_body(int what) ++{ ++ debug("audit unsupported protocol euid %d type %d", geteuid(), what); ++} ++ ++/* ++ * This will be called on succesfull protocol negotiation. ++ */ ++void ++audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, ++ uid_t uid) ++{ ++ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, enc, mac, compress, (long)pid, ++ (unsigned)uid); ++} + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h +--- a/openssh-6.6p1/audit.h ++++ b/openssh-6.6p1/audit.h +@@ -53,10 +53,14 @@ 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 *); + int audit_run_command(const char *); + void audit_end_command(int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); + int audit_keyusage(int, const char *, unsigned, char *, int); + void audit_key(int, int *, const Key *); ++void audit_unsupported(int); ++void audit_kex(int, char *, char *, char *); ++void audit_unsupported_body(int); ++void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); + + #endif /* _SSH_AUDIT_H */ +diff --git a/openssh-6.6p1/auditstub.c b/openssh-6.6p1/auditstub.c +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/auditstub.c +@@ -0,0 +1,39 @@ ++/* $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 ++ */ ++ ++void ++audit_unsupported(int n) ++{ ++} ++ ++void ++audit_kex(int ctos, char *enc, char *mac, char *comp) ++{ ++} ++ +diff --git a/openssh-6.6p1/cipher.h b/openssh-6.6p1/cipher.h +--- a/openssh-6.6p1/cipher.h ++++ b/openssh-6.6p1/cipher.h +@@ -58,17 +58,30 @@ + #define SSH_CIPHER_MAX 31 + + #define CIPHER_ENCRYPT 1 + #define CIPHER_DECRYPT 0 + + typedef struct Cipher Cipher; + typedef struct CipherContext CipherContext; + +-struct Cipher; ++struct Cipher { ++ char *name; ++ int number; /* for ssh1 only */ ++ u_int block_size; ++ u_int key_len; ++ u_int iv_len; /* defaults to block_size */ ++ u_int auth_len; ++ u_int discard_len; ++ u_int flags; ++#define CFLAG_CBC (1<<0) ++#define CFLAG_CHACHAPOLY (1<<1) ++ const EVP_CIPHER *(*evptype)(void); ++}; ++ + struct CipherContext { + int plaintext; + int encrypt; + EVP_CIPHER_CTX evp; + struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ + const Cipher *cipher; + }; + +diff --git a/openssh-6.6p1/kex.c b/openssh-6.6p1/kex.c +--- a/openssh-6.6p1/kex.c ++++ b/openssh-6.6p1/kex.c +@@ -45,16 +45,17 @@ + #include "kex.h" + #include "log.h" + #include "mac.h" + #include "match.h" + #include "dispatch.h" + #include "monitor.h" + #include "roaming.h" + #include "digest.h" ++#include "audit.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 +@@ -346,53 +347,65 @@ kex_kexinit_finish(Kex *kex) + fatal("Unsupported key exchange %d", kex->kex_type); + } + } + + static void + choose_enc(Enc *enc, char *client, char *server) + { + char *name = match_list(client, server, NULL); +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(0); ++#endif + fatal("no matching cipher found: client %s server %s", + client, server); ++ } + if ((enc->cipher = cipher_by_name(name)) == NULL) + fatal("matching cipher is not supported: %s", name); + enc->name = name; + enc->enabled = 0; + enc->iv = NULL; + enc->iv_len = cipher_ivlen(enc->cipher); + enc->key = NULL; + enc->key_len = cipher_keylen(enc->cipher); + enc->block_size = cipher_blocksize(enc->cipher); + } + + static void + choose_mac(Mac *mac, char *client, char *server) + { + char *name = match_list(client, server, NULL); +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(1); ++#endif + fatal("no matching mac found: client %s server %s", + client, server); ++ } + if (mac_setup(mac, name) < 0) + fatal("unsupported mac %s", name); + /* truncate the key */ + if (datafellows & SSH_BUG_HMAC) + mac->key_len = 16; + mac->name = name; + mac->key = NULL; + mac->enabled = 0; + } + + static void + choose_comp(Comp *comp, char *client, char *server) + { + char *name = match_list(client, server, NULL); +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(2); ++#endif + fatal("no matching comp found: client %s server %s", client, server); ++ } + if (strcmp(name, "zlib@openssh.com") == 0) { + comp->type = COMP_DELAYED; + } else if (strcmp(name, "zlib") == 0) { + comp->type = COMP_ZLIB; + } else if (strcmp(name, "none") == 0) { + comp->type = COMP_NONE; + } else { + fatal("unsupported comp %s", name); +@@ -497,16 +510,19 @@ kex_choose_conf(Kex *kex) + if (authlen == 0) + choose_mac(&newkeys->mac, cprop[nmac], sprop[nmac]); + choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); + debug("kex: %s %s %s %s", + ctos ? "client->server" : "server->client", + newkeys->enc.name, + authlen == 0 ? newkeys->mac.name : "", + newkeys->comp.name); ++#ifdef SSH_AUDIT_EVENTS ++ audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name); ++#endif + } + choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); + choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], + sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); + need = dh_need = 0; + for (mode = 0; mode < MODE_MAX; mode++) { + newkeys = kex->newkeys[mode]; + need = MAX(need, newkeys->enc.key_len); +diff --git a/openssh-6.6p1/monitor.c b/openssh-6.6p1/monitor.c +--- a/openssh-6.6p1/monitor.c ++++ b/openssh-6.6p1/monitor.c +@@ -92,16 +92,17 @@ + #endif + #include "monitor_wrap.h" + #include "monitor_fdpass.h" + #include "misc.h" + #include "compat.h" + #include "ssh2.h" + #include "roaming.h" + #include "authfd.h" ++#include "audit.h" + + #ifdef GSSAPI + static Gssctxt *gsscontext = NULL; + #endif + + /* Imports */ + extern ServerOptions options; + extern u_int utmp_len; +@@ -176,16 +177,18 @@ int mm_answer_gss_accept_ctx(int, Buffer + int mm_answer_gss_userok(int, Buffer *); + int mm_answer_gss_checkmic(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 *); + #endif + + static int monitor_read_log(struct monitor *); + + static Authctxt *authctxt; + static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ + + /* local state for key verify */ +@@ -227,16 +230,18 @@ 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}, + #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}, +@@ -257,16 +262,18 @@ struct mon_table mon_dispatch_postauth20 + {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}, + #endif + {0, 0, NULL} + }; + + struct mon_table mon_dispatch_proto15[] = { + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, + {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, +@@ -288,28 +295,32 @@ 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}, + #endif + {0, 0, NULL} + }; + + struct mon_table mon_dispatch_postauth15[] = { + {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}, + #endif + {0, 0, NULL} + }; + + struct mon_table *mon_dispatch; + + /* Specifies if a certain message is allowed at the moment */ + +@@ -2187,8 +2198,52 @@ mm_answer_gss_userok(int sock, Buffer *m + + auth_method = "gssapi-with-mic"; + + /* Monitor loop will terminate if authenticated */ + return (authenticated); + } + #endif /* GSSAPI */ + ++#ifdef SSH_AUDIT_EVENTS ++int ++mm_answer_audit_unsupported_body(int sock, Buffer *m) ++{ ++ int what; ++ ++ what = buffer_get_int(m); ++ ++ audit_unsupported_body(what); ++ ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_kex_body(int sock, Buffer *m) ++{ ++ int ctos, len; ++ char *cipher, *mac, *compress; ++ pid_t pid; ++ uid_t uid; ++ ++ ctos = buffer_get_int(m); ++ cipher = buffer_get_string(m, &len); ++ mac = buffer_get_string(m, &len); ++ compress = buffer_get_string(m, &len); ++ pid = buffer_get_int64(m); ++ uid = buffer_get_int64(m); ++ ++ audit_kex_body(ctos, cipher, mac, compress, pid, uid); ++ ++ free(cipher); ++ free(mac); ++ free(compress); ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); ++ return 0; ++} ++ ++#endif /* SSH_AUDIT_EVENTS */ ++ +diff --git a/openssh-6.6p1/monitor.h b/openssh-6.6p1/monitor.h +--- a/openssh-6.6p1/monitor.h ++++ b/openssh-6.6p1/monitor.h +@@ -60,16 +60,18 @@ 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_ANS_AUDIT_COMMAND = 114, MONITOR_REQ_AUDIT_END_COMMAND = 115, ++ MONITOR_REQ_AUDIT_UNSUPPORTED = 116, MONITOR_ANS_AUDIT_UNSUPPORTED = 117, ++ MONITOR_REQ_AUDIT_KEX = 118, MONITOR_ANS_AUDIT_KEX = 119, + + }; + + struct mm_master; + struct monitor { + int m_recvfd; + int m_sendfd; + int m_log_recvfd; +diff --git a/openssh-6.6p1/monitor_wrap.c b/openssh-6.6p1/monitor_wrap.c +--- a/openssh-6.6p1/monitor_wrap.c ++++ b/openssh-6.6p1/monitor_wrap.c +@@ -1320,8 +1320,46 @@ mm_ssh_gssapi_userok(char *user) + authenticated = buffer_get_int(&m); + + buffer_free(&m); + debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); + return (authenticated); + } + #endif /* GSSAPI */ + ++#ifdef SSH_AUDIT_EVENTS ++void ++mm_audit_unsupported_body(int what) ++{ ++ Buffer m; ++ ++ buffer_init(&m); ++ buffer_put_int(&m, what); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, ++ &m); ++ ++ buffer_free(&m); ++} ++ ++void ++mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid, ++ uid_t uid) ++{ ++ Buffer m; ++ ++ buffer_init(&m); ++ buffer_put_int(&m, ctos); ++ buffer_put_cstring(&m, cipher ? cipher : ""); ++ buffer_put_cstring(&m, mac ? mac : ""); ++ buffer_put_cstring(&m, compress ? compress : ""); ++ buffer_put_int64(&m, pid); ++ buffer_put_int64(&m, uid); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, ++ &m); ++ ++ buffer_free(&m); ++} ++#endif /* SSH_AUDIT_EVENTS */ ++ +diff --git a/openssh-6.6p1/monitor_wrap.h b/openssh-6.6p1/monitor_wrap.h +--- a/openssh-6.6p1/monitor_wrap.h ++++ b/openssh-6.6p1/monitor_wrap.h +@@ -72,16 +72,18 @@ int mm_sshpam_respond(void *, u_int, cha + void mm_sshpam_free_ctx(void *); + #endif + + #ifdef SSH_AUDIT_EVENTS + #include "audit.h" + void mm_audit_event(ssh_audit_event_t); + int mm_audit_run_command(const char *); + void mm_audit_end_command(int, const char *); ++void mm_audit_unsupported_body(int); ++void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t); + #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-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -2325,16 +2325,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(2, cipher_name(cipher_type), "crc", "none"); ++#endif ++ + debug("Encryption type: %.200s", cipher_name(cipher_type)); + + /* Get the encrypted integer. */ + if ((session_key_int = BN_new()) == NULL) + fatal("do_ssh1_kex: BN_new failed"); + packet_get_bignum(session_key_int); + + protocol_flags = packet_get_int(); diff --git a/openssh-6.6p1-audit5-session_key_destruction.patch b/openssh-6.6p1-audit5-session_key_destruction.patch new file mode 100644 index 0000000..cee4029 --- /dev/null +++ b/openssh-6.6p1-audit5-session_key_destruction.patch @@ -0,0 +1,983 @@ +# session key destruction and auditing +# based on: +# https://bugzilla.mindrot.org/show_bug.cgi?id=1402 +# https://bugzilla.mindrot.org/attachment.cgi?id=2014 +# by jchadima@redhat.com + +diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c +--- a/openssh-6.6p1/audit-bsm.c ++++ b/openssh-6.6p1/audit-bsm.c +@@ -480,9 +480,15 @@ audit_unsupported_body(int what) + /* not implemented */ + } + + void + audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid) + { + /* not implemented */ + } ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} + #endif /* BSM */ +diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c +--- a/openssh-6.6p1/audit-linux.c ++++ b/openssh-6.6p1/audit-linux.c +@@ -289,24 +289,25 @@ audit_unsupported_body(int what) + /* no problem, the next instruction will be fatal() */ + return; + audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, + buf, NULL, get_remote_ipaddr(), NULL, 0); + audit_close(audit_fd); + #endif + } + ++const static char *direction[] = { "from-server", "from-client", "both" }; ++ + void + audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, + uid_t uid) + { + #ifdef AUDIT_CRYPTO_SESSION + char buf[AUDIT_LOG_SIZE]; + int audit_fd, audit_ok; +- const static char *direction[] = { "from-server", "from-client", "both" }; + Cipher *cipher = cipher_by_name(enc); + char *s; + + snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", + direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, + (intmax_t)pid, (intmax_t)uid, + get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port()); + free(s); +@@ -322,9 +323,37 @@ audit_kex_body(int ctos, char *enc, char + 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"); ++} ++ + #endif /* USE_LINUX_AUDIT */ +diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c +--- a/openssh-6.6p1/audit.c ++++ b/openssh-6.6p1/audit.c +@@ -138,16 +138,22 @@ audit_unsupported(int what) + } + + void + audit_kex(int ctos, char *enc, char *mac, char *comp) + { + PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid())); + } + ++void ++audit_session_key_free(int ctos) ++{ ++ PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid())); ++} ++ + # ifndef CUSTOM_SSH_AUDIT_EVENTS + /* + * Null implementations of audit functions. + * 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 +@@ -269,10 +275,20 @@ audit_unsupported_body(int what) + void + audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, + uid_t uid) + { + debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u", + (unsigned)geteuid(), ctos, enc, mac, compress, (long)pid, + (unsigned)uid); + } ++ ++/* ++ * This will be called on succesfull session key discard ++ */ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ debug("audit session key discard euid %u direction %d from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); ++} + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h +--- a/openssh-6.6p1/audit.h ++++ b/openssh-6.6p1/audit.h +@@ -57,10 +57,12 @@ int audit_run_command(const char *); + void audit_end_command(int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); + int audit_keyusage(int, const char *, unsigned, char *, int); + void audit_key(int, int *, const Key *); + void audit_unsupported(int); + void audit_kex(int, char *, char *, char *); + void audit_unsupported_body(int); + void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); ++void audit_session_key_free(int ctos); ++void audit_session_key_free_body(int ctos, pid_t, uid_t); + + #endif /* _SSH_AUDIT_H */ +diff --git a/openssh-6.6p1/auditstub.c b/openssh-6.6p1/auditstub.c +--- a/openssh-6.6p1/auditstub.c ++++ b/openssh-6.6p1/auditstub.c +@@ -22,18 +22,29 @@ + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Red Hat author: Jan F. Chadima + */ + ++#include ++ + void + audit_unsupported(int n) + { + } + + void + audit_kex(int ctos, char *enc, char *mac, char *comp) + { + } + ++void ++audit_session_key_free(int ctos) ++{ ++} ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++} +diff --git a/openssh-6.6p1/kex.c b/openssh-6.6p1/kex.c +--- a/openssh-6.6p1/kex.c ++++ b/openssh-6.6p1/kex.c +@@ -700,8 +700,39 @@ dump_digest(char *msg, u_char *digest, i + if (i%32 == 31) + fprintf(stderr, "\n"); + else if (i%8 == 7) + fprintf(stderr, " "); + } + fprintf(stderr, "\n"); + } + #endif ++ ++static void ++enc_destroy(Enc *enc) ++{ ++ if (enc == NULL) ++ return; ++ ++ if (enc->key) { ++ memset(enc->key, 0, enc->key_len); ++ free(enc->key); ++ } ++ ++ if (enc->iv) { ++ memset(enc->iv, 0, enc->block_size); ++ free(enc->iv); ++ } ++ ++ memset(enc, 0, sizeof(*enc)); ++} ++ ++void ++newkeys_destroy(Newkeys *newkeys) ++{ ++ if (newkeys == NULL) ++ return; ++ ++ enc_destroy(&newkeys->enc); ++ mac_destroy(&newkeys->mac); ++ memset(&newkeys->comp, 0, sizeof(newkeys->comp)); ++} ++ +diff --git a/openssh-6.6p1/kex.h b/openssh-6.6p1/kex.h +--- a/openssh-6.6p1/kex.h ++++ b/openssh-6.6p1/kex.h +@@ -162,16 +162,18 @@ void kexdh_client(Kex *); + void kexdh_server(Kex *); + void kexgex_client(Kex *); + void kexgex_server(Kex *); + void kexecdh_client(Kex *); + void kexecdh_server(Kex *); + void kexc25519_client(Kex *); + void kexc25519_server(Kex *); + ++void newkeys_destroy(Newkeys *newkeys); ++ + void + kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, + BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); + void + kexgex_hash(int, char *, char *, char *, int, char *, + int, u_char *, int, int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, + BIGNUM *, BIGNUM *, u_char **, u_int *); + #ifdef OPENSSL_HAS_ECC +diff --git a/openssh-6.6p1/mac.c b/openssh-6.6p1/mac.c +--- a/openssh-6.6p1/mac.c ++++ b/openssh-6.6p1/mac.c +@@ -253,16 +253,30 @@ mac_clear(Mac *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(Mac *mac) ++{ ++ if (mac == NULL) ++ return; ++ ++ if (mac->key) { ++ memset(mac->key, 0, mac->key_len); ++ free(mac->key); ++ } ++ ++ memset(mac, 0, sizeof(*mac)); ++} ++ + /* XXX copied from ciphers_valid */ + #define MAC_SEP "," + int + mac_valid(const char *names) + { + char *maclist, *cp, *p; + + if (names == NULL || strcmp(names, "") == 0) +diff --git a/openssh-6.6p1/mac.h b/openssh-6.6p1/mac.h +--- a/openssh-6.6p1/mac.h ++++ b/openssh-6.6p1/mac.h +@@ -24,8 +24,9 @@ + */ + + int mac_valid(const char *); + char *mac_alg_list(char); + int mac_setup(Mac *, char *); + int mac_init(Mac *); + u_char *mac_compute(Mac *, u_int32_t, u_char *, int); + void mac_clear(Mac *); ++void mac_destroy(Mac *); +diff --git a/openssh-6.6p1/monitor.c b/openssh-6.6p1/monitor.c +--- a/openssh-6.6p1/monitor.c ++++ b/openssh-6.6p1/monitor.c +@@ -179,16 +179,17 @@ int mm_answer_gss_checkmic(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 *); + #endif + + static int monitor_read_log(struct monitor *); + + static Authctxt *authctxt; + static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ + + /* local state for key verify */ +@@ -232,16 +233,17 @@ struct mon_table mon_dispatch_proto20[] + {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}, + #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}, +@@ -264,16 +266,17 @@ struct mon_table mon_dispatch_postauth20 + {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}, + #endif + {0, 0, NULL} + }; + + struct mon_table mon_dispatch_proto15[] = { + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, + {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, +@@ -297,30 +300,32 @@ struct mon_table mon_dispatch_proto15[] + {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}, + #endif + {0, 0, NULL} + }; + + struct mon_table mon_dispatch_postauth15[] = { + {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}, + #endif + {0, 0, NULL} + }; + + struct mon_table *mon_dispatch; + + /* Specifies if a certain message is allowed at the moment */ + +@@ -1949,21 +1954,23 @@ mm_get_keystate(struct monitor *pmonitor + goto skip; + } else { + /* Get the Kex for rekeying */ + *pmonitor->m_pkex = mm_get_kex(&m); + } + + blob = buffer_get_string(&m, &bloblen); + current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); ++ memset(blob, 0, bloblen); + free(blob); + + debug3("%s: Waiting for second key", __func__); + blob = buffer_get_string(&m, &bloblen); + current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); ++ memset(blob, 0, bloblen); + free(blob); + + /* Now get sequence numbers for the packets */ + seqnr = buffer_get_int(&m); + blocks = buffer_get_int64(&m); + packets = buffer_get_int(&m); + bytes = buffer_get_int64(&m); + packet_set_state(MODE_OUT, seqnr, blocks, packets, bytes); +@@ -1999,16 +2006,31 @@ mm_get_keystate(struct monitor *pmonitor + + /* Roaming */ + if (compat20) { + child_state.sent_bytes = buffer_get_int64(&m); + child_state.recv_bytes = buffer_get_int64(&m); + } + + buffer_free(&m); ++ ++#ifdef SSH_AUDIT_EVENTS ++ if (compat20) { ++ buffer_init(&m); ++ mm_request_receive_expect(pmonitor->m_sendfd, ++ MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); ++ mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m); ++ buffer_free(&m); ++ } ++#endif ++ ++ /* Drain any buffered messages from the child */ ++ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) ++ ; ++ + } + + + /* Allocation functions for zlib */ + void * + mm_zalloc(struct mm_master *mm, u_int ncount, u_int size) + { + size_t len = (size_t) size * ncount; +@@ -2240,10 +2262,28 @@ mm_answer_audit_kex_body(int sock, Buffe + free(mac); + free(compress); + buffer_clear(m); + + mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); + return 0; + } + ++int ++mm_answer_audit_session_key_free_body(int sock, Buffer *m) ++{ ++ int ctos; ++ pid_t pid; ++ uid_t uid; ++ ++ ctos = buffer_get_int(m); ++ pid = buffer_get_int64(m); ++ uid = buffer_get_int64(m); ++ ++ audit_session_key_free_body(ctos, pid, uid); ++ ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m); ++ return 0; ++} + #endif /* SSH_AUDIT_EVENTS */ + +diff --git a/openssh-6.6p1/monitor.h b/openssh-6.6p1/monitor.h +--- a/openssh-6.6p1/monitor.h ++++ b/openssh-6.6p1/monitor.h +@@ -62,16 +62,17 @@ enum monitor_reqtype { + 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_ANS_AUDIT_COMMAND = 114, MONITOR_REQ_AUDIT_END_COMMAND = 115, + MONITOR_REQ_AUDIT_UNSUPPORTED = 116, MONITOR_ANS_AUDIT_UNSUPPORTED = 117, + MONITOR_REQ_AUDIT_KEX = 118, MONITOR_ANS_AUDIT_KEX = 119, ++ MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 120, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 121, + + }; + + struct mm_master; + struct monitor { + int m_recvfd; + int m_sendfd; + int m_log_recvfd; +diff --git a/openssh-6.6p1/monitor_wrap.c b/openssh-6.6p1/monitor_wrap.c +--- a/openssh-6.6p1/monitor_wrap.c ++++ b/openssh-6.6p1/monitor_wrap.c +@@ -649,22 +649,24 @@ mm_send_keystate(struct monitor *monitor + __func__, packet_get_newkeys(MODE_OUT), + packet_get_newkeys(MODE_IN)); + + /* Keys from Kex */ + if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen)) + fatal("%s: conversion of newkeys failed", __func__); + + buffer_put_string(&m, blob, bloblen); ++ memset(blob, 0, bloblen); + free(blob); + + if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) + fatal("%s: conversion of newkeys failed", __func__); + + buffer_put_string(&m, blob, bloblen); ++ memset(blob, 0, bloblen); + free(blob); + + packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes); + buffer_put_int(&m, seqnr); + buffer_put_int64(&m, blocks); + buffer_put_int(&m, packets); + buffer_put_int64(&m, bytes); + packet_get_state(MODE_IN, &seqnr, &blocks, &packets, &bytes); +@@ -1356,10 +1358,25 @@ mm_audit_kex_body(int ctos, char *cipher + 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); ++} + #endif /* SSH_AUDIT_EVENTS */ + +diff --git a/openssh-6.6p1/monitor_wrap.h b/openssh-6.6p1/monitor_wrap.h +--- a/openssh-6.6p1/monitor_wrap.h ++++ b/openssh-6.6p1/monitor_wrap.h +@@ -74,16 +74,17 @@ void mm_sshpam_free_ctx(void *); + + #ifdef SSH_AUDIT_EVENTS + #include "audit.h" + void mm_audit_event(ssh_audit_event_t); + int mm_audit_run_command(const char *); + void mm_audit_end_command(int, const char *); + void mm_audit_unsupported_body(int); + void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t); ++void mm_audit_session_key_free_body(int, pid_t, uid_t); + #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-6.6p1/packet.c b/openssh-6.6p1/packet.c +--- a/openssh-6.6p1/packet.c ++++ b/openssh-6.6p1/packet.c +@@ -56,16 +56,17 @@ + #include + #include + #include + #include + #include + #include + + #include "xmalloc.h" ++#include "audit.h" + #include "buffer.h" + #include "packet.h" + #include "crc32.h" + #include "compress.h" + #include "deattack.h" + #include "channels.h" + #include "compat.h" + #include "ssh1.h" +@@ -469,41 +470,51 @@ packet_get_connection_in(void) + /* Returns the descriptor used for writing. */ + + int + packet_get_connection_out(void) + { + return active_state->connection_out; + } + ++static int ++packet_state_has_keys (const struct session_state *state) ++{ ++ return state != NULL && ++ (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL); ++} ++ + /* Closes the connection and clears and frees internal data structures. */ + + void + packet_close(void) + { + if (!active_state->initialized) + return; + active_state->initialized = 0; +- if (active_state->connection_in == active_state->connection_out) { +- shutdown(active_state->connection_out, SHUT_RDWR); +- close(active_state->connection_out); +- } else { +- close(active_state->connection_in); +- close(active_state->connection_out); +- } + buffer_free(&active_state->input); + buffer_free(&active_state->output); + buffer_free(&active_state->outgoing_packet); + buffer_free(&active_state->incoming_packet); + if (active_state->compression_buffer_ready) { + buffer_free(&active_state->compression_buffer); + buffer_compress_uninit(); + } +- cipher_cleanup(&active_state->send_context); +- cipher_cleanup(&active_state->receive_context); ++ if (packet_state_has_keys(active_state)) { ++ cipher_cleanup(&active_state->send_context); ++ cipher_cleanup(&active_state->receive_context); ++ audit_session_key_free(2); ++ } ++ if (active_state->connection_in == active_state->connection_out) { ++ shutdown(active_state->connection_out, SHUT_RDWR); ++ close(active_state->connection_out); ++ } else { ++ close(active_state->connection_in); ++ close(active_state->connection_out); ++ } + } + + /* Sets remote side protocol flags. */ + + void + packet_set_protocol_flags(u_int protocol_flags) + { + active_state->remote_protocol_flags = protocol_flags; +@@ -729,16 +740,35 @@ packet_send1(void) + + /* + * Note that the packet is now only buffered in output. It won't be + * actually sent until packet_write_wait or packet_write_poll is + * called. + */ + } + ++static void ++newkeys_destroy_and_free(Newkeys *newkeys) ++{ ++ if (newkeys == NULL) ++ return; ++ ++ free(newkeys->enc.name); ++ ++ mac_clear(&newkeys->mac); ++ /* MAC may happen to be empty - if the GCM mode of AES is used */ ++ if (newkeys->mac.name) ++ free(newkeys->mac.name); ++ ++ free(newkeys->comp.name); ++ ++ newkeys_destroy(newkeys); ++ free(newkeys); ++} ++ + void + set_newkeys(int mode) + { + Enc *enc; + Mac *mac; + Comp *comp; + CipherContext *cc; + u_int64_t *max_blocks; +@@ -754,31 +784,19 @@ set_newkeys(int mode) + } else { + cc = &active_state->receive_context; + crypt_type = CIPHER_DECRYPT; + active_state->p_read.packets = active_state->p_read.blocks = 0; + max_blocks = &active_state->max_blocks_in; + } + if (active_state->newkeys[mode] != NULL) { + debug("set_newkeys: rekeying"); ++ audit_session_key_free(mode); + cipher_cleanup(cc); +- enc = &active_state->newkeys[mode]->enc; +- mac = &active_state->newkeys[mode]->mac; +- comp = &active_state->newkeys[mode]->comp; +- mac_clear(mac); +- explicit_bzero(enc->iv, enc->iv_len); +- explicit_bzero(enc->key, enc->key_len); +- explicit_bzero(mac->key, mac->key_len); +- free(enc->name); +- free(enc->iv); +- free(enc->key); +- free(mac->name); +- free(mac->key); +- free(comp->name); +- free(active_state->newkeys[mode]); ++ newkeys_destroy_and_free(active_state->newkeys[mode]); + } + active_state->newkeys[mode] = kex_get_newkeys(mode); + if (active_state->newkeys[mode] == NULL) + fatal("newkeys: no keys for mode %d", mode); + enc = &active_state->newkeys[mode]->enc; + mac = &active_state->newkeys[mode]->mac; + comp = &active_state->newkeys[mode]->comp; + if (cipher_authlen(enc->cipher) == 0 && mac_init(mac) == 0) +@@ -2004,54 +2022,93 @@ packet_get_output(void) + } + + void * + packet_get_newkeys(int mode) + { + return (void *)active_state->newkeys[mode]; + } + ++static void ++packet_destroy_state(struct session_state *state) ++{ ++ if (state == NULL) ++ return; ++ ++ cipher_cleanup(&state->receive_context); ++ cipher_cleanup(&state->send_context); ++ ++ buffer_free(&state->input); ++ buffer_free(&state->output); ++ buffer_free(&state->outgoing_packet); ++ buffer_free(&state->incoming_packet); ++ buffer_free(&state->compression_buffer); ++ newkeys_destroy_and_free(state->newkeys[MODE_IN]); ++ state->newkeys[MODE_IN] = NULL; ++ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); ++ state->newkeys[MODE_OUT] = NULL; ++ mac_destroy(state->packet_discard_mac); ++// TAILQ_HEAD(, packet) outgoing; ++// memset(state, 0, sizeof(state)); ++} ++ ++void ++packet_destroy_all(int audit_it, int privsep) ++{ ++ if (audit_it) ++ audit_it = packet_state_has_keys (active_state) || ++ packet_state_has_keys (backup_state); ++ packet_destroy_state(active_state); ++ packet_destroy_state(backup_state); ++ if (audit_it) { ++#ifdef SSH_AUDIT_EVENTS ++ if (privsep) ++ audit_session_key_free(2); ++ else ++ audit_session_key_free_body(2, getpid(), getuid()); ++#endif ++ } ++} ++ + /* + * Save the state for the real connection, and use a separate state when + * resuming a suspended connection. + */ + void + packet_backup_state(void) + { +- struct session_state *tmp; +- + close(active_state->connection_in); + active_state->connection_in = -1; + close(active_state->connection_out); + active_state->connection_out = -1; +- if (backup_state) +- tmp = backup_state; +- else +- tmp = alloc_session_state(); + backup_state = active_state; +- active_state = tmp; ++ active_state = alloc_session_state(); + } + + /* + * Swap in the old state when resuming a connecion. + */ + void + packet_restore_state(void) + { + struct session_state *tmp; + void *buf; + u_int len; + + tmp = backup_state; + backup_state = active_state; + active_state = tmp; + active_state->connection_in = backup_state->connection_in; +- backup_state->connection_in = -1; + active_state->connection_out = backup_state->connection_out; +- backup_state->connection_out = -1; + len = buffer_len(&backup_state->input); + if (len > 0) { + buf = buffer_ptr(&backup_state->input); + buffer_append(&active_state->input, buf, len); + buffer_clear(&backup_state->input); + add_recv_bytes(len); + } ++ backup_state->connection_in = -1; ++ backup_state->connection_out = -1; ++ packet_destroy_state(backup_state); ++ free(backup_state); ++ backup_state = NULL; + } ++ +diff --git a/openssh-6.6p1/packet.h b/openssh-6.6p1/packet.h +--- a/openssh-6.6p1/packet.h ++++ b/openssh-6.6p1/packet.h +@@ -119,9 +119,10 @@ void packet_set_rekey_limits(u_int32_t, + time_t packet_get_rekey_timeout(void); + + void packet_backup_state(void); + void packet_restore_state(void); + + void *packet_get_input(void); + void *packet_get_output(void); + ++void packet_destroy_all(int, int); + #endif /* PACKET_H */ +diff --git a/openssh-6.6p1/session.c b/openssh-6.6p1/session.c +--- a/openssh-6.6p1/session.c ++++ b/openssh-6.6p1/session.c +@@ -1694,16 +1694,19 @@ do_child(Session *s, const char *command + int env_size; + char *argv[ARGV_MAX]; + const char *shell, *shell0, *hostname = NULL; + struct passwd *pw = s->pw; + int r = 0; + + /* remove hostkey from the child's memory */ + destroy_sensitive_data(); ++ /* Don't audit this - both us and the parent would be talking to the ++ monitor over a single socket, with no synchronization. */ ++ packet_destroy_all(0, 1); + + /* Force a password change */ + if (s->authctxt->force_pwchange) { + do_setusercontext(pw); + child_close_fds(); + do_pwchange(s); + exit(1); + } +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -720,16 +720,18 @@ privsep_preauth(Authctxt *authctxt) + setproctitle("%s", "[net]"); + if (box != NULL) + ssh_sandbox_child(box); + + return 0; + } + } + ++extern Newkeys *current_keys[]; ++ + static void + privsep_postauth(Authctxt *authctxt) + { + u_int32_t rnd[256]; + + #ifdef DISABLE_FD_PASSING + if (1) { + #else +@@ -744,16 +746,20 @@ 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); ++ newkeys_destroy(current_keys[MODE_OUT]); ++ newkeys_destroy(current_keys[MODE_IN]); ++ audit_session_key_free_body(2, getpid(), getuid()); ++ packet_destroy_all(0, 0); + monitor_child_postauth(pmonitor); + + /* NEVERREACHED */ + exit(0); + } + + /* child */ + +@@ -2118,16 +2124,17 @@ main(int ac, char **av) + do_authentication(authctxt); + } + /* + * 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. + */ +@@ -2170,16 +2177,18 @@ main(int ac, char **av) + + packet_set_timeout(options.client_alive_interval, + options.client_alive_count_max); + + /* Start session. */ + do_authenticated(authctxt); + + /* The connection has been terminated. */ ++ packet_destroy_all(1, 1); ++ + packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); + packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); + verbose("Transferred: sent %llu, received %llu bytes", + (unsigned long long)obytes, (unsigned long long)ibytes); + + verbose("Closing connection to %.500s port %d", remote_ip, remote_port); + + #ifdef USE_PAM +@@ -2526,26 +2535,38 @@ 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->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) && !mm_is_monitor(); ++ packet_destroy_all(1, is_privsep_child); + #ifdef SSH_AUDIT_EVENTS + /* done after do_cleanup so it can cancel the PAM auth 'thread' */ + if ((the_authctxt == NULL || !the_authctxt->authenticated) && + (!use_privsep || mm_is_monitor())) + audit_event(SSH_CONNECTION_ABANDON); + #endif + _exit(i); + } diff --git a/openssh-6.6p1-audit6-server_key_destruction.patch b/openssh-6.6p1-audit6-server_key_destruction.patch new file mode 100644 index 0000000..73821e8 --- /dev/null +++ b/openssh-6.6p1-audit6-server_key_destruction.patch @@ -0,0 +1,742 @@ +# server key destruction and auditing +# based on: +# https://bugzilla.mindrot.org/show_bug.cgi?id=1402 +# https://bugzilla.mindrot.org/attachment.cgi?id=2015 +# by jchadima@redhat.com + +diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c +--- a/openssh-6.6p1/audit-bsm.c ++++ b/openssh-6.6p1/audit-bsm.c +@@ -486,9 +486,27 @@ audit_kex_body(int ctos, char *enc, char + /* 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-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c +--- a/openssh-6.6p1/audit-linux.c ++++ b/openssh-6.6p1/audit-linux.c +@@ -351,9 +351,55 @@ audit_session_key_free_body(int ctos, pi + 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-6.6p1/audit.c b/openssh-6.6p1/audit.c +--- a/openssh-6.6p1/audit.c ++++ b/openssh-6.6p1/audit.c +@@ -285,10 +285,29 @@ audit_kex_body(int ctos, char *enc, char + * 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-6.6p1/audit.h b/openssh-6.6p1/audit.h +--- a/openssh-6.6p1/audit.h ++++ b/openssh-6.6p1/audit.h +@@ -43,26 +43,30 @@ enum ssh_audit_event_type { + 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 + }; + 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 *); + int audit_run_command(const char *); + void audit_end_command(int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); + int audit_keyusage(int, const char *, unsigned, char *, int); + void audit_key(int, int *, const Key *); + void audit_unsupported(int); + void audit_kex(int, char *, char *, char *); + void audit_unsupported_body(int); + void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); + void audit_session_key_free(int ctos); + void audit_session_key_free_body(int ctos, pid_t, uid_t); ++void audit_destroy_sensitive_data(const char *, pid_t, uid_t); ++void audit_generate_ephemeral_server_key(const char *); + + #endif /* _SSH_AUDIT_H */ +diff --git a/openssh-6.6p1/key.c b/openssh-6.6p1/key.c +--- a/openssh-6.6p1/key.c ++++ b/openssh-6.6p1/key.c +@@ -1964,16 +1964,43 @@ key_demote(const Key *k) + fatal("key_demote: bad key type %d", k->type); + break; + } + + return (pk); + } + + int ++key_is_private(const Key *k) ++{ ++ switch (k->type) { ++ case KEY_RSA_CERT_V00: ++ case KEY_RSA_CERT: ++ case KEY_RSA1: ++ case KEY_RSA: ++ return k->rsa->d != NULL; ++ case KEY_DSA_CERT_V00: ++ case KEY_DSA_CERT: ++ case KEY_DSA: ++ return k->dsa->priv_key != NULL; ++#ifdef OPENSSL_HAS_ECC ++ case KEY_ECDSA_CERT: ++ case KEY_ECDSA: ++ return EC_KEY_get0_private_key(k->ecdsa) != NULL; ++#endif ++ case KEY_ED25519_CERT: ++ case KEY_ED25519: ++ return k->ed25519_sk != NULL; ++ default: ++ fatal("key_is_private: bad key type %d", k->type); ++ return 1; ++ } ++} ++ ++int + key_is_cert(const Key *k) + { + if (k == NULL) + return 0; + return key_type_is_cert(k->type); + } + + /* Return the cert-less equivalent to a certified key type */ +diff --git a/openssh-6.6p1/key.h b/openssh-6.6p1/key.h +--- a/openssh-6.6p1/key.h ++++ b/openssh-6.6p1/key.h +@@ -113,16 +113,17 @@ int key_read(Key *, char **); + u_int key_size(const Key *); + enum fp_type key_fp_type_select(void); + char *key_fp_type_str(enum fp_type); + + Key *key_generate(int, u_int); + Key *key_from_private(const Key *); + int key_type_from_name(char *); + int key_is_cert(const Key *); ++int key_is_private(const Key *k); + int key_type_is_cert(int); + int key_type_plain(int); + int key_to_certified(Key *, int); + int key_drop_cert(Key *); + int key_certify(Key *, Key *); + void key_cert_copy(const Key *, struct Key *); + int key_cert_check_authority(const Key *, int, int, const char *, + const char **); +diff --git a/openssh-6.6p1/monitor.c b/openssh-6.6p1/monitor.c +--- a/openssh-6.6p1/monitor.c ++++ b/openssh-6.6p1/monitor.c +@@ -109,16 +109,18 @@ extern u_int utmp_len; + extern Newkeys *current_keys[]; + extern z_stream incoming_stream; + extern z_stream outgoing_stream; + 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 */ + + struct { + z_stream incoming; + z_stream outgoing; + u_char *keyin; + u_int keyinlen; + u_char *keyout; +@@ -180,16 +182,17 @@ int mm_answer_gss_checkmic(int, Buffer * + + #ifdef SSH_AUDIT_EVENTS + int mm_answer_audit_event(int, Buffer *); + int mm_answer_audit_command(int, Buffer *); + int mm_answer_audit_end_command(int, Buffer *); + int mm_answer_audit_unsupported_body(int, Buffer *); + int mm_answer_audit_kex_body(int, Buffer *); + int mm_answer_audit_session_key_free_body(int, Buffer *); ++int mm_answer_audit_server_key_free(int, Buffer *); + #endif + + static int monitor_read_log(struct monitor *); + + static Authctxt *authctxt; + static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ + + /* local state for key verify */ +@@ -234,16 +237,17 @@ struct mon_table mon_dispatch_proto20[] + {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}, +@@ -267,16 +271,17 @@ struct mon_table mon_dispatch_postauth20 + {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[] = { + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, + {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, +@@ -301,31 +306,33 @@ struct mon_table mon_dispatch_proto15[] + {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 + {0, 0, NULL} + }; + + struct mon_table mon_dispatch_postauth15[] = { + {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 + {0, 0, NULL} + }; + + struct mon_table *mon_dispatch; + + /* Specifies if a certain message is allowed at the moment */ + +@@ -1739,16 +1746,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); +@@ -2280,10 +2289,31 @@ mm_answer_audit_session_key_free_body(in + + 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); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m); ++ return 0; ++} + #endif /* SSH_AUDIT_EVENTS */ + +diff --git a/openssh-6.6p1/monitor.h b/openssh-6.6p1/monitor.h +--- a/openssh-6.6p1/monitor.h ++++ b/openssh-6.6p1/monitor.h +@@ -63,16 +63,17 @@ enum monitor_reqtype { + MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, + MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, + MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, + MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, + MONITOR_ANS_AUDIT_COMMAND = 114, MONITOR_REQ_AUDIT_END_COMMAND = 115, + MONITOR_REQ_AUDIT_UNSUPPORTED = 116, MONITOR_ANS_AUDIT_UNSUPPORTED = 117, + MONITOR_REQ_AUDIT_KEX = 118, MONITOR_ANS_AUDIT_KEX = 119, + MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 120, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 121, ++ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 122, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 123, + + }; + + struct mm_master; + struct monitor { + int m_recvfd; + int m_sendfd; + int m_log_recvfd; +diff --git a/openssh-6.6p1/monitor_wrap.c b/openssh-6.6p1/monitor_wrap.c +--- a/openssh-6.6p1/monitor_wrap.c ++++ b/openssh-6.6p1/monitor_wrap.c +@@ -1373,10 +1373,26 @@ mm_audit_session_key_free_body(int ctos, + 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); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, ++ &m); ++ buffer_free(&m); ++} + #endif /* SSH_AUDIT_EVENTS */ + +diff --git a/openssh-6.6p1/monitor_wrap.h b/openssh-6.6p1/monitor_wrap.h +--- a/openssh-6.6p1/monitor_wrap.h ++++ b/openssh-6.6p1/monitor_wrap.h +@@ -75,16 +75,17 @@ void mm_sshpam_free_ctx(void *); + #ifdef SSH_AUDIT_EVENTS + #include "audit.h" + void mm_audit_event(ssh_audit_event_t); + int mm_audit_run_command(const char *); + void mm_audit_end_command(int, const char *); + void mm_audit_unsupported_body(int); + void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t); + void mm_audit_session_key_free_body(int, pid_t, uid_t); ++void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); + #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-6.6p1/session.c b/openssh-6.6p1/session.c +--- a/openssh-6.6p1/session.c ++++ b/openssh-6.6p1/session.c +@@ -132,17 +132,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; +@@ -1693,17 +1693,17 @@ do_child(Session *s, const char *command + char **env; + int env_size; + char *argv[ARGV_MAX]; + const char *shell, *shell0, *hostname = NULL; + struct passwd *pw = s->pw; + int r = 0; + + /* remove hostkey from the child's memory */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(1); + /* Don't audit this - both us and the parent would be talking to the + monitor over a single socket, with no synchronization. */ + packet_destroy_all(0, 1); + + /* Force a password change */ + if (s->authctxt->force_pwchange) { + do_setusercontext(pw); + child_close_fds(); +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -259,17 +259,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); + + static void do_ssh1_kex(void); + static void do_ssh2_kex(void); + + /* + * Close all listening sockets + */ +@@ -278,16 +278,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) +@@ -557,60 +566,99 @@ 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; ++ pid_t pid; ++ uid_t uid; + + if (sensitive_data.server_key) { + key_free(sensitive_data.server_key); + sensitive_data.server_key = NULL; + } ++ pid = getpid(); ++ uid = getuid(); + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { ++ char *fp; ++ ++ if (key_is_private(sensitive_data.host_keys[i])) ++ fp = key_fingerprint(sensitive_data.host_keys[i], ++ key_fp_type_select(), SSH_FP_HEX); ++ else ++ fp = NULL; + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = NULL; ++ if (fp != NULL) { ++ if (privsep) ++ PRIVSEP(audit_destroy_sensitive_data(fp, ++ pid, uid)); ++ else ++ audit_destroy_sensitive_data(fp, ++ pid, uid); ++ free(fp); ++ } + } +- if (sensitive_data.host_certificates[i]) { ++ if (sensitive_data.host_certificates ++ && sensitive_data.host_certificates[i]) { + key_free(sensitive_data.host_certificates[i]); + sensitive_data.host_certificates[i] = NULL; + } + } + 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; ++ pid_t pid; ++ uid_t uid; + int i; + ++ pid = getpid(); ++ uid = getuid(); + 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 = key_fingerprint(sensitive_data.host_keys[i], ++ key_fp_type_select(), SSH_FP_HEX); ++ else ++ fp = NULL; + tmp = key_demote(sensitive_data.host_keys[i]); + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = tmp; + if (tmp->type == KEY_RSA1) + sensitive_data.ssh1_host_key = tmp; ++ if (fp != NULL) { ++ audit_destroy_sensitive_data(fp, pid, uid); ++ free(fp); ++ } + } + /* Certs do not need demotion */ + } + + /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ + } + + static void +@@ -1201,16 +1249,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(); + unlink(options.pid_file); + exit(received_sigterm == SIGTERM ? 0 : 255); + } + if (key_used && key_do_regen) { + generate_ephemeral_server_key(); + key_used = 0; + key_do_regen = 0; +@@ -2167,27 +2216,28 @@ 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); + + /* Start session. */ + do_authenticated(authctxt); + + /* The connection has been terminated. */ + packet_destroy_all(1, 1); ++ destroy_sensitive_data(1); + + packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); + packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); + verbose("Transferred: sent %llu, received %llu bytes", + (unsigned long long)obytes, (unsigned long long)ibytes); + + verbose("Closing connection to %.500s port %d", remote_ip, remote_port); + +@@ -2412,17 +2462,17 @@ do_ssh1_kex(void) + fatal("%s: hash failed", __func__); + ssh_digest_free(md); + explicit_bzero(buf, bytes); + free(buf); + for (i = 0; i < 16; i++) + session_id[i] = session_key[i] ^ session_key[i + 16]; + } + /* Destroy the private and public keys. No longer. */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(0); + + if (use_privsep) + mm_ssh1_session_id(session_id); + + /* Destroy the decrypted integer. It is no longer needed. */ + BN_clear_free(session_key_int); + + /* Set the session key. From this on all communications will be encrypted. */ +@@ -2556,16 +2606,18 @@ cleanup_exit(int i) + 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) && !mm_is_monitor(); ++ 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 ((the_authctxt == NULL || !the_authctxt->authenticated) && + (!use_privsep || mm_is_monitor())) + audit_event(SSH_CONNECTION_ABANDON); + #endif + _exit(i); diff --git a/openssh-6.6p1-audit7-libaudit_compat.patch b/openssh-6.6p1-audit7-libaudit_compat.patch new file mode 100644 index 0000000..ce46452 --- /dev/null +++ b/openssh-6.6p1-audit7-libaudit_compat.patch @@ -0,0 +1,107 @@ +# definitions for AUDIT_CRYPTO_* symbols fom libaudit 2.x + +diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c +--- a/openssh-6.6p1/audit-linux.c ++++ b/openssh-6.6p1/audit-linux.c +@@ -25,16 +25,17 @@ + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Red Hat author: Jan F. Chadima + */ + + #include "includes.h" + #if defined(USE_LINUX_AUDIT) + #include ++#include "compat-libaudit.h" + #include + #include + + #include "log.h" + #include "audit.h" + #include "key.h" + #include "hostfile.h" + #include "auth.h" +diff --git a/openssh-6.6p1/compat-libaudit.h b/openssh-6.6p1/compat-libaudit.h +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/compat-libaudit.h +@@ -0,0 +1,79 @@ ++/* AUDIT_CRYPTO symbol definitions from libaudit 2.x */ ++/* libaudit.h -- ++ * Copyright 2004-2011 Red Hat Inc., Durham, North Carolina. ++ * All Rights Reserved. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Authors: ++ * Steve Grubb ++ * Rickard E. (Rik) Faith ++ */ ++#ifndef _COMPAT_LIBAUDIT_H_ ++#define _COMPAT_LIBAUDIT_H_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifndef AUDIT_FIRST_CRYPTO_MSG ++#define AUDIT_FIRST_CRYPTO_MSG 2400 ++#endif ++ ++#ifndef AUDIT_CRYPTO_TEST_USER ++#define AUDIT_CRYPTO_TEST_USER 2400 /* Crypto test results */ ++#endif ++ ++#ifndef AUDIT_CRYPTO_PARAM_CHANGE_USER ++#define AUDIT_CRYPTO_PARAM_CHANGE_USER 2401 /* Crypto attribute change */ ++#endif ++ ++#ifndef AUDIT_CRYPTO_LOGIN ++#define AUDIT_CRYPTO_LOGIN 2402 /* Logged in as crypto officer */ ++#endif ++ ++#ifndef AUDIT_CRYPTO_LOGOUT ++#define AUDIT_CRYPTO_LOGOUT 2403 /* Logged out from crypto */ ++#endif ++ ++#ifndef AUDIT_CRYPTO_KEY_USER ++#define AUDIT_CRYPTO_KEY_USER 2404 /* Create,delete,negotiate */ ++#endif ++ ++#ifndef AUDIT_CRYPTO_FAILURE_USER ++#define AUDIT_CRYPTO_FAILURE_USER 2405 /* Fail decrypt,encrypt,randomiz */ ++#endif ++ ++#ifndef AUDIT_CRYPTO_REPLAY_USER ++#define AUDIT_CRYPTO_REPLAY_USER 2406 /* Crypto replay detected */ ++#endif ++ ++#ifndef AUDIT_CRYPTO_SESSION ++#define AUDIT_CRYPTO_SESSION 2407 /* Record parameters set during ++ TLS session establishment */ ++#endif ++ ++ ++#ifndef AUDIT_LAST_CRYPTO_MSG ++#define AUDIT_LAST_CRYPTO_MSG 2499 ++#endif ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _COMPAT_LIBAUDIT_H_ */ ++ diff --git a/openssh-6.6p1-audit8-libaudit_dns_timeouts.patch b/openssh-6.6p1-audit8-libaudit_dns_timeouts.patch new file mode 100644 index 0000000..c199c65 --- /dev/null +++ b/openssh-6.6p1-audit8-libaudit_dns_timeouts.patch @@ -0,0 +1,47 @@ +# bnc#752354, bnc#757360 +# prevent timeouts in libaudit code caused by DNS misconfiguration by +# explicitely disabling DNS lookups in libaudit when UseDNS is false. +# Note that this particular solution causes the logs to always contain +# "hostname=?, addr=?" when DNS lookups are disabled. + +diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c +--- a/openssh-6.6p1/audit-linux.c ++++ b/openssh-6.6p1/audit-linux.c +@@ -62,17 +62,17 @@ linux_audit_user_logxxx(int uid, const c + if (errno == EINVAL || errno == EPROTONOSUPPORT || + errno == EAFNOSUPPORT) + return; /* No audit support in kernel */ + else + goto fatal_report; /* Must prevent login */ + } + rc = audit_log_acct_message(audit_fd, event, + NULL, "login", username ? username : "(unknown)", +- username == NULL ? uid : -1, hostname, ip, ttyn, success); ++ username == NULL ? uid : -1, options.use_dns ? hostname : NULL, 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; +@@ -114,17 +114,17 @@ linux_audit_user_auth(int uid, const cha + 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); ++ username == NULL ? uid : -1, options.use_dns ? hostname : NULL, 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; diff --git a/openssh-6.6p1-blocksigalrm.patch b/openssh-6.6p1-blocksigalrm.patch index 2727eaf..1cd7f05 100644 --- a/openssh-6.6p1-blocksigalrm.patch +++ b/openssh-6.6p1-blocksigalrm.patch @@ -2,19 +2,33 @@ # grace_alarm_handler) # bnc#57354 -Index: b/log.c -=================================================================== ---- a/log.c -+++ b/log.c -@@ -51,6 +51,7 @@ +diff --git a/openssh-6.6p1/log.c b/openssh-6.6p1/log.c +--- a/openssh-6.6p1/log.c ++++ b/openssh-6.6p1/log.c +@@ -47,16 +47,17 @@ + #include + #include + #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) + # include #endif + #include "xmalloc.h" #include "log.h" +#include static LogLevel log_level = SYSLOG_LEVEL_INFO; static int log_on_stderr = 1; -@@ -388,6 +389,7 @@ do_log(LogLevel level, const char *fmt, + static int log_stderr_fd = STDERR_FILENO; + static int log_facility = LOG_AUTH; + static char *argv0; + static log_handler_fn *log_handler; + static void *log_handler_ctx; +@@ -384,16 +385,17 @@ do_log(LogLevel level, const char *fmt, + { + #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) + struct syslog_data sdata = SYSLOG_DATA_INIT; + #endif + char msgbuf[MSGBUFSIZ]; char fmtbuf[MSGBUFSIZ]; char *txt = NULL; int pri = LOG_INFO; @@ -22,7 +36,17 @@ Index: b/log.c int saved_errno = errno; log_handler_fn *tmp_handler; -@@ -446,6 +448,14 @@ do_log(LogLevel level, const char *fmt, + if (level > log_level) + return; + + switch (level) { + case SYSLOG_LEVEL_FATAL: +@@ -442,20 +444,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", fmtbuf); (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); } else { @@ -37,7 +61,9 @@ Index: b/log.c #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); syslog_r(pri, &sdata, "%.500s", fmtbuf); -@@ -455,6 +465,7 @@ do_log(LogLevel level, const char *fmt, + closelog_r(&sdata); + #else + openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); syslog(pri, "%.500s", fmtbuf); closelog(); #endif diff --git a/openssh-6.6p1-curve25519-6.6.1p1.patch b/openssh-6.6p1-curve25519-6.6.1p1.patch new file mode 100644 index 0000000..7eb8086 --- /dev/null +++ b/openssh-6.6p1-curve25519-6.6.1p1.patch @@ -0,0 +1,205 @@ +# Date: Sun, 20 Apr 2014 17:14:08 +1000 (EST) +# From: Damien Miller +# To: openssh-unix-dev@mindrot.org +# Subject: bad bignum encoding for curve25519-sha256@libssh.org +# Message-ID: +# +# Hi, +# +# So I screwed up when writing the support for the curve25519 KEX method +# that doesn't depend on OpenSSL's BIGNUM type - a bug in my code left +# leading zero bytes where they should have been skipped. The impact of +# this is that OpenSSH 6.5 and 6.6 will fail during key exchange with a +# peer that implements curve25519-sha256@libssh.org properly about 0.2% +# of the time (one in every 512ish connections). +# +# We've fixed this for OpenSSH 6.7 by avoiding the curve25519-sha256 +# key exchange for previous versions, but I'd recommend distributors +# of OpenSSH apply this patch so the affected code doesn't become +# too entrenched in LTS releases. +# +# The patch fixes the bug and makes OpenSSH identify itself as 6.6.1 so as +# to distinguish itself from the incorrect versions so the compatibility +# code to disable the affected KEX isn't activated. +# +# I've committed this on the 6.6 branch too. +# +# Apologies for the hassle. +# +# -d + +diff --git a/openssh-6.6p1/bufaux.c b/openssh-6.6p1/bufaux.c +--- a/openssh-6.6p1/bufaux.c ++++ b/openssh-6.6p1/bufaux.c +@@ -1,9 +1,9 @@ +-/* $OpenBSD: bufaux.c,v 1.56 2014/02/02 03:44:31 djm Exp $ */ ++/* $OpenBSD: bufaux.c,v 1.57 2014/04/16 23:22:45 djm Exp $ */ + /* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Auxiliary functions for storing and retrieving various data types to/from + * Buffers. + * + * As far as I am concerned, the code I have written for this software +@@ -367,16 +367,19 @@ buffer_get_bignum2_as_string(Buffer *buf + void + buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l) + { + u_char *buf, *p; + int pad = 0; + + if (l > 8 * 1024) + fatal("%s: length %u too long", __func__, l); ++ /* Skip leading zero bytes */ ++ for (; l > 0 && *s == 0; l--, s++) ++ ; + p = buf = xmalloc(l + 1); + /* + * If most significant bit is set then prepend a zero byte to + * avoid interpretation as a negative number. + */ + if (l > 0 && (s[0] & 0x80) != 0) { + *p++ = '\0'; + pad = 1; +diff --git a/openssh-6.6p1/compat.c b/openssh-6.6p1/compat.c +--- a/openssh-6.6p1/compat.c ++++ b/openssh-6.6p1/compat.c +@@ -90,16 +90,19 @@ compat_datafellows(const char *version) + SSH_OLD_FORWARD_ADDR}, + { "OpenSSH_2.*," + "OpenSSH_3.0*," + "OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, + { "OpenSSH_3.*", SSH_OLD_FORWARD_ADDR }, + { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, + { "OpenSSH_4*", 0 }, + { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT}, ++ { "OpenSSH_6.6.1*", SSH_NEW_OPENSSH}, ++ { "OpenSSH_6.5*," ++ "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD}, + { "OpenSSH*", SSH_NEW_OPENSSH }, + { "*MindTerm*", 0 }, + { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID|SSH_BUG_DEBUG| + SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE| + SSH_BUG_FIRSTKEX }, + { "2.1 *", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID|SSH_BUG_DEBUG| +@@ -246,22 +249,34 @@ compat_cipher_proposal(char *cipher_prop + debug2("%s: original cipher proposal: %s", __func__, cipher_prop); + cipher_prop = filter_proposal(cipher_prop, "aes*"); + debug2("%s: compat cipher proposal: %s", __func__, cipher_prop); + if (*cipher_prop == '\0') + fatal("No supported ciphers found"); + return cipher_prop; + } + +- + char * + compat_pkalg_proposal(char *pkalg_prop) + { + if (!(datafellows & SSH_BUG_RSASIGMD5)) + return pkalg_prop; + debug2("%s: original public key proposal: %s", __func__, pkalg_prop); + pkalg_prop = filter_proposal(pkalg_prop, "ssh-rsa"); + debug2("%s: compat public key proposal: %s", __func__, pkalg_prop); + if (*pkalg_prop == '\0') + fatal("No supported PK algorithms found"); + return pkalg_prop; + } + ++char * ++compat_kex_proposal(char *kex_prop) ++{ ++ if (!(datafellows & SSH_BUG_CURVE25519PAD)) ++ return kex_prop; ++ debug2("%s: original KEX proposal: %s", __func__, kex_prop); ++ kex_prop = filter_proposal(kex_prop, "curve25519-sha256@libssh.org"); ++ debug2("%s: compat KEX proposal: %s", __func__, kex_prop); ++ if (*kex_prop == '\0') ++ fatal("No supported key exchange algorithms found"); ++ return kex_prop; ++} ++ +diff --git a/openssh-6.6p1/compat.h b/openssh-6.6p1/compat.h +--- a/openssh-6.6p1/compat.h ++++ b/openssh-6.6p1/compat.h +@@ -54,20 +54,22 @@ + #define SSH_BUG_DUMMYCHAN 0x00100000 + #define SSH_BUG_EXTEOF 0x00200000 + #define SSH_BUG_PROBE 0x00400000 + #define SSH_BUG_FIRSTKEX 0x00800000 + #define SSH_OLD_FORWARD_ADDR 0x01000000 + #define SSH_BUG_RFWD_ADDR 0x02000000 + #define SSH_NEW_OPENSSH 0x04000000 + #define SSH_BUG_DYNAMIC_RPORT 0x08000000 ++#define SSH_BUG_CURVE25519PAD 0x10000000 + + void enable_compat13(void); + void enable_compat20(void); + void compat_datafellows(const char *); + int proto_spec(const char *); + char *compat_cipher_proposal(char *); + char *compat_pkalg_proposal(char *); ++char *compat_kex_proposal(char *); + + extern int compat13; + extern int compat20; + extern int datafellows; + #endif +diff --git a/openssh-6.6p1/sshconnect2.c b/openssh-6.6p1/sshconnect2.c +--- a/openssh-6.6p1/sshconnect2.c ++++ b/openssh-6.6p1/sshconnect2.c +@@ -190,16 +190,18 @@ ssh_kex2(char *host, struct sockaddr *ho + else { + /* Prefer algorithms that we already have keys for */ + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + compat_pkalg_proposal( + order_hostkeyalgs(host, hostaddr, port)); + } + if (options.kex_algorithms != NULL) + myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; ++ myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( ++ myproposal[PROPOSAL_KEX_ALGS]); + + if (options.rekey_limit || options.rekey_interval) + packet_set_rekey_limits((u_int32_t)options.rekey_limit, + (time_t)options.rekey_interval); + + /* start key exchange */ + kex = kex_setup(myproposal); + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -2457,16 +2457,19 @@ do_ssh2_kex(void) + 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.kex_algorithms != NULL) + myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; + ++ myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( ++ myproposal[PROPOSAL_KEX_ALGS]); ++ + if (options.rekey_limit || options.rekey_interval) + packet_set_rekey_limits((u_int32_t)options.rekey_limit, + (time_t)options.rekey_interval); + + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( + list_hostkey_types()); + + /* start key exchange */ +diff --git a/openssh-6.6p1/version.h b/openssh-6.6p1/version.h +--- a/openssh-6.6p1/version.h ++++ b/openssh-6.6p1/version.h +@@ -1,6 +1,6 @@ + /* $OpenBSD: version.h,v 1.70 2014/02/27 22:57:40 djm Exp $ */ + +-#define SSH_VERSION "OpenSSH_6.6" ++#define SSH_VERSION "OpenSSH_6.6.1" + + #define SSH_PORTABLE "p1" + #define SSH_RELEASE SSH_VERSION SSH_PORTABLE diff --git a/openssh-6.6p1-disable-openssl-abi-check.patch b/openssh-6.6p1-disable-openssl-abi-check.patch index ff94de7..61ce8d5 100644 --- a/openssh-6.6p1-disable-openssl-abi-check.patch +++ b/openssh-6.6p1-disable-openssl-abi-check.patch @@ -2,16 +2,22 @@ # reliable indicator of ABI changes and doesn't make much sense in a # distribution package -Index: b/entropy.c -=================================================================== ---- a/entropy.c -+++ b/entropy.c -@@ -213,10 +213,11 @@ seed_rng(void) - #ifndef OPENSSL_PRNG_ONLY - unsigned char buf[RANDOM_SEED_SIZE]; +diff --git a/openssh-6.6p1/entropy.c b/openssh-6.6p1/entropy.c +--- a/openssh-6.6p1/entropy.c ++++ b/openssh-6.6p1/entropy.c +@@ -212,22 +212,23 @@ seed_rng(void) #endif + /* + * OpenSSL version numbers: MNNFFPPS: major minor fix patch status + * We match major, minor, fix and status (not patch) for <1.0.0. + * After that, we acceptable compatible fix versions (so we + * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed + * within a patch series. + */ +#if 0 - if (!ssh_compatible_openssl(OPENSSL_VERSION_NUMBER, SSLeay())) + u_long version_mask = SSLeay() >= 0x1000000f ? ~0xffff0L : ~0xff0L; + if (((SSLeay() ^ OPENSSL_VERSION_NUMBER) & version_mask) || + (SSLeay() >> 12) < (OPENSSL_VERSION_NUMBER >> 12)) fatal("OpenSSL version mismatch. Built against %lx, you " "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); - @@ -19,3 +25,8 @@ Index: b/entropy.c #ifndef OPENSSL_PRNG_ONLY if (RAND_status() == 1) { debug3("RNG is ready, skipping seeding"); + return; + } + + if (seed_from_prngd(buf, sizeof(buf)) == -1) + fatal("Could not obtain seed from PRNGd"); diff --git a/openssh-6.6p1-eal3.patch b/openssh-6.6p1-eal3.patch index 871b50c..a3058d3 100644 --- a/openssh-6.6p1-eal3.patch +++ b/openssh-6.6p1-eal3.patch @@ -1,10 +1,14 @@ # fix paths and references in sshd man pages -Index: b/sshd.8 -=================================================================== ---- a/sshd.8 -+++ b/sshd.8 -@@ -873,7 +873,7 @@ are displayed to anyone trying to log in +diff --git a/openssh-6.6p1/sshd.8 b/openssh-6.6p1/sshd.8 +--- a/openssh-6.6p1/sshd.8 ++++ b/openssh-6.6p1/sshd.8 +@@ -875,17 +875,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 @@ -13,30 +17,59 @@ Index: b/sshd.8 This file is used in exactly the same way as .Pa hosts.equiv , but allows host-based authentication without permitting login with -@@ -953,7 +953,7 @@ The content of this file is not sensitiv + 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 +@@ -956,17 +956,17 @@ The content of this file is not sensitiv + .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.conf 5 , +.Xr login.defs 5 , .Xr moduli 5 , .Xr sshd_config 5 , .Xr inetd 8 , -Index: b/sshd_config.5 -=================================================================== ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -374,8 +374,7 @@ This option is only available for protoc + .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-6.6p1/sshd_config.5 b/openssh-6.6p1/sshd_config.5 +--- a/openssh-6.6p1/sshd_config.5 ++++ b/openssh-6.6p1/sshd_config.5 +@@ -278,18 +278,17 @@ The contents of the specified file are s + authentication is allowed. + If the argument is + .Dq none + then no banner is displayed. + This option is only available for protocol version 2. 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 +-PAM or though authentication styles supported in -.Xr login.conf 5 ) +PAM) The default is .Dq yes . .It Cm ChrootDirectory -@@ -773,7 +772,7 @@ or + Specifies the pathname of a directory to + .Xr chroot 2 + to after authentication. + All components of the pathname must be root-owned directories that are + not writable by any other user or group. +@@ -576,17 +575,17 @@ and + .Pa .shosts + files will not be used in + .Cm RhostsRSAAuthentication + or + .Cm HostbasedAuthentication . .Pp .Pa /etc/hosts.equiv and @@ -45,3 +78,8 @@ Index: b/sshd_config.5 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-6.6p1-fingerprint_hash.patch b/openssh-6.6p1-fingerprint_hash.patch new file mode 100644 index 0000000..7a0a76f --- /dev/null +++ b/openssh-6.6p1-fingerprint_hash.patch @@ -0,0 +1,730 @@ +# HG changeset patch +# Parent 8b2615db484b7061edd15f3bee36958f790f790e + +# select fingerprint hash algorithms based on the environment variable +# SSH_FP_TYPE_ENVVAR and append it to hex and randomart fingerprints +# Petr Cerny + +diff --git a/openssh-6.6p1/auth-rsa.c b/openssh-6.6p1/auth-rsa.c +--- a/openssh-6.6p1/auth-rsa.c ++++ b/openssh-6.6p1/auth-rsa.c +@@ -230,17 +230,17 @@ rsa_key_allowed_in_file(struct passwd *p + + /* check the real bits */ + keybits = BN_num_bits(key->rsa->n); + if (keybits < 0 || bits != keybits) + logit("Warning: %s, line %lu: keysize mismatch: " + "actual %d vs. announced %d.", + file, linenum, BN_num_bits(key->rsa->n), bits); + +- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX); + debug("matching key found: file %s, line %lu %s %s", + file, linenum, key_type(key), fp); + free(fp); + + /* Never accept a revoked key */ + if (auth_key_is_revoked(key)) + break; + +diff --git a/openssh-6.6p1/auth.c b/openssh-6.6p1/auth.c +--- a/openssh-6.6p1/auth.c ++++ b/openssh-6.6p1/auth.c +@@ -680,17 +680,17 @@ auth_key_is_revoked(Key *key) + case -1: + /* Error opening revoked_keys_file: refuse all keys */ + error("Revoked keys file is unreadable: refusing public key " + "authentication"); + return 1; + case 1: + revoked: + /* Key revoked */ +- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ key_fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX); + error("WARNING: authentication attempt with a revoked " + "%s key %s ", key_type(key), key_fp); + free(key_fp); + return 1; + } + fatal("key_in_file returned junk"); + } + +diff --git a/openssh-6.6p1/auth2-hostbased.c b/openssh-6.6p1/auth2-hostbased.c +--- a/openssh-6.6p1/auth2-hostbased.c ++++ b/openssh-6.6p1/auth2-hostbased.c +@@ -202,23 +202,23 @@ hostbased_key_allowed(struct passwd *pw, + _PATH_SSH_SYSTEM_HOSTFILE2, + options.ignore_user_known_hosts ? NULL : + _PATH_SSH_USER_HOSTFILE2); + } + + if (host_status == HOST_OK) { + if (key_is_cert(key)) { + fp = key_fingerprint(key->cert->signature_key, +- SSH_FP_MD5, SSH_FP_HEX); ++ key_fp_type_select(), SSH_FP_HEX); + verbose("Accepted certificate ID \"%s\" signed by " + "%s CA %s from %s@%s", key->cert->key_id, + key_type(key->cert->signature_key), fp, + cuser, lookup); + } else { +- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX); + verbose("Accepted %s public key %s from %s@%s", + key_type(key), fp, cuser, lookup); + } + free(fp); + } + + return (host_status == HOST_OK); + } +diff --git a/openssh-6.6p1/auth2-pubkey.c b/openssh-6.6p1/auth2-pubkey.c +--- a/openssh-6.6p1/auth2-pubkey.c ++++ b/openssh-6.6p1/auth2-pubkey.c +@@ -208,25 +208,25 @@ pubkey_auth_info(Authctxt *authctxt, con + i = vasprintf(&extra, fmt, ap); + va_end(ap); + if (i < 0 || extra == NULL) + fatal("%s: vasprintf failed", __func__); + } + + if (key_is_cert(key)) { + fp = key_fingerprint(key->cert->signature_key, +- SSH_FP_MD5, SSH_FP_HEX); ++ key_fp_type_select(), SSH_FP_HEX); + auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", + key_type(key), key->cert->key_id, + (unsigned long long)key->cert->serial, + key_type(key->cert->signature_key), fp, + extra == NULL ? "" : ", ", extra == NULL ? "" : extra); + free(fp); + } else { +- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX); + auth_info(authctxt, "%s %s%s%s", key_type(key), fp, + extra == NULL ? "" : ", ", extra == NULL ? "" : extra); + free(fp); + } + free(extra); + } + + static int +@@ -360,17 +360,17 @@ check_authkeys_file(FILE *f, char *file, + if (key_is_cert(key)) { + if (!key_equal(found, key->cert->signature_key)) + continue; + if (auth_parse_options(pw, key_options, file, + linenum) != 1) + continue; + if (!key_is_cert_authority) + continue; +- fp = key_fingerprint(found, SSH_FP_MD5, ++ fp = key_fingerprint(found, key_fp_type_select(), + SSH_FP_HEX); + debug("matching CA found: file %s, line %lu, %s %s", + file, linenum, key_type(found), fp); + /* + * If the user has specified a list of principals as + * a key option, then prefer that list to matching + * their username in the certificate principals list. + */ +@@ -401,17 +401,17 @@ check_authkeys_file(FILE *f, char *file, + break; + } else if (key_equal(found, key)) { + if (auth_parse_options(pw, key_options, file, + linenum) != 1) + continue; + if (key_is_cert_authority) + continue; + found_key = 1; +- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(found, key_fp_type_select(), SSH_FP_HEX); + debug("matching key found: file %s, line %lu %s %s", + file, linenum, key_type(found), fp); + free(fp); + break; + } + } + if (found != NULL) + key_free(found); +@@ -427,17 +427,17 @@ user_cert_trusted_ca(struct passwd *pw, + char *ca_fp, *principals_file = NULL; + const char *reason; + int ret = 0; + + if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) + return 0; + + ca_fp = key_fingerprint(key->cert->signature_key, +- SSH_FP_MD5, SSH_FP_HEX); ++ key_fp_type_select(), SSH_FP_HEX); + + if (key_in_file(key->cert->signature_key, + options.trusted_user_ca_keys, 1) != 1) { + debug2("%s: CA %s %s is not listed in %s", __func__, + key_type(key->cert->signature_key), ca_fp, + options.trusted_user_ca_keys); + goto out; + } +diff --git a/openssh-6.6p1/key.c b/openssh-6.6p1/key.c +--- a/openssh-6.6p1/key.c ++++ b/openssh-6.6p1/key.c +@@ -420,30 +420,39 @@ key_fingerprint_raw(const Key *k, enum f + *dgst_raw_length = ssh_digest_bytes(hash_alg); + } else { + fatal("%s: blob is null", __func__); + } + return retval; + } + + static char * +-key_fingerprint_hex(u_char *dgst_raw, u_int dgst_raw_len) ++key_fingerprint_hex(u_char *dgst_raw, u_int dgst_raw_len, enum fp_type dgst_type) + { + char *retval; + u_int i; + +- retval = xcalloc(1, dgst_raw_len * 3 + 1); ++ /* reserve space for both the key hash and the string for the hash type */ ++ retval = xcalloc(1, dgst_raw_len * 3 + 1 + SSH_FP_TYPE_STRLEN + 2); + for (i = 0; i < dgst_raw_len; i++) { + char hex[4]; + snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]); + strlcat(retval, hex, dgst_raw_len * 3 + 1); + } + + /* Remove the trailing ':' character */ +- retval[(dgst_raw_len * 3) - 1] = '\0'; ++ retval[(dgst_raw_len * 3) - 1] = ' '; ++ ++ /* Append hash type */ ++ { ++ char hash[SSH_FP_TYPE_STRLEN + 2 + 1]; ++ snprintf(hash, sizeof(hash), "[%s]", key_fp_type_str(dgst_type)); ++ strlcat(retval, hash, dgst_raw_len * 3 + 1 + SSH_FP_TYPE_STRLEN + 2); ++ } ++ + return retval; + } + + static char * + key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len) + { + char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; + char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', +@@ -518,17 +527,18 @@ key_fingerprint_bubblebabble(u_char *dgs + * can be in the exact middle of the picture, and FLDBASE should be >=8 . + * Else pictures would be too dense, and drawing the frame would + * fail, too, because the key type would not fit in anymore. + */ + #define FLDBASE 8 + #define FLDSIZE_Y (FLDBASE + 1) + #define FLDSIZE_X (FLDBASE * 2 + 1) + static char * +-key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k) ++key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k, ++ enum fp_type dgst_type) + { + /* + * Chars to be used after each other every time the worm + * intersects with itself. Matter of taste. + */ + char *augmentation_string = " .o+=*BOX@%&#/^SE"; + char *retval, *p; + u_char field[FLDSIZE_X][FLDSIZE_Y]; +@@ -585,18 +595,19 @@ key_fingerprint_randomart(u_char *dgst_r + *p++ = '|'; + for (x = 0; x < FLDSIZE_X; x++) + *p++ = augmentation_string[MIN(field[x][y], len)]; + *p++ = '|'; + *p++ = '\n'; + } + + /* output lower border */ +- *p++ = '+'; +- for (i = 0; i < FLDSIZE_X; i++) ++ i = snprintf(p, FLDSIZE_X, "+--[%s]", key_fp_type_str(dgst_type)); ++ p += i; ++ for (i--; i < FLDSIZE_X; i++) + *p++ = '-'; + *p++ = '+'; + + return retval; + } + + char * + key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) +@@ -605,34 +616,91 @@ key_fingerprint(const Key *k, enum fp_ty + u_char *dgst_raw; + u_int dgst_raw_len; + + dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len); + if (!dgst_raw) + fatal("key_fingerprint: null from key_fingerprint_raw()"); + switch (dgst_rep) { + case SSH_FP_HEX: +- retval = key_fingerprint_hex(dgst_raw, dgst_raw_len); ++ retval = key_fingerprint_hex(dgst_raw, dgst_raw_len, dgst_type); + break; + case SSH_FP_BUBBLEBABBLE: + retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len); + break; + case SSH_FP_RANDOMART: +- retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, k); ++ retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, k, dgst_type); + break; + default: + fatal("key_fingerprint: bad digest representation %d", + dgst_rep); + break; + } + explicit_bzero(dgst_raw, dgst_raw_len); + free(dgst_raw); + return retval; + } + ++enum fp_type ++key_fp_type_select(void) ++{ ++ static enum fp_type fp; ++ static char fp_defined = 0; ++ char *env; ++ ++ if (!fp_defined) { ++ env = getenv(SSH_FP_TYPE_ENVVAR); ++ if (env) { ++ if (!strcasecmp(env, "md5") || ++ !strcasecmp(env, "md-5")) ++ fp = SSH_FP_MD5; ++ else if (!strcasecmp(env, "sha1") || ++ !strcasecmp(env, "sha-1")) ++ fp = SSH_FP_SHA1; ++#ifdef HAVE_EVP_SHA256 ++ else if (!strcasecmp(env, "sha256") || ++ !strcasecmp(env, "sha-256")) ++ fp = SSH_FP_SHA256; ++#endif ++ else { ++ error("invalid key type in environment variable " ++ SSH_FP_TYPE_ENVVAR ": '%s' - falling back to MD5.", ++ env); ++ fp = SSH_FP_MD5; ++ } ++ } else ++ fp = SSH_FP_MD5; ++ ++ fp_defined = 1; ++ } ++ return fp; ++} ++ ++/* ++ * string lengths must be less or equal to SSH_FP_TYPE_STRLEN (defined in ++ * key.h) as to fit into the fingerprint string buffer ++ */ ++char * ++key_fp_type_str(enum fp_type dgst_type) ++{ ++ switch (dgst_type) { ++ case SSH_FP_MD5: ++ return "MD5"; ++ case SSH_FP_SHA1: ++ return "SHA-1"; ++#ifdef HAVE_EVP_SHA256 ++ case SSH_FP_SHA256: ++ return "SHA-256"; ++#endif ++ default: ++ fatal("%s: unknown key fingerprint hash algorithm requested", __func__); ++ } ++} ++ ++ + /* + * Reads a multiple-precision integer in decimal from the buffer, and advances + * the pointer. The integer must already be initialized. This function is + * permitted to modify the buffer. This leaves *cpp to point just beyond the + * last processed (and maybe modified) character. Note that this may modify + * the buffer containing the number. + */ + static int +diff --git a/openssh-6.6p1/key.h b/openssh-6.6p1/key.h +--- a/openssh-6.6p1/key.h ++++ b/openssh-6.6p1/key.h +@@ -53,16 +53,18 @@ enum fp_type { + SSH_FP_MD5, + SSH_FP_SHA256 + }; + enum fp_rep { + SSH_FP_HEX, + SSH_FP_BUBBLEBABBLE, + SSH_FP_RANDOMART + }; ++#define SSH_FP_TYPE_ENVVAR "SSH_FINGERPRINT_TYPE" ++#define SSH_FP_TYPE_STRLEN 8 + + /* key is stored in external hardware */ + #define KEY_FLAG_EXT 0x0001 + + #define CERT_MAX_PRINCIPALS 256 + struct KeyCert { + Buffer certblob; /* Kept around for use on wire */ + u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */ +@@ -104,16 +106,18 @@ int key_equal_public(const Key *, cons + int key_equal(const Key *, const Key *); + char *key_fingerprint(const Key *, enum fp_type, enum fp_rep); + u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); + const char *key_type(const Key *); + const char *key_cert_type(const Key *); + int key_write(const Key *, FILE *); + int key_read(Key *, char **); + u_int key_size(const Key *); ++enum fp_type key_fp_type_select(void); ++char *key_fp_type_str(enum fp_type); + + Key *key_generate(int, u_int); + Key *key_from_private(const Key *); + int key_type_from_name(char *); + int key_is_cert(const Key *); + int key_type_is_cert(int); + int key_type_plain(int); + int key_to_certified(Key *, int); +diff --git a/openssh-6.6p1/ssh-add.c b/openssh-6.6p1/ssh-add.c +--- a/openssh-6.6p1/ssh-add.c ++++ b/openssh-6.6p1/ssh-add.c +@@ -325,17 +325,17 @@ list_identities(AuthenticationConnection + int version; + + for (version = 1; version <= 2; version++) { + for (key = ssh_get_first_identity(ac, &comment, version); + key != NULL; + key = ssh_get_next_identity(ac, &comment, version)) { + had_identities = 1; + if (do_fp) { +- fp = key_fingerprint(key, SSH_FP_MD5, ++ fp = key_fingerprint(key, key_fp_type_select(), + SSH_FP_HEX); + printf("%d %s %s (%s)\n", + key_size(key), fp, comment, key_type(key)); + free(fp); + } else { + if (!key_write(key, stdout)) + fprintf(stderr, "key_write failed"); + fprintf(stdout, " %s\n", comment); +diff --git a/openssh-6.6p1/ssh-agent.c b/openssh-6.6p1/ssh-agent.c +--- a/openssh-6.6p1/ssh-agent.c ++++ b/openssh-6.6p1/ssh-agent.c +@@ -193,17 +193,17 @@ lookup_identity(Key *key, int version) + + /* Check confirmation of keysign request */ + static int + confirm_key(Identity *id) + { + char *p; + int ret = -1; + +- p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); ++ p = key_fingerprint(id->key, key_fp_type_select(), SSH_FP_HEX); + if (ask_permission("Allow use of key %s?\nKey fingerprint %s.", + id->comment, p)) + ret = 0; + free(p); + + return (ret); + } + +diff --git a/openssh-6.6p1/ssh-keygen.c b/openssh-6.6p1/ssh-keygen.c +--- a/openssh-6.6p1/ssh-keygen.c ++++ b/openssh-6.6p1/ssh-keygen.c +@@ -741,27 +741,27 @@ do_download(struct passwd *pw) + { + #ifdef ENABLE_PKCS11 + Key **keys = NULL; + int i, nkeys; + enum fp_rep rep; + enum fp_type fptype; + char *fp, *ra; + +- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; ++ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fp_type_select(); + rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; + + pkcs11_init(0); + nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); + if (nkeys <= 0) + fatal("cannot read public key from pkcs11"); + for (i = 0; i < nkeys; i++) { + if (print_fingerprint) { + fp = key_fingerprint(keys[i], fptype, rep); +- ra = key_fingerprint(keys[i], SSH_FP_MD5, ++ ra = key_fingerprint(keys[i], key_fp_type_select(), + SSH_FP_RANDOMART); + printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]), + fp, key_type(keys[i])); + if (log_level >= SYSLOG_LEVEL_VERBOSE) + printf("%s\n", ra); + free(ra); + free(fp); + } else { +@@ -784,29 +784,29 @@ do_fingerprint(struct passwd *pw) + FILE *f; + Key *public; + char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; + int i, skip = 0, num = 0, invalid = 1; + enum fp_rep rep; + enum fp_type fptype; + struct stat st; + +- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; ++ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fp_type_select(); + rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + public = key_load_public(identity_file, &comment); + if (public != NULL) { + fp = key_fingerprint(public, fptype, rep); +- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); ++ ra = key_fingerprint(public, key_fp_type_select(), SSH_FP_RANDOMART); + printf("%u %s %s (%s)\n", key_size(public), fp, comment, + key_type(public)); + if (log_level >= SYSLOG_LEVEL_VERBOSE) + printf("%s\n", ra); + key_free(public); + free(comment); + free(ra); + free(fp); +@@ -862,17 +862,17 @@ do_fingerprint(struct passwd *pw) + public = key_new(KEY_UNSPEC); + if (key_read(public, &cp) != 1) { + key_free(public); + continue; + } + } + comment = *cp ? cp : comment; + fp = key_fingerprint(public, fptype, rep); +- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); ++ ra = key_fingerprint(public, key_fp_type_select(), SSH_FP_RANDOMART); + printf("%u %s %s (%s)\n", key_size(public), fp, + comment ? comment : "no comment", key_type(public)); + if (log_level >= SYSLOG_LEVEL_VERBOSE) + printf("%s\n", ra); + free(ra); + free(fp); + key_free(public); + invalid = 0; +@@ -983,20 +983,20 @@ do_gen_all_hostkeys(struct passwd *pw) + static void + printhost(FILE *f, const char *name, Key *public, int ca, int hash) + { + if (print_fingerprint) { + enum fp_rep rep; + enum fp_type fptype; + char *fp, *ra; + +- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; ++ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fp_type_select(); + rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; + fp = key_fingerprint(public, fptype, rep); +- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); ++ ra = key_fingerprint(public, key_fp_type_select(), SSH_FP_RANDOMART); + printf("%u %s %s (%s)\n", key_size(public), fp, name, + key_type(public)); + if (log_level >= SYSLOG_LEVEL_VERBOSE) + printf("%s\n", ra); + free(ra); + free(fp); + } else { + if (hash && (name = host_hash(name, NULL, 0)) == NULL) +@@ -1873,19 +1873,19 @@ do_show_cert(struct passwd *pw) + if (stat(identity_file, &st) < 0) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); + if ((key = key_load_public(identity_file, NULL)) == NULL) + fatal("%s is not a public key", identity_file); + if (!key_is_cert(key)) + fatal("%s is not a certificate", identity_file); + v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; + +- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ key_fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX); + ca_fp = key_fingerprint(key->cert->signature_key, +- SSH_FP_MD5, SSH_FP_HEX); ++ key_fp_type_select(), SSH_FP_HEX); + + printf("%s:\n", identity_file); + printf(" Type: %s %s certificate\n", key_ssh_name(key), + key_cert_type(key)); + printf(" Public key: %s %s\n", key_type(key), key_fp); + printf(" Signing CA: %s %s\n", + key_type(key->cert->signature_key), ca_fp); + printf(" Key ID: \"%s\"\n", key->cert->key_id); +@@ -2681,18 +2681,18 @@ passphrase_again: + exit(1); + } + if (!key_write(public, f)) + fprintf(stderr, "write key failed\n"); + fprintf(f, " %s\n", comment); + fclose(f); + + if (!quiet) { +- char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); +- char *ra = key_fingerprint(public, SSH_FP_MD5, ++ char *fp = key_fingerprint(public, key_fp_type_select(), SSH_FP_HEX); ++ char *ra = key_fingerprint(public, key_fp_type_select(), + SSH_FP_RANDOMART); + printf("Your public key has been saved in %s.\n", + identity_file); + printf("The key fingerprint is:\n"); + printf("%s %s\n", fp, comment); + printf("The key's randomart image is:\n"); + printf("%s\n", ra); + free(ra); +diff --git a/openssh-6.6p1/sshconnect.c b/openssh-6.6p1/sshconnect.c +--- a/openssh-6.6p1/sshconnect.c ++++ b/openssh-6.6p1/sshconnect.c +@@ -909,18 +909,18 @@ check_host_key(char *hostname, struct so + "address '%.128s' to the list of known " + "hosts (%.30s).", type, ip, + user_hostfiles[0]); + else + logit("Warning: Permanently added the %s host " + "key for IP address '%.128s' to the list " + "of known hosts.", type, ip); + } else if (options.visual_host_key) { +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); +- ra = key_fingerprint(host_key, SSH_FP_MD5, ++ fp = key_fingerprint(host_key, key_fp_type_select(), SSH_FP_HEX); ++ ra = key_fingerprint(host_key, key_fp_type_select(), + SSH_FP_RANDOMART); + logit("Host key fingerprint is %s\n%s\n", fp, ra); + free(ra); + free(fp); + } + break; + case HOST_NEW: + if (options.host_key_alias == NULL && port != 0 && +@@ -950,18 +950,18 @@ check_host_key(char *hostname, struct so + + if (show_other_keys(host_hostkeys, host_key)) + snprintf(msg1, sizeof(msg1), + "\nbut keys of different type are already" + " known for this host."); + else + snprintf(msg1, sizeof(msg1), "."); + /* The default */ +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); +- ra = key_fingerprint(host_key, SSH_FP_MD5, ++ fp = key_fingerprint(host_key, key_fp_type_select(), SSH_FP_HEX); ++ ra = key_fingerprint(host_key, key_fp_type_select(), + SSH_FP_RANDOMART); + msg2[0] = '\0'; + if (options.verify_host_key_dns) { + if (matching_host_key_dns) + snprintf(msg2, sizeof(msg2), + "Matching host key fingerprint" + " found in DNS.\n"); + else +@@ -1215,17 +1215,17 @@ fail: + + /* returns 0 if key verifies or -1 if key does NOT verify */ + int + verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) + { + int flags = 0; + char *fp; + +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(host_key, key_fp_type_select(), SSH_FP_HEX); + debug("Server host key: %s %s", key_type(host_key), fp); + free(fp); + + /* XXX certs are not yet supported for DNS */ + if (!key_is_cert(host_key) && options.verify_host_key_dns && + verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { + if (flags & DNS_VERIFY_FOUND) { + +@@ -1322,18 +1322,18 @@ show_other_keys(struct hostkeys *hostkey + char *fp, *ra; + const struct hostkey_entry *found; + + for (i = 0; type[i] != -1; i++) { + if (type[i] == key->type) + continue; + if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) + continue; +- fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX); +- ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART); ++ fp = key_fingerprint(found->key, key_fp_type_select(), SSH_FP_HEX); ++ ra = key_fingerprint(found->key, key_fp_type_select(), SSH_FP_RANDOMART); + logit("WARNING: %s key found for host %s\n" + "in %s:%lu\n" + "%s key fingerprint %s.", + key_type(found->key), + found->host, found->file, found->line, + key_type(found->key), fp); + if (options.visual_host_key) + logit("%s", ra); +@@ -1344,17 +1344,17 @@ show_other_keys(struct hostkeys *hostkey + return ret; + } + + static void + warn_changed_key(Key *host_key) + { + char *fp; + +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(host_key, key_fp_type_select(), SSH_FP_HEX); + + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); + error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); + error("It is also possible that a host key has just been changed."); + error("The fingerprint for the %s key sent by the remote host is\n%s.", +diff --git a/openssh-6.6p1/sshconnect2.c b/openssh-6.6p1/sshconnect2.c +--- a/openssh-6.6p1/sshconnect2.c ++++ b/openssh-6.6p1/sshconnect2.c +@@ -579,17 +579,17 @@ input_userauth_pk_ok(int type, u_int32_t + goto done; + } + if (key->type != pktype) { + error("input_userauth_pk_ok: type mismatch " + "for decoded key (received %d, expected %d)", + key->type, pktype); + goto done; + } +- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX); + debug2("input_userauth_pk_ok: fp %s", fp); + free(fp); + + /* + * search keys in the reverse order, because last candidate has been + * moved to the end of the queue. this also avoids confusion by + * duplicate keys + */ +@@ -990,17 +990,17 @@ sign_and_send_pubkey(Authctxt *authctxt, + Buffer b; + u_char *blob, *signature; + u_int bloblen, slen; + u_int skip = 0; + int ret = -1; + int have_sig = 1; + char *fp; + +- fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(id->key, key_fp_type_select(), SSH_FP_HEX); + debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); + free(fp); + + if (key_to_blob(id->key, &blob, &bloblen) == 0) { + /* we cannot handle this key */ + debug3("sign_and_send_pubkey: cannot handle key"); + return 0; + } diff --git a/openssh-6.6p1-fips-checks.patch b/openssh-6.6p1-fips-checks.patch new file mode 100644 index 0000000..3c78a2a --- /dev/null +++ b/openssh-6.6p1-fips-checks.patch @@ -0,0 +1,529 @@ +# HG changeset patch +# Parent 717873621cf4991164c61caafd9ac07473231f10 +# Simple implementation of FIPS 140-2 selfchecks. Use OpenSSL to generate and +# verify checksums of binaries. Any hash iused in OpenSSH can be used (MD5 would +# obviously be a poor choice, since OpenSSL would barf and abort immediately in +# FIPS mode). SHA-2 seems to be a reasonable choice. +# +# The logic of the checks is as follows: decide whether FIPS mode is mandated +# (either by checking /proc/sys/crypto/fips_enabled or envoroinment variable +# SSH_FORCE_FIPS. In FIPS mode, checksums are required to match (inability to +# retrieve pre-calculated hash is a fatal error). In non-FIPS mode the checks +# still must be performed, unless the hashes are not installed. Thus if the hash +# file is not found (or the hash matches), proceed in non-FIPS mode and abort +# otherwise. + +diff --git a/openssh-6.6p1/fips-check.c b/openssh-6.6p1/fips-check.c +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/fips-check.c +@@ -0,0 +1,37 @@ ++#include "includes.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "digest.h" ++#include "fips.h" ++ ++#include ++ ++#define PROC_NAME_LEN 64 ++ ++static const char *argv0; ++ ++void ++print_help_exit(int ev) ++{ ++ fprintf(stderr, "%s <-c|-w> \n", argv0); ++ fprintf(stderr, " -c verify hash of 'file' against hash in 'checksum_file'\n"); ++ fprintf(stderr, " -w write hash of 'file' into 'checksum_file'\n"); ++ exit(ev); ++} ++ ++int ++main(int argc, char **argv) ++{ ++ ++ fips_ssh_init(); ++// printf("SSL Error: %lx: %s", ERR_get_error(), ERR_get_string(ERR_get_error(), NULL)); ++ ++ return 0; ++} +diff --git a/openssh-6.6p1/fips.c b/openssh-6.6p1/fips.c +--- a/openssh-6.6p1/fips.c ++++ b/openssh-6.6p1/fips.c +@@ -24,21 +24,342 @@ + + #include "includes.h" + + #include "fips.h" + + #include "digest.h" + #include "key.h" + #include "log.h" ++#include "xmalloc.h" ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include + + #include ++#include ++ ++enum fips_checksum_status { ++ CHECK_OK = 0, ++ CHECK_FAIL, ++ CHECK_MISSING ++}; + + static int fips_state = -1; + ++static char * ++hex_fingerprint(u_int raw_len, u_char *raw) ++{ ++ char *retval; ++ u_int i; ++ ++ /* reserve space for both the key hash and the string for the hash type */ ++ retval = malloc(3 * raw_len); ++ for (i = 0; i < raw_len; i++) { ++ char hex[4]; ++ snprintf(hex, sizeof(hex), "%02x:", raw[i]); ++ strlcat(retval, hex, raw_len * 3); ++ } ++ ++ return retval; ++} ++ ++/* calculates hash of contents of file given by filename using algorithm alg ++ * and placing the resukt into newly allacated memory - remember to free it ++ * when not needed anymore */ ++static int ++hash_file(const char *filename, int alg, u_char **hash_out) ++{ ++ int check = -1; ++ int hash_len; ++ int fd; ++ struct stat fs; ++ void *hmap; ++ char *hash; ++ ++ hash_len = ssh_digest_bytes(alg); ++ hash = xmalloc(hash_len); ++ ++ fd = open(filename, O_RDONLY); ++ if (-1 == fd) ++ goto bail_out; ++ ++ if (-1 == fstat(fd, &fs)) ++ goto bail_out; ++ ++ hmap = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, fd, 0); ++ ++ if ((void *)(-1) != hmap) { ++ check = ssh_digest_memory(alg, hmap, fs.st_size, hash, hash_len); ++ munmap(hmap, fs.st_size); ++ } ++ close(fd); ++ ++bail_out: ++ if (0 == check) { ++ check = CHECK_OK; ++ *hash_out = hash; ++ } else { ++ check = CHECK_FAIL; ++ *hash_out = NULL; ++ free(hash); ++ } ++ return check; ++} ++ ++/* find pathname of binary of process with PID pid. exe is buffer expected to ++ * be capable of holding at least max_pathlen characters ++ */ ++static int ++get_executable_path(pid_t pid, char *exe, int max_pathlen) ++{ ++ char exe_sl[PROC_EXE_PATH_LEN]; ++ int n; ++ ++ n = snprintf(exe_sl, sizeof(exe_sl), "/proc/%u/exe", pid); ++ if ((n <= 10) || (n >= max_pathlen)) { ++ fatal("error compiling filename of link to executable"); ++ } ++ ++ n = readlink(exe_sl, exe, max_pathlen); ++ if (n < max_pathlen) { ++ exe[n] = 0; ++ } else { ++ fatal("error getting executable pathname"); ++ } ++ return 0; ++} ++ ++/* Read checksum file chk, storing the algorithm used for generating it into ++ * *alg; allocate enough memory to hold the hash and return it in *hash. ++ * Remember to free() it when not needed anymore. ++ */ ++static int ++read_hash(const char *chk, int *alg, u_char **hash) ++{ ++ int check = -1; ++ int hash_len; ++ int fdh, n; ++ char alg_c; ++ char *hash_in; ++ ++ *hash = NULL; ++ ++ fdh = open(chk, O_RDONLY); ++ if (-1 == fdh) { ++ switch (errno) { ++ case ENOENT: ++ check = CHECK_MISSING; ++ debug("fips: checksum file %s is missing\n", chk); ++ break; ++ default: ++ check = CHECK_FAIL; ++ debug("fips: ckecksum file %s not accessible\n", chk); ++ break; ++ ++ } ++ goto bail_out; ++ } ++ ++ n = read(fdh, &alg_c, 1); ++ if (1 != n) { ++ check = CHECK_FAIL; ++ goto bail_out; ++ } ++ ++ *alg = (int)alg_c; ++ hash_len = ssh_digest_bytes(*alg); ++ hash_in = xmalloc(hash_len); ++ ++ n = read(fdh, (void *)hash_in, hash_len); ++ if (hash_len != n) { ++ debug("fips: unable to read whole checksum from checksum file\n"); ++ free (hash_in); ++ check = CHECK_FAIL; ++ } else { ++ check = CHECK_OK; ++ *hash = hash_in; ++ } ++bail_out: ++ return check; ++} ++ ++static int ++fips_hash_self(void) ++{ ++ int check = -1; ++ int alg; ++ u_char *hash, *hash_chk; ++ char *exe, *chk; ++ ++ exe = xmalloc(PATH_MAX); ++ chk = xmalloc(PATH_MAX); ++ ++ /* we will need to add the ".chk" suffix and the null terminator */ ++ check = get_executable_path(getpid(), exe ++ , PATH_MAX - strlen(CHECKSUM_SUFFIX) - 1); ++ ++ strncpy(chk, exe, PATH_MAX); ++ strlcat(chk, CHECKSUM_SUFFIX, PATH_MAX); ++ ++ check = read_hash(chk, &alg, &hash_chk); ++ if (CHECK_OK != check) ++ goto cleanup_chk; ++ ++ check = hash_file(exe, alg, &hash); ++ if (CHECK_OK != check) ++ goto cleanup; ++ ++ check = memcmp(hash, hash_chk, ssh_digest_bytes(alg)); ++ if (0 == check) { ++ check = CHECK_OK; ++ debug("fips: checksum matches\n"); ++ } else { ++ check = CHECK_FAIL; ++ debug("fips: checksum mismatch!\n"); ++ } ++ ++cleanup: ++ free(hash); ++cleanup_chk: ++ free(hash_chk); ++ free(chk); ++ free(exe); ++ ++ return check; ++} ++ ++static int ++fips_check_required_proc(void) ++{ ++ int fips_required = 0; ++ int fips_fd; ++ char fips_sys = 0; ++ ++ struct stat dummy; ++ if (-1 == stat(FIPS_PROC_PATH, &dummy)) { ++ switch (errno) { ++ case ENOENT: ++ case ENOTDIR: ++ break; ++ default: ++ fatal("Check for system-wide FIPS mode is required and %s cannot" ++ " be accessed for reason other than non-existence - aborting" ++ , FIPS_PROC_PATH); ++ break; ++ } ++ } else { ++ if (-1 == (fips_fd = open(FIPS_PROC_PATH, O_RDONLY))) ++ fatal("Check for system-wide FIPS mode is required and %s cannot" ++ " be opened for reading - aborting" ++ , FIPS_PROC_PATH); ++ if (1 > read(fips_fd, &fips_sys, 1)) ++ fatal("Check for system-wide FIPS mode is required and %s doesn't" ++ " return at least one character - aborting" ++ , FIPS_PROC_PATH); ++ close(fips_sys); ++ switch (fips_sys) { ++ case '0': ++ case '1': ++ fips_required = fips_sys - '0'; ++ break; ++ default: ++ fatal("Bogus character %c found in %s - aborting" ++ , fips_sys, FIPS_PROC_PATH); ++ } ++ } ++ return fips_required; ++} ++ ++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; ++} ++ ++static int ++fips_required(void) ++{ ++ int fips_requests = 0; ++ fips_requests += fips_check_required_proc(); ++ fips_requests += fips_check_required_env(); ++ return fips_requests; ++} ++ ++/* check whether FIPS mode is required and perform selfchecksum/selftest */ ++void ++fips_ssh_init(void) ++{ ++ int checksum; ++ ++ checksum = fips_hash_self(); ++ ++ if (fips_required()) { ++ switch (checksum) { ++ case CHECK_OK: ++ debug("fips: mandatory checksum ok"); ++ break; ++ case CHECK_FAIL: ++ fatal("fips: mandatory checksum failed - aborting"); ++ break; ++ case CHECK_MISSING: ++ fatal("fips: mandatory checksum data missing - aborting"); ++ break; ++ default: ++ fatal("Fatal error: internal error at %s:%u" ++ , __FILE__, __LINE__); ++ break; ++ } ++ fips_state = FIPS_mode_set(1); ++ if (1 != fips_state) { ++ ERR_load_crypto_strings(); ++ u_long err = ERR_get_error(); ++ error("fips: OpenSSL error %lx: %s", err, ERR_error_string(err, NULL)); ++ fatal("fips: unable to set OpenSSL into FIPS mode - aborting" ++ , fips_state); ++ } ++ } else { ++ switch (checksum) { ++ case CHECK_OK: ++ debug("fips: checksum ok"); ++ break; ++ case CHECK_FAIL: ++ fatal("fips: checksum failed - aborting"); ++ break; ++ case CHECK_MISSING: ++ debug("fips: mandatory checksum data missing, but not required - continuing non-FIPS"); ++ break; ++ default: ++ fatal("Fatal error: internal error at %s:%u", ++ __FILE__, __LINE__); ++ break; ++ } ++ } ++ return; ++} ++ + int + fips_mode() + { + if (-1 == fips_state) { + fips_state = FIPS_mode(); + if (fips_state) + debug("FIPS mode initialized"); + } +diff --git a/openssh-6.6p1/fips.h b/openssh-6.6p1/fips.h +--- a/openssh-6.6p1/fips.h ++++ b/openssh-6.6p1/fips.h +@@ -1,10 +1,10 @@ + /* +- * Copyright (c) 2012 Petr Cerny. All rights reserved. ++ * Copyright (c) 2012-2014 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 +@@ -19,15 +19,22 @@ + * 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 + ++#define SSH_FORCE_FIPS_ENV "SSH_FORCE_FIPS" ++#define FIPS_PROC_PATH "/proc/sys/crypto/fips_enabled" ++ ++#define PROC_EXE_PATH_LEN 64 ++#define CHECKSUM_SUFFIX ".chk" ++ ++void fips_ssh_init(void); + int fips_mode(void); + int fips_correct_dgst(int); + int fips_dgst_min(void); + enum fp_type fips_correct_fp_type(enum fp_type); + + #endif + +diff --git a/openssh-6.6p1/sftp-server.c b/openssh-6.6p1/sftp-server.c +--- a/openssh-6.6p1/sftp-server.c ++++ b/openssh-6.6p1/sftp-server.c +@@ -47,16 +47,18 @@ + #include "log.h" + #include "misc.h" + #include "match.h" + #include "uidswap.h" + + #include "sftp.h" + #include "sftp-common.h" + ++#include "fips.h" ++ + /* helper */ + #define get_int64() buffer_get_int64(&iqueue); + #define get_int() buffer_get_int(&iqueue); + #define get_string(lenp) buffer_get_string(&iqueue, lenp); + + /* Our verbosity */ + static LogLevel log_level = SYSLOG_LEVEL_ERROR; + +@@ -1453,16 +1455,19 @@ sftp_server_main(int argc, char **argv, + ssize_t len, olen, set_size; + SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; + char *cp, *homedir = NULL, buf[4*4096]; + long mask; + + extern char *optarg; + extern char *__progname; + ++ /* initialize fips */ ++ fips_ssh_init(); ++ + __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:m:cehR")) != -1) { + switch (ch) { +diff --git a/openssh-6.6p1/ssh.c b/openssh-6.6p1/ssh.c +--- a/openssh-6.6p1/ssh.c ++++ b/openssh-6.6p1/ssh.c +@@ -420,16 +420,19 @@ main(int ac, char **av) + struct stat st; + struct passwd *pw; + int timeout_ms; + extern int optind, optreset; + extern char *optarg; + Forward fwd; + struct addrinfo *addrs = NULL; + ++ /* initialize fips */ ++ fips_ssh_init(); ++ + /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ + sanitise_stdfd(); + + __progname = ssh_get_progname(av[0]); + + #ifndef HAVE_SETPROCTITLE + /* Prepare for later setproctitle emulation */ + /* Save argv so it isn't clobbered by setproctitle() emulation */ +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -1466,16 +1466,19 @@ main(int ac, char **av) + u_int64_t ibytes, obytes; + mode_t new_umask; + Key *key; + Key *pubkey; + int keytype; + Authctxt *authctxt; + struct connection_info *connection_info = get_connection_info(0, 0); + ++ /* initialize fips */ ++ fips_ssh_init(); ++ + #ifdef HAVE_SECUREWARE + (void)set_auth_parameters(ac, av); + #endif + __progname = ssh_get_progname(av[0]); + + /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ + saved_argc = ac; + rexec_argc = ac; diff --git a/openssh-6.6p1-fips.patch b/openssh-6.6p1-fips.patch index a7573a7..21e675f 100644 --- a/openssh-6.6p1-fips.patch +++ b/openssh-6.6p1-fips.patch @@ -1,22 +1,247 @@ -Index: openssh-7.1p2/cipher.c -=================================================================== ---- openssh-7.1p2.orig/cipher.c -+++ openssh-7.1p2/cipher.c -@@ -39,6 +39,8 @@ +# comply with FIPS 140-2 by using only approved crypto algorithms +# when OpenSSL is detected to be running in FIPS mode +# +# HG changeset patch +# Parent 844066cb9c0ec2b10eb1ace7134f7bced7cc802d + +diff --git a/openssh-6.6p1/Makefile.in b/openssh-6.6p1/Makefile.in +--- a/openssh-6.6p1/Makefile.in ++++ b/openssh-6.6p1/Makefile.in +@@ -71,17 +71,18 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o + readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \ + atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ + monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ + kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ + msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ + ssh-pkcs11.o krl.o smult_curve25519_ref.o \ + kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ + ssh-ed25519.o digest-openssl.o hmac.o \ +- sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o ++ sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ ++ fips.o - #include + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o \ + roaming_common.o roaming_client.o -+#include + 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 \ +diff --git a/openssh-6.6p1/auth-rsa.c b/openssh-6.6p1/auth-rsa.c +--- a/openssh-6.6p1/auth-rsa.c ++++ b/openssh-6.6p1/auth-rsa.c +@@ -44,16 +44,18 @@ + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" + #include "ssh.h" + #include "misc.h" + + #include "digest.h" + ++#include "fips.h" + - #include + /* 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]; +@@ -84,45 +86,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); + } + + /* +@@ -130,17 +139,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. */ +@@ -150,17 +159,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-6.6p1/cipher-ctr.c b/openssh-6.6p1/cipher-ctr.c +--- a/openssh-6.6p1/cipher-ctr.c ++++ b/openssh-6.6p1/cipher-ctr.c +@@ -22,16 +22,18 @@ #include - #include -@@ -99,6 +101,26 @@ static const struct sshcipher ciphers[] + #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 /* OPENSSL_HAVE_EVPCTR */ +diff --git a/openssh-6.6p1/cipher.c b/openssh-6.6p1/cipher.c +--- a/openssh-6.6p1/cipher.c ++++ b/openssh-6.6p1/cipher.c +@@ -45,16 +45,18 @@ + + #include "xmalloc.h" + #include "log.h" + #include "misc.h" + #include "cipher.h" + #include "buffer.h" + #include "digest.h" + ++#include "fips.h" ++ + /* compatibility with old or broken OpenSSL versions */ + #include "openbsd-compat/openssl-compat.h" + + extern const EVP_CIPHER *evp_ssh1_bf(void); + extern const EVP_CIPHER *evp_ssh1_3des(void); + extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); + + struct Cipher { +@@ -66,17 +68,17 @@ struct Cipher { + u_int auth_len; + u_int discard_len; + u_int flags; + #define CFLAG_CBC (1<<0) + #define CFLAG_CHACHAPOLY (1<<1) + const EVP_CIPHER *(*evptype)(void); + }; + +-static const struct Cipher ciphers[] = { ++static const struct Cipher ciphers_all[] = { + { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, + { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, + { "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 }, + + { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, + { "blowfish-cbc", + SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc }, +@@ -99,27 +101,67 @@ static const struct Cipher ciphers[] = { + { "aes256-gcm@openssh.com", + SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, + #endif + { "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 fips_ciphers[] = { ++static const struct Cipher ciphers_fips140_2[] = { + { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, ++ { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, ++ + { "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 }, @@ -37,205 +262,449 @@ Index: openssh-7.1p2/cipher.c + /*--*/ - /* Returns a comma-separated list of supported ciphers. */ -@@ -109,7 +131,7 @@ cipher_alg_list(char sep, int auth_only) ++/* Returns array of ciphers available depending on selected FIPS mode */ ++static struct Cipher * ++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 list of supported ciphers separated by the specified char. */ + char * + cipher_alg_list(char sep, int auth_only) + { + char *ret = NULL; size_t nlen, rlen = 0; - const struct sshcipher *c; + const Cipher *c; - for (c = ciphers; c->name != NULL; c++) { -+ for (c = FIPS_mode() ? fips_ciphers : 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) -@@ -193,7 +215,7 @@ const struct sshcipher * + continue; + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(c->name); + ret = xrealloc(ret, 1, rlen + nlen + 2); +@@ -189,27 +231,27 @@ cipher_mask_ssh1(int client) + } + return mask; + } + + const Cipher * cipher_by_name(const char *name) { - const struct sshcipher *c; + const Cipher *c; - for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) ++ for (c = fips_select_ciphers(); c->name != NULL; c++) if (strcmp(c->name, name) == 0) return c; return NULL; -@@ -203,7 +225,7 @@ const struct sshcipher * + } + + const Cipher * cipher_by_number(int id) { - const struct sshcipher *c; + const Cipher *c; - for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) ++ for (c = fips_select_ciphers(); c->name != NULL; c++) if (c->number == id) return c; return NULL; -@@ -244,7 +266,7 @@ cipher_number(const char *name) - const struct sshcipher *c; + } + + #define CIPHER_SEP "," + int + ciphers_valid(const char *names) +@@ -241,17 +283,17 @@ ciphers_valid(const char *names) + */ + + int + cipher_number(const char *name) + { + const Cipher *c; if (name == NULL) return -1; - for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) ++ for (c = fips_select_ciphers(); c->name != NULL; c++) if (strcasecmp(c->name, name) == 0) return c->number; return -1; -Index: openssh-7.1p2/cipher-ctr.c -=================================================================== ---- openssh-7.1p2.orig/cipher-ctr.c -+++ openssh-7.1p2/cipher-ctr.c -@@ -138,7 +138,8 @@ evp_aes_128_ctr(void) - aes_ctr.do_cipher = ssh_aes_ctr; - #ifndef SSH_OLD_EVP - aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | -- EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; -+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV | -+ EVP_CIPH_FLAG_FIPS; - #endif - return (&aes_ctr); } -Index: openssh-7.1p2/dh.h -=================================================================== ---- openssh-7.1p2.orig/dh.h -+++ openssh-7.1p2/dh.h -@@ -46,6 +46,7 @@ u_int dh_estimate(int); - /* Min and max values from RFC4419. */ - #define DH_GRP_MIN 1024 -+#define DH_GRP_MIN_FIPS 2048 - #define DH_GRP_MAX 8192 + char * + cipher_name(int id) + { +@@ -429,23 +471,24 @@ cipher_cleanup(CipherContext *cc) + * Selects the cipher, and keys if by computing the MD5 checksum of the + * passphrase and using the resulting 16 bytes as the key. + */ + + void + cipher_set_key_string(CipherContext *cc, const Cipher *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); + +- if (ssh_digest_memory(SSH_DIGEST_MD5, passphrase, strlen(passphrase), ++ if (ssh_digest_memory(dgst, passphrase, strlen(passphrase), + digest, sizeof(digest)) < 0) + fatal("%s: md5 failed", __func__); + +- cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt); ++ cipher_init(cc, cipher, digest, ssh_digest_bytes(dgst), NULL, 0, do_encrypt); + + explicit_bzero(digest, sizeof(digest)); + } /* -Index: openssh-7.1p2/entropy.c -=================================================================== ---- openssh-7.1p2.orig/entropy.c -+++ openssh-7.1p2/entropy.c -@@ -218,6 +218,8 @@ seed_rng(void) - fatal("OpenSSL version mismatch. Built against %lx, you " - "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); - #endif -+ /* clean the PRNG status when exiting the program */ -+ atexit(RAND_cleanup); - #ifndef OPENSSL_PRNG_ONLY - if (RAND_status() == 1) { - debug3("RNG is ready, skipping seeding"); -Index: openssh-7.1p2/kex.c -=================================================================== ---- openssh-7.1p2.orig/kex.c -+++ openssh-7.1p2/kex.c -@@ -35,6 +35,7 @@ + * Exports an IV from the CipherContext required to export the key + * state back from the unprivileged child to the privileged parent + * process. +diff --git a/openssh-6.6p1/fips.c b/openssh-6.6p1/fips.c +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/fips.c +@@ -0,0 +1,128 @@ ++/* ++ * 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 "digest.h" ++#include "key.h" ++#include "log.h" ++ ++#include ++ ++static int fips_state = -1; ++ ++int ++fips_mode() ++{ ++ if (-1 == fips_state) { ++ fips_state = FIPS_mode(); ++ if (fips_state) ++ debug("FIPS mode initialized"); ++ } ++ return fips_state; ++} ++ ++enum fp_type ++fips_correct_fp_type(enum fp_type fp) ++{ ++ int fips; ++ enum fp_type fp_fix = fp; ++ ++ fips = fips_mode(); ++ switch (fips) { ++ case 0: ++ break; ++ case 1: ++ if (SSH_FP_MD5 == fp) { ++ fp_fix = SSH_FP_SHA1; ++ debug("MD5 not allowed in FIPS 140-2 mode, " ++ "using SHA-1 for key fingerprints instead."); ++ } ++ break; ++ default: ++ /* should not be reached */ ++ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u", ++ fips, __FILE__, __LINE__); ++ } ++ ++ return fp_fix; ++} ++ ++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-1 instead."); ++ rv = SSH_DIGEST_SHA1; ++ 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; ++} ++ ++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; ++} ++ +diff --git a/openssh-6.6p1/fips.h b/openssh-6.6p1/fips.h +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/fips.h +@@ -0,0 +1,33 @@ ++/* ++ * 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 ++ ++int fips_mode(void); ++int fips_correct_dgst(int); ++int fips_dgst_min(void); ++enum fp_type fips_correct_fp_type(enum fp_type); ++ ++#endif ++ +diff --git a/openssh-6.6p1/hmac.c b/openssh-6.6p1/hmac.c +--- a/openssh-6.6p1/hmac.c ++++ b/openssh-6.6p1/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]; - #ifdef WITH_OPENSSL - #include -+#include - #endif +- 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-6.6p1/kex.c b/openssh-6.6p1/kex.c +--- a/openssh-6.6p1/kex.c ++++ b/openssh-6.6p1/kex.c +@@ -638,19 +638,21 @@ kex_get_newkeys(int mode) + } + + void + derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, + u_int8_t cookie[8], u_int8_t id[16]) + { + u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; + int len; ++ int digest; + struct ssh_digest_ctx *hashctx; + +- if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) ++ digest = fips_correct_dgst(SSH_DIGEST_MD5); ++ if ((hashctx = ssh_digest_start(digest)) == NULL) + fatal("%s: ssh_digest_start", __func__); + + len = BN_num_bytes(host_modulus); + if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) + fatal("%s: bad host modulus (len %d)", __func__, len); + BN_bn2bin(host_modulus, nbuf); + if (ssh_digest_update(hashctx, nbuf, len) != 0) + fatal("%s: ssh_digest_update failed", __func__); +@@ -659,17 +661,17 @@ derive_ssh1_session_id(BIGNUM *host_modu + if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) + fatal("%s: bad server modulus (len %d)", __func__, len); + BN_bn2bin(server_modulus, nbuf); + if (ssh_digest_update(hashctx, nbuf, len) != 0 || + ssh_digest_update(hashctx, cookie, 8) != 0) + fatal("%s: ssh_digest_update failed", __func__); + if (ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) + fatal("%s: ssh_digest_final failed", __func__); +- memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); ++ memcpy(id, obuf, ssh_digest_bytes(digest)); + + explicit_bzero(nbuf, sizeof(nbuf)); + explicit_bzero(obuf, sizeof(obuf)); + } + + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) + void + dump_digest(char *msg, u_char *digest, int len) +diff --git a/openssh-6.6p1/key.c b/openssh-6.6p1/key.c +--- a/openssh-6.6p1/key.c ++++ b/openssh-6.6p1/key.c +@@ -53,16 +53,18 @@ + #include "rsa.h" + #include "uuencode.h" + #include "buffer.h" + #include "log.h" + #include "misc.h" #include "ssh2.h" -@@ -108,6 +109,25 @@ static const struct kexalg kexalgs[] = { - { NULL, -1, -1, -1}, - }; + #include "digest.h" -+static const struct kexalg kexalgs_fips[] = { -+ { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, -+#ifdef HAVE_EVP_SHA256 -+ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, -+#endif -+#ifdef OPENSSL_HAS_ECC -+ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, -+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, -+ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, -+ SSH_DIGEST_SHA384 }, -+# ifdef OPENSSL_HAS_NISTP521 -+ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, -+ SSH_DIGEST_SHA512 }, -+# endif -+#endif -+ { NULL, -1, -1, -1}, -+}; ++#include "fips.h" + - char * - kex_alg_list(char sep) + static int to_blob(const Key *, u_char **, u_int *, int); + static Key *key_from_blob2(const u_char *, u_int, int); + + static struct KeyCert * + cert_new(void) { -@@ -135,7 +155,7 @@ kex_alg_by_name(const char *name) - { - const struct kexalg *k; + struct KeyCert *cert; -- for (k = kexalgs; k->name != NULL; k++) { -+ for (k = (FIPS_mode() ? kexalgs_fips : kexalgs); k->name != NULL; k++) { - if (strcmp(k->name, name) == 0) - return k; - #ifdef GSSAPI -@@ -161,7 +181,10 @@ kex_names_valid(const char *names) - for ((p = strsep(&cp, ",")); p && *p != '\0'; - (p = strsep(&cp, ","))) { - if (kex_alg_by_name(p) == NULL) { -- error("Unsupported KEX algorithm \"%.100s\"", p); -+ if (FIPS_mode()) -+ error("\"%.100s\" is not allowed in FIPS mode", p); -+ else -+ error("Unsupported KEX algorithm \"%.100s\"", p); - free(s); - return 0; - } -Index: openssh-7.1p2/kexgexc.c -=================================================================== ---- openssh-7.1p2.orig/kexgexc.c -+++ openssh-7.1p2/kexgexc.c -@@ -28,6 +28,7 @@ +@@ -664,16 +666,19 @@ key_fp_type_select(void) + error("invalid key type in environment variable " + SSH_FP_TYPE_ENVVAR ": '%s' - falling back to MD5.", + env); + fp = SSH_FP_MD5; + } + } else + fp = SSH_FP_MD5; - #ifdef WITH_OPENSSL - -+#include - #include - #include - -@@ -63,7 +64,7 @@ kexgex_client(struct ssh *ssh) - - nbits = dh_estimate(kex->dh_need * 8); - -- kex->min = DH_GRP_MIN; -+ kex->min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; - kex->max = DH_GRP_MAX; - kex->nbits = nbits; - if (datafellows & SSH_BUG_DHGEX_LARGE) -Index: openssh-7.1p2/kexgexs.c -=================================================================== ---- openssh-7.1p2.orig/kexgexs.c -+++ openssh-7.1p2/kexgexs.c -@@ -83,9 +83,9 @@ input_kex_dh_gex_request(int type, u_int - kex->nbits = nbits; - kex->min = min; - kex->max = max; -- min = MAX(DH_GRP_MIN, min); -+ min = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, min); - max = MIN(DH_GRP_MAX, max); -- nbits = MAX(DH_GRP_MIN, nbits); -+ nbits = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, nbits); - nbits = MIN(DH_GRP_MAX, nbits); - - if (kex->max < kex->min || kex->nbits < kex->min || -Index: openssh-7.1p2/mac.c -=================================================================== ---- openssh-7.1p2.orig/mac.c -+++ openssh-7.1p2/mac.c -@@ -27,6 +27,8 @@ - - #include - -+#include ++ if (fips_mode()) ++ fp = fips_correct_fp_type(fp); + - #include - #include + fp_defined = 1; + } + return fp; + } -@@ -54,7 +56,7 @@ struct macalg { + /* + * string lengths must be less or equal to SSH_FP_TYPE_STRLEN (defined in + * key.h) as to fit into the fingerprint string buffer +diff --git a/openssh-6.6p1/mac.c b/openssh-6.6p1/mac.c +--- a/openssh-6.6p1/mac.c ++++ b/openssh-6.6p1/mac.c +@@ -39,33 +39,35 @@ + #include "kex.h" + #include "mac.h" + #include "misc.h" + + #include "digest.h" + #include "hmac.h" + #include "umac.h" + ++#include "fips.h" ++ + #include "openbsd-compat/openssl-compat.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 all_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 }, -@@ -85,6 +87,24 @@ static const struct macalg macs[] = { + #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 }, +@@ -86,25 +88,59 @@ 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 fips_macs[] = { ++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 @@ -244,410 +713,347 @@ Index: openssh-7.1p2/mac.c +#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 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__); ++// return NULL; ++ } ++} + /* Returns a list of supported MACs separated by the specified char. */ char * mac_alg_list(char sep) -@@ -93,7 +113,7 @@ mac_alg_list(char sep) + { + char *ret = NULL; size_t nlen, rlen = 0; const struct macalg *m; - for (m = macs; m->name != NULL; m++) { -+ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { ++ for (m = fips_select_macs(); m->name != NULL; m++) { if (ret != NULL) ret[rlen++] = sep; nlen = strlen(m->name); -@@ -132,7 +152,7 @@ mac_setup(struct sshmac *mac, char *name + ret = xrealloc(ret, 1, rlen + nlen + 2); + memcpy(ret + rlen, m->name, nlen + 1); + rlen += nlen; + } + return ret; +@@ -128,17 +164,17 @@ mac_setup_by_alg(Mac *mac, const struct + mac->etm = macalg->etm; + } + + int + mac_setup(Mac *mac, char *name) { const struct macalg *m; - for (m = macs; m->name != NULL; m++) { -+ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { ++ for (m = fips_select_macs(); m->name != NULL; m++) { if (strcmp(name, m->name) != 0) continue; - if (mac != NULL) -Index: openssh-7.1p2/Makefile.in -=================================================================== ---- openssh-7.1p2.orig/Makefile.in -+++ openssh-7.1p2/Makefile.in -@@ -165,25 +165,25 @@ libssh.a: $(LIBSSH_OBJS) - $(RANLIB) $@ + if (mac != NULL) { + mac_setup_by_alg(mac, m); + debug2("mac_setup: setup %s", name); + } + return (0); + } +diff --git a/openssh-6.6p1/myproposal.h b/openssh-6.6p1/myproposal.h +--- a/openssh-6.6p1/myproposal.h ++++ b/openssh-6.6p1/myproposal.h +@@ -104,16 +104,20 @@ - ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) -- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) -+ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHLIBS) $(LIBS) $(GSSLIBS) - - sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) -- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) -+ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) - - scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o -- $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o -- $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o -- $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o -- $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o -- $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o - $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) -@@ -192,7 +192,7 @@ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) l - $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o sshbuf-getput-basic.o ssherr.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o -- $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -+ $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) - - sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o - $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -Index: openssh-7.1p2/myproposal.h -=================================================================== ---- openssh-7.1p2.orig/myproposal.h -+++ openssh-7.1p2/myproposal.h -@@ -138,6 +138,28 @@ - "hmac-sha1-96," \ - "hmac-md5-96" - -+#define KEX_DEFAULT_KEX_FIPS \ -+ KEX_ECDH_METHODS \ -+ KEX_SHA256_METHODS \ -+ "diffie-hellman-group-exchange-sha1," \ -+ "diffie-hellman-group14-sha1" -+#define KEX_FIPS_ENCRYPT \ + #define KEX_DEFAULT_ENCRYPT \ + "aes128-ctr,aes192-ctr,aes256-ctr," \ + "arcfour256,arcfour128," \ + AESGCM_CIPHER_MODES \ + "chacha20-poly1305@openssh.com," \ + "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ + "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se" ++#define KEX_FIPS_140_2_ENCRYPT \ + "aes128-ctr,aes192-ctr,aes256-ctr," \ + "aes128-cbc,3des-cbc," \ + "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se" -+#ifdef HAVE_EVP_SHA256 -+#define KEX_FIPS_MAC \ + + #define KEX_DEFAULT_MAC \ + "hmac-md5-etm@openssh.com," \ + "hmac-sha1-etm@openssh.com," \ + "umac-64-etm@openssh.com," \ + "umac-128-etm@openssh.com," \ + "hmac-sha2-256-etm@openssh.com," \ + "hmac-sha2-512-etm@openssh.com," \ +@@ -124,16 +128,19 @@ + "hmac-sha1," \ + "umac-64@openssh.com," \ + "umac-128@openssh.com," \ + SHA2_HMAC_MODES \ + "hmac-ripemd160," \ + "hmac-ripemd160@openssh.com," \ + "hmac-sha1-96," \ + "hmac-md5-96" ++#define KEX_FIPS_140_2_MAC \ + "hmac-sha1," \ -+ "hmac-sha2-256," \ -+ "hmac-sha2-512," \ -+ "hmac-sha1-etm@openssh.com," \ -+ "hmac-sha2-256-etm@openssh.com," \ -+ "hmac-sha2-512-etm@openssh.com" -+#else -+#define KEX_FIPS_MAC \ -+ "hmac-sha1" -+#endif ++ SHA2_HMAC_MODES \ + + #define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" + #define KEX_DEFAULT_LANG "" + + + static char *myproposal[PROPOSAL_MAX] = { + KEX_DEFAULT_KEX, + KEX_DEFAULT_PK_ALG, +diff --git a/openssh-6.6p1/ssh.c b/openssh-6.6p1/ssh.c +--- a/openssh-6.6p1/ssh.c ++++ b/openssh-6.6p1/ssh.c +@@ -100,16 +100,18 @@ + #include "mac.h" + #include "sshpty.h" + #include "match.h" + #include "msg.h" + #include "uidswap.h" + #include "roaming.h" + #include "version.h" + ++#include "fips.h" + - #else - - #define KEX_SERVER_KEX \ -Index: openssh-7.1p2/readconf.c -=================================================================== ---- openssh-7.1p2.orig/readconf.c -+++ openssh-7.1p2/readconf.c -@@ -1905,9 +1905,12 @@ fill_default_options(Options * options) - options->fingerprint_hash = SSH_FP_HASH_DEFAULT; - if (options->update_hostkeys == -1) - options->update_hostkeys = 0; -- if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 || -- kex_assemble_names(KEX_CLIENT_MAC, &options->macs) != 0 || -- kex_assemble_names(KEX_CLIENT_KEX, &options->kex_algorithms) != 0 || -+ if (kex_assemble_names((FIPS_mode() ? KEX_FIPS_ENCRYPT -+ : KEX_CLIENT_ENCRYPT), &options->ciphers) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_MAC -+ : KEX_CLIENT_MAC), &options->macs) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_DEFAULT_KEX_FIPS -+ : KEX_CLIENT_KEX), &options->kex_algorithms) != 0 || - kex_assemble_names(KEX_DEFAULT_PK_ALG, - &options->hostbased_key_types) != 0 || - kex_assemble_names(KEX_DEFAULT_PK_ALG, -Index: openssh-7.1p2/servconf.c -=================================================================== ---- openssh-7.1p2.orig/servconf.c -+++ openssh-7.1p2/servconf.c -@@ -354,9 +354,12 @@ fill_default_server_options(ServerOption - if (options->fingerprint_hash == -1) - options->fingerprint_hash = SSH_FP_HASH_DEFAULT; - -- if (kex_assemble_names(KEX_SERVER_ENCRYPT, &options->ciphers) != 0 || -- kex_assemble_names(KEX_SERVER_MAC, &options->macs) != 0 || -- kex_assemble_names(KEX_SERVER_KEX, &options->kex_algorithms) != 0 || -+ if (kex_assemble_names((FIPS_mode() ? KEX_FIPS_ENCRYPT -+ : KEX_SERVER_ENCRYPT), &options->ciphers) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_MAC -+ : KEX_SERVER_MAC), &options->macs) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_DEFAULT_KEX_FIPS -+ : KEX_SERVER_KEX), &options->kex_algorithms) != 0 || - kex_assemble_names(KEX_DEFAULT_PK_ALG, - &options->hostbased_key_types) != 0 || - kex_assemble_names(KEX_DEFAULT_PK_ALG, -@@ -2316,8 +2319,10 @@ dump_config(ServerOptions *o) - /* string arguments */ - dump_cfg_string(sPidFile, o->pid_file); - dump_cfg_string(sXAuthLocation, o->xauth_location); -- dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : KEX_SERVER_ENCRYPT); -- dump_cfg_string(sMacs, o->macs ? o->macs : KEX_SERVER_MAC); -+ dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : FIPS_mode() -+ ? KEX_FIPS_ENCRYPT : KEX_SERVER_ENCRYPT); -+ dump_cfg_string(sMacs, o->macs ? o->macs : FIPS_mode() -+ ? KEX_FIPS_MAC : KEX_SERVER_MAC); - dump_cfg_string(sBanner, o->banner); - dump_cfg_string(sForceCommand, o->adm_forced_command); - dump_cfg_string(sChrootDirectory, o->chroot_directory); -@@ -2332,8 +2337,8 @@ dump_config(ServerOptions *o) - dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command); - dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user); - dump_cfg_string(sHostKeyAgent, o->host_key_agent); -- dump_cfg_string(sKexAlgorithms, -- o->kex_algorithms ? o->kex_algorithms : KEX_SERVER_KEX); -+ dump_cfg_string(sKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : -+ FIPS_mode() ? KEX_DEFAULT_KEX_FIPS : KEX_SERVER_KEX); - dump_cfg_string(sHostbasedAcceptedKeyTypes, o->hostbased_key_types ? - o->hostbased_key_types : KEX_DEFAULT_PK_ALG); - dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms ? -Index: openssh-7.1p2/ssh.c -=================================================================== ---- openssh-7.1p2.orig/ssh.c -+++ openssh-7.1p2/ssh.c -@@ -75,6 +75,8 @@ - #include - #include + #ifdef ENABLE_PKCS11 + #include "ssh-pkcs11.h" #endif -+#include -+#include - #include "openbsd-compat/openssl-compat.h" - #include "openbsd-compat/sys-queue.h" -@@ -522,6 +524,14 @@ main(int ac, char **av) - sanitise_stdfd(); - - __progname = ssh_get_progname(av[0]); -+ SSLeay_add_all_algorithms(); -+ if (access("/etc/system-fips", F_OK) == 0) -+ if (! FIPSCHECK_verify(NULL, NULL)){ -+ if (FIPS_mode()) -+ fatal("FIPS integrity verification test failed."); -+ else -+ logit("FIPS integrity verification test failed."); -+ } + extern char *__progname; + /* Saves a copy of argv for setproctitle emulation */ #ifndef HAVE_SETPROCTITLE - /* Prepare for later setproctitle emulation */ -@@ -599,6 +609,9 @@ main(int ac, char **av) - "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { +@@ -499,16 +501,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:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { switch (opt) { case '1': -+ if (FIPS_mode()) { ++ if (fips_mode()) + fatal("Protocol 1 not allowed in the FIPS mode."); -+ } options.protocol = SSH_PROTO_1; break; case '2': -@@ -940,7 +953,6 @@ main(int ac, char **av) + options.protocol = SSH_PROTO_2; + break; + case '4': + options.address_family = AF_INET; + break; +@@ -826,16 +830,22 @@ main(int ac, char **av) + if (!host) + usage(); + host_arg = xstrdup(host); - #ifdef WITH_OPENSSL -- OpenSSL_add_all_algorithms(); + OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); - #endif - -@@ -1114,6 +1126,10 @@ main(int ac, char **av) - - seed_rng(); - -+ if (FIPS_mode()) { -+ logit("FIPS mode initialized"); -+ } -+ - if (options.user == NULL) - options.user = xstrdup(pw->pw_name); - -@@ -1191,6 +1207,12 @@ main(int ac, char **av) - - timeout_ms = options.connection_timeout * 1000; + if (FIPS_mode()) { + options.protocol &= SSH_PROTO_2; + if (options.protocol == 0) -+ fatal("Protocol 2 disabled by configuration but required in the FIPS mode."); ++ fatal("Protocol 2 disabled by configuration but required in the FIPS mode"); + } + - /* Open a connection to the remote host. */ - if (ssh_connect(host, addrs, &hostaddr, options.port, - options.address_family, options.connection_attempts, -Index: openssh-7.1p2/sshconnect2.c -=================================================================== ---- openssh-7.1p2.orig/sshconnect2.c -+++ openssh-7.1p2/sshconnect2.c -@@ -44,6 +44,8 @@ - #include - #endif + /* Initialize the command to execute on remote host. */ + buffer_init(&command); -+#include + /* + * Save the command to execute on the remote host in a buffer. There + * is no limit on the length of the command, except by the maximum + * packet size. Also sets the tty flag if there is no command. + */ +diff --git a/openssh-6.6p1/sshconnect2.c b/openssh-6.6p1/sshconnect2.c +--- a/openssh-6.6p1/sshconnect2.c ++++ b/openssh-6.6p1/sshconnect2.c +@@ -66,16 +66,18 @@ + #include "match.h" + #include "dispatch.h" + #include "canohost.h" + #include "msg.h" + #include "pathnames.h" + #include "uidswap.h" + #include "hostfile.h" + ++#include "fips.h" + - #include "openbsd-compat/sys-queue.h" - - #include "xmalloc.h" -@@ -170,20 +172,25 @@ ssh_kex2(char *host, struct sockaddr *ho - #ifdef GSSAPI - if (options.gss_keyex) { -- /* Add the GSSAPI mechanisms currently supported on this -- * client to the key exchange algorithm proposal */ -- orig = options.kex_algorithms; -- -- if (options.gss_trust_dns) -- gss_host = (char *)get_canonical_hostname(1); -- else -- gss_host = host; -- -- gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); -- if (gss) { -- debug("Offering GSSAPI proposal: %s", gss); -- xasprintf(&options.kex_algorithms, -- "%s,%s", gss, orig); -+ if (FIPS_mode()) { -+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); -+ options.gss_keyex = 0; -+ } else { -+ /* Add the GSSAPI mechanisms currently supported on this -+ * client to the key exchange algorithm proposal */ -+ orig = options.kex_algorithms; + #include "ssh-gss.h" + #endif + + /* import */ + extern char *client_version_string; + extern char *server_version_string; + extern Options options; +@@ -163,31 +165,41 @@ ssh_kex2(char *host, struct sockaddr *ho + + if (options.ciphers == (char *)-1) { + logit("No valid ciphers for protocol version 2 given, using defaults."); + options.ciphers = NULL; + } + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; ++ } else if (fips_mode()) { ++ /* TODO: use intersection of FIPS ciphers and those requested in ++ * configuration */ ++ myproposal[PROPOSAL_ENC_ALGS_CTOS] = ++ myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_140_2_ENCRYPT; + } + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); + myproposal[PROPOSAL_ENC_ALGS_STOC] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); + if (options.compression) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = + myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib@openssh.com,zlib,none"; + } else { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = + myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com,zlib"; + } + if (options.macs != NULL) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; ++ } else if (fips_mode()) { ++ /* TODO: use intersection of FIPS macs and those requested in ++ * configuration */ ++ myproposal[PROPOSAL_MAC_ALGS_CTOS] = ++ myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_140_2_MAC; + } + if (options.hostkeyalgorithms != NULL) + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + compat_pkalg_proposal(options.hostkeyalgorithms); + else { + /* Prefer algorithms that we already have keys for */ + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + compat_pkalg_proposal( +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -117,16 +117,18 @@ + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" + #include "roaming.h" + #include "ssh-sandbox.h" + #include "version.h" + ++#include "fips.h" + -+ 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(&options.kex_algorithms, -+ "%s,%s", gss, orig); -+ } + #ifdef LIBWRAP + #include + #include + int allow_severity; + int deny_severity; + #endif /* LIBWRAP */ + + #ifndef O_NOCTTY +@@ -1723,16 +1725,20 @@ main(int ac, char **av) + case KEY_ECDSA: + case KEY_ED25519: + sensitive_data.have_ssh2_key = 1; + break; } + debug("private host key: #%d type %d %s", i, keytype, + key_type(key ? key : pubkey)); } - #endif -Index: openssh-7.1p2/sshd.c -=================================================================== ---- openssh-7.1p2.orig/sshd.c -+++ openssh-7.1p2/sshd.c -@@ -66,6 +66,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -77,6 +78,8 @@ - #include - #include - #include -+#include -+#include - #include "openbsd-compat/openssl-compat.h" - #endif - -@@ -1536,6 +1539,18 @@ main(int ac, char **av) - #endif - __progname = ssh_get_progname(av[0]); - -+ SSLeay_add_all_algorithms(); -+ if (access("/etc/system-fips", F_OK) == 0) -+ if (! FIPSCHECK_verify(NULL, NULL)) { -+ openlog(__progname, LOG_PID, LOG_AUTHPRIV); -+ if (FIPS_mode()) { -+ syslog(LOG_CRIT, "FIPS integrity verification test failed."); -+ cleanup_exit(255); -+ } -+ else -+ syslog(LOG_INFO, "FIPS integrity verification test failed."); -+ closelog(); -+ } - /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ - saved_argc = ac; - rexec_argc = ac; -@@ -1692,7 +1707,7 @@ main(int ac, char **av) - else - closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); - --#ifdef WITH_OPENSSL -+#if 0 /* FIPS */ - OpenSSL_add_all_algorithms(); - #endif - -@@ -1888,6 +1903,10 @@ main(int ac, char **av) - sshkey_type(pubkey) : sshkey_ssh_name(pubkey), fp); - free(fp); - } -+ if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) { ++ 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; -@@ -2056,6 +2075,10 @@ main(int ac, char **av) - /* Reinitialize the log (because of the fork above). */ - log_init(__progname, options.log_level, options.log_facility, log_stderr); - -+ if (FIPS_mode()) { -+ logit("FIPS mode initialized"); -+ } -+ - /* Chdir to the root directory so that the current disk can be - unmounted if desired. */ - if (chdir("/") == -1) -@@ -2654,10 +2677,14 @@ do_ssh2_kex(void) - if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) - orig = NULL; - -- if (options.gss_keyex) -- gss = ssh_gssapi_server_mechanisms(); -- else -- gss = NULL; -+ if (options.gss_keyex) { -+ if (FIPS_mode()) { -+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); -+ options.gss_keyex = 0; -+ } else { -+ gss = ssh_gssapi_server_mechanisms(); -+ } -+ } - - if (gss && orig) - xasprintf(&newstr, "%s,%s", gss, orig); -Index: openssh-7.1p2/sshkey.c -=================================================================== ---- openssh-7.1p2.orig/sshkey.c -+++ openssh-7.1p2/sshkey.c -@@ -35,6 +35,7 @@ - #include - #include - #include -+#include - #endif - - #include "crypto_api.h" -@@ -1555,6 +1556,8 @@ rsa_generate_private_key(u_int bits, RSA } - if (!BN_set_word(f4, RSA_F4) || - !RSA_generate_key_ex(private, bits, f4, NULL)) { -+ if (FIPS_mode()) -+ logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__); - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; + 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; + } +@@ -2370,30 +2376,30 @@ do_ssh1_kex(void) + } + if (rsafail) { + int bytes = BN_num_bytes(session_key_int); + u_char *buf = xmalloc(bytes); + struct ssh_digest_ctx *md; + + logit("do_connection: generating a fake encryption key"); + BN_bn2bin(session_key_int, buf); +- if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || ++ if ((md = ssh_digest_start(fips_correct_dgst(SSH_DIGEST_MD5))) == NULL || + ssh_digest_update(md, buf, bytes) < 0 || + ssh_digest_update(md, sensitive_data.ssh1_cookie, + SSH_SESSION_KEY_LENGTH) < 0 || + ssh_digest_final(md, session_key, sizeof(session_key)) < 0) +- fatal("%s: md5 failed", __func__); ++ fatal("%s: hash failed", __func__); + ssh_digest_free(md); +- if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || ++ if ((md = ssh_digest_start(fips_correct_dgst(SSH_DIGEST_MD5))) == NULL || + ssh_digest_update(md, session_key, 16) < 0 || + ssh_digest_update(md, sensitive_data.ssh1_cookie, + SSH_SESSION_KEY_LENGTH) < 0 || + ssh_digest_final(md, session_key + 16, + sizeof(session_key) - 16) < 0) +- fatal("%s: md5 failed", __func__); ++ fatal("%s: hash failed", __func__); + ssh_digest_free(md); + explicit_bzero(buf, bytes); + free(buf); + for (i = 0; i < 16; i++) + session_id[i] = session_key[i] ^ session_key[i + 16]; + } + /* Destroy the private and public keys. No longer. */ + destroy_sensitive_data(); +@@ -2441,25 +2447,31 @@ sshd_hostkey_sign(Key *privkey, Key *pub + static void + do_ssh2_kex(void) + { + Kex *kex; + + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; ++ } else if (fips_mode()) { ++ myproposal[PROPOSAL_ENC_ALGS_CTOS] = ++ myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_140_2_ENCRYPT; + } + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); + myproposal[PROPOSAL_ENC_ALGS_STOC] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); + + if (options.macs != NULL) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; ++ } else if (fips_mode()) { ++ myproposal[PROPOSAL_MAC_ALGS_CTOS] = ++ myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_140_2_MAC; + } + 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"; } diff --git a/openssh-6.6p1-gssapi_key_exchange.patch b/openssh-6.6p1-gssapi_key_exchange.patch index 418917a..dc2fb22 100644 --- a/openssh-6.6p1-gssapi_key_exchange.patch +++ b/openssh-6.6p1-gssapi_key_exchange.patch @@ -1,38 +1,260 @@ -Index: openssh-7.1p2/auth2.c -=================================================================== ---- openssh-7.1p2.orig/auth2.c -+++ openssh-7.1p2/auth2.c -@@ -70,6 +70,7 @@ extern Authmethod method_passwd; - extern Authmethod method_kbdint; - extern Authmethod method_hostbased; - #ifdef GSSAPI -+extern Authmethod method_gsskeyex; - extern Authmethod method_gssapi; - extern Authmethod method_gssapi_old; - #endif -@@ -78,6 +79,7 @@ Authmethod *authmethods[] = { - &method_none, - &method_pubkey, - #ifdef GSSAPI -+ &method_gsskeyex, - &method_gssapi, - &method_gssapi_old, - #endif -Index: openssh-7.1p2/auth2-gss.c -=================================================================== ---- openssh-7.1p2.orig/auth2-gss.c -+++ openssh-7.1p2/auth2-gss.c -@@ -31,6 +31,7 @@ - #include +# HG changeset patch +# Parent 0b2761bdc8c2071a11ca24387c3f58be2fdbaa5e + +diff --git a/openssh-6.6p1/ChangeLog.gssapi b/openssh-6.6p1/ChangeLog.gssapi +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/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-6.6p1/Makefile.in b/openssh-6.6p1/Makefile.in +--- a/openssh-6.6p1/Makefile.in ++++ b/openssh-6.6p1/Makefile.in +@@ -67,16 +67,17 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o + canohost.o channels.o cipher.o cipher-aes.o \ + cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \ + compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \ + log.o match.o md-sha256.o moduli.o nchan.o packet.o \ + readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \ + atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ + monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ + kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ ++ kexgssc.o \ + msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ + ssh-pkcs11.o krl.o smult_curve25519_ref.o \ + kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ + ssh-ed25519.o digest-openssl.o hmac.o \ + sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ + fips.o \ + auditstub.o - #include -+#include +@@ -86,17 +87,17 @@ SSHOBJS= ssh.o readconf.o clientloop.o s - #include "xmalloc.h" - #include "key.h" -@@ -53,6 +54,40 @@ static int input_gssapi_mic(int type, u_ - static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); - static int input_gssapi_errtok(int, u_int32_t, void *); + 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 kexdhs.o kexgexs.o kexecdhs.o \ ++ monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o kexgsss.o \ + kexc25519s.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 \ + roaming_common.o roaming_serv.o \ + sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ + sandbox-seccomp-filter.o sandbox-capsicum.o + +diff --git a/openssh-6.6p1/auth-krb5.c b/openssh-6.6p1/auth-krb5.c +--- a/openssh-6.6p1/auth-krb5.c ++++ b/openssh-6.6p1/auth-krb5.c +@@ -177,18 +177,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(); +@@ -238,35 +243,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-6.6p1/auth2-gss.c b/openssh-6.6p1/auth2-gss.c +--- a/openssh-6.6p1/auth2-gss.c ++++ b/openssh-6.6p1/auth2-gss.c +@@ -1,12 +1,12 @@ + /* $OpenBSD: auth2-gss.c,v 1.21 2014/02/26 20:28:44 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 +@@ -47,16 +47,50 @@ + + extern ServerOptions options; + + static void input_gssapi_token(int type, u_int32_t plen, void *ctxt); + static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); + static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); + static void input_gssapi_errtok(int, u_int32_t, void *); +/* + * The 'gssapi_keyex' userauth mechanism. @@ -71,7 +293,17 @@ Index: openssh-7.1p2/auth2-gss.c /* * We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like) -@@ -238,7 +273,8 @@ input_gssapi_exchange_complete(int type, + */ + static int + userauth_gssapi(Authctxt *authctxt) + { + gss_OID_desc goid = {0, NULL}; +@@ -239,17 +273,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(); @@ -81,7 +313,17 @@ Index: openssh-7.1p2/auth2-gss.c authctxt->postponed = 0; dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); -@@ -274,7 +310,8 @@ input_gssapi_mic(int type, u_int32_t ple + 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); + } +@@ -274,31 +309,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)))) @@ -91,8 +333,15 @@ Index: openssh-7.1p2/auth2-gss.c else logit("GSSAPI MIC check failed"); -@@ -290,6 +327,12 @@ input_gssapi_mic(int type, u_int32_t ple - return 0; + 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); } +Authmethod method_gsskeyex = { @@ -104,13 +353,52 @@ Index: openssh-7.1p2/auth2-gss.c Authmethod method_gssapi = { "gssapi-with-mic", userauth_gssapi, -Index: openssh-7.1p2/clientloop.c -=================================================================== ---- openssh-7.1p2.orig/clientloop.c -+++ openssh-7.1p2/clientloop.c -@@ -115,6 +115,10 @@ - #include "ssherr.h" - #include "hostfile.h" + &options.gss_authentication + }; + + Authmethod method_gssapi_old = { + "gssapi", +diff --git a/openssh-6.6p1/auth2.c b/openssh-6.6p1/auth2.c +--- a/openssh-6.6p1/auth2.c ++++ b/openssh-6.6p1/auth2.c +@@ -64,24 +64,26 @@ 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; + extern Authmethod method_gssapi_old; + #endif + + Authmethod *authmethods[] = { + &method_none, + &method_pubkey, + #ifdef GSSAPI ++ &method_gsskeyex, + &method_gssapi, + &method_gssapi_old, + #endif + &method_passwd, + &method_kbdint, + &method_hostbased, + NULL + }; +diff --git a/openssh-6.6p1/clientloop.c b/openssh-6.6p1/clientloop.c +--- a/openssh-6.6p1/clientloop.c ++++ b/openssh-6.6p1/clientloop.c +@@ -106,16 +106,20 @@ + #include "authfd.h" + #include "atomicio.h" + #include "sshpty.h" + #include "misc.h" + #include "match.h" + #include "msg.h" + #include "roaming.h" +#ifdef GSSAPI +#include "ssh-gss.h" @@ -119,7 +407,17 @@ Index: openssh-7.1p2/clientloop.c /* import options */ extern Options options; -@@ -1610,6 +1614,15 @@ client_loop(int have_pty, int escape_cha + /* 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; +@@ -1603,16 +1607,25 @@ client_loop(int have_pty, int escape_cha + &max_fd2, &nalloc, rekeying); + + if (quit_pending) + break; + /* Do channel operations unless rekeying in progress. */ if (!rekeying) { channel_after_select(readset, writeset); @@ -134,12 +432,21 @@ Index: openssh-7.1p2/clientloop.c + if (need_rekeying || packet_need_rekeying()) { debug("need rekeying"); - active_state->kex->done = 0; -Index: openssh-7.1p2/configure.ac -=================================================================== ---- openssh-7.1p2.orig/configure.ac -+++ openssh-7.1p2/configure.ac -@@ -625,6 +625,30 @@ main() { if (NSVersionOfRunTimeLibrary(" + xxx_kex->done = 0; + kex_send_kexinit(xxx_kex); + need_rekeying = 0; + } + } + +diff --git a/openssh-6.6p1/configure.ac b/openssh-6.6p1/configure.ac +--- a/openssh-6.6p1/configure.ac ++++ b/openssh-6.6p1/configure.ac +@@ -579,16 +579,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]) @@ -170,11 +477,34 @@ Index: openssh-7.1p2/configure.ac m4_pattern_allow([AU_IPv]) AC_CHECK_DECL([AU_IPv4], [], AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) -Index: openssh-7.1p2/gss-genr.c -=================================================================== ---- openssh-7.1p2.orig/gss-genr.c -+++ openssh-7.1p2/gss-genr.c -@@ -41,12 +41,167 @@ + [#include ] + AC_DEFINE([LASTLOG_WRITE_PUTUTXLINE], [1], + [Define if pututxline updates lastlog too]) + ) + AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV], +diff --git a/openssh-6.6p1/gss-genr.c b/openssh-6.6p1/gss-genr.c +--- a/openssh-6.6p1/gss-genr.c ++++ b/openssh-6.6p1/gss-genr.c +@@ -1,12 +1,12 @@ + /* $OpenBSD: gss-genr.c,v 1.22 2013/11/08 00:39:15 djm Exp $ */ + + /* +- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 +@@ -34,22 +34,177 @@ + #include + #include + #include + + #include "xmalloc.h" #include "buffer.h" #include "log.h" #include "ssh2.h" @@ -342,7 +672,17 @@ Index: openssh-7.1p2/gss-genr.c /* 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) -@@ -199,7 +354,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de + { + return (ctx != NULL && ctx->oid != GSS_C_NO_OID && + ctx->oid->length == len && + memcmp(ctx->oid->elements, data, len) == 0); + } +@@ -192,17 +347,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, @@ -351,7 +691,17 @@ Index: openssh-7.1p2/gss-genr.c GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 0, NULL, recv_tok, NULL, send_tok, flags, NULL); -@@ -229,8 +384,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con + if (GSS_ERROR(ctx->major)) + ssh_gssapi_error(ctx); + + return (ctx->major); + } +@@ -222,60 +377,173 @@ 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 @@ -394,7 +744,7 @@ Index: openssh-7.1p2/gss-genr.c if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, GSS_C_QOP_DEFAULT, buffer, hash))) ssh_gssapi_error(ctx); -@@ -238,6 +427,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer + return (ctx->major); } @@ -414,7 +764,13 @@ Index: openssh-7.1p2/gss-genr.c void ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, const char *context) -@@ -251,11 +453,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha + { + 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 @@ -432,7 +788,9 @@ Index: openssh-7.1p2/gss-genr.c /* RFC 4462 says we MUST NOT do SPNEGO */ if (oid->length == spnego_oid.length && -@@ -265,6 +472,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx + (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); @@ -443,7 +801,9 @@ Index: openssh-7.1p2/gss-genr.c if (!GSS_ERROR(major)) { major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL); -@@ -274,10 +485,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx + gss_release_buffer(&minor, &token); + if ((*ctx)->context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&minor, &(*ctx)->context, GSS_C_NO_BUFFER); } @@ -463,6 +823,7 @@ Index: openssh-7.1p2/gss-genr.c + static OM_uint32 last_call = 0; + OM_uint32 lifetime, now, major, minor; + int equal; ++ gss_cred_usage_t usage = GSS_C_INITIATE; + + now = time(NULL); + @@ -511,25 +872,193 @@ Index: openssh-7.1p2/gss-genr.c +} + #endif /* GSSAPI */ -Index: openssh-7.1p2/gss-serv.c -=================================================================== ---- openssh-7.1p2.orig/gss-serv.c -+++ openssh-7.1p2/gss-serv.c -@@ -45,17 +45,19 @@ +diff --git a/openssh-6.6p1/gss-serv-krb5.c b/openssh-6.6p1/gss-serv-krb5.c +--- a/openssh-6.6p1/gss-serv-krb5.c ++++ b/openssh-6.6p1/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 +@@ -117,16 +117,17 @@ 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; + 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; +@@ -175,37 +176,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-6.6p1/gss-serv.c b/openssh-6.6p1/gss-serv.c +--- a/openssh-6.6p1/gss-serv.c ++++ b/openssh-6.6p1/gss-serv.c +@@ -1,12 +1,12 @@ + /* $OpenBSD: gss-serv.c,v 1.26 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 +@@ -40,25 +40,30 @@ + #include "buffer.h" + #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 "servconf.h" +#include "uidswap.h" #include "ssh-gss.h" +#include "monitor_wrap.h" - - extern ServerOptions options; ++ ++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}, 0, 0}; ++ 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}; @@ -537,7 +1066,71 @@ Index: openssh-7.1p2/gss-serv.c #ifdef KRB5 extern ssh_gssapi_mech gssapi_kerberos_mech; -@@ -142,6 +144,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss + #endif + + ssh_gssapi_mech* supported_mechs[]= { + #ifdef KRB5 + &gssapi_kerberos_mech, +@@ -95,59 +100,91 @@ ssh_gssapi_test_oid_supported(OM_uint32 + /* Privileged (called from ssh_gssapi_server_ctx) */ + static OM_uint32 + ssh_gssapi_acquire_cred(Gssctxt *ctx) + { + OM_uint32 status; + char lname[MAXHOSTNAMELEN]; + gss_OID_set oidset; + +- gss_create_empty_oid_set(&status, &oidset); +- gss_add_oid_set_member(&status, ctx->oid, &oidset); ++ if (options.gss_strict_acceptor) { ++ gss_create_empty_oid_set(&status, &oidset); ++ gss_add_oid_set_member(&status, ctx->oid, &oidset); + +- if (gethostname(lname, MAXHOSTNAMELEN)) { +- gss_release_oid_set(&status, &oidset); +- return (-1); +- } ++ if (gethostname(lname, MAXHOSTNAMELEN)) { ++ gss_release_oid_set(&status, &oidset); ++ return (-1); ++ } + +- if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { ++ if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { ++ gss_release_oid_set(&status, &oidset); ++ return (ctx->major); ++ } ++ ++ if ((ctx->major = gss_acquire_cred(&ctx->minor, ++ ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, ++ NULL, NULL))) ++ ssh_gssapi_error(ctx); ++ + gss_release_oid_set(&status, &oidset); + return (ctx->major); ++ } else { ++ ctx->name = GSS_C_NO_NAME; ++ ctx->creds = GSS_C_NO_CREDENTIAL; + } +- +- if ((ctx->major = gss_acquire_cred(&ctx->minor, +- ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) +- ssh_gssapi_error(ctx); +- +- gss_release_oid_set(&status, &oidset); +- return (ctx->major); ++ return GSS_S_COMPLETE; + } + + /* Privileged */ + OM_uint32 + ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) + { + 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 */ @@ -567,7 +1160,9 @@ Index: openssh-7.1p2/gss-serv.c void ssh_gssapi_supported_oids(gss_OID_set *oidset) { -@@ -151,7 +176,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o + int i = 0; + OM_uint32 min_status; + int present; gss_OID_set supported; gss_create_empty_oid_set(&min_status, oidset); @@ -578,14 +1173,25 @@ Index: openssh-7.1p2/gss-serv.c while (supported_mechs[i]->name != NULL) { if (GSS_ERROR(gss_test_oid_set_member(&min_status, -@@ -277,8 +304,48 @@ OM_uint32 + &supported_mechs[i]->oid, supported, &present))) + present = 0; + if (present) + gss_add_oid_set_member(&min_status, + &supported_mechs[i]->oid, oidset); +@@ -263,32 +300,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, @@ -600,8 +1206,7 @@ Index: openssh-7.1p2/gss-serv.c + ssh_gssapi_error(ctx); + return (ctx->major); + } - -- gss_buffer_desc ename; ++ + ctx->major = gss_compare_name(&ctx->minor, client->name, + new_name, &equal); + @@ -628,7 +1233,14 @@ Index: openssh-7.1p2/gss-serv.c client->mech = NULL; -@@ -293,6 +360,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + 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; @@ -642,7 +1254,17 @@ Index: openssh-7.1p2/gss-serv.c if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); -@@ -310,6 +384,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + return (ctx->major); + } + + if ((ctx->major = gss_export_name(&ctx->minor, ctx->client, + &ename))) { +@@ -296,16 +380,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); } @@ -651,33 +1273,17 @@ Index: openssh-7.1p2/gss-serv.c /* We can't copy this structure, so we just move the pointer to it */ client->creds = ctx->client_creds; ctx->client_creds = GSS_C_NO_CREDENTIAL; -@@ -320,11 +396,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g - void - ssh_gssapi_cleanup_creds(void) - { -- if (gssapi_client.store.filename != NULL) { -- /* Unlink probably isn't sufficient */ -- debug("removing gssapi cred file\"%s\"", -- gssapi_client.store.filename); -- unlink(gssapi_client.store.filename); -+ krb5_ccache ccache = NULL; -+ krb5_error_code problem; -+ -+ if (gssapi_client.store.data != NULL) { -+ if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) { -+ debug("%s: krb5_cc_resolve(): %.100s", __func__, -+ krb5_get_err_text(gssapi_client.store.data, problem)); -+ } else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) { -+ debug("%s: krb5_cc_resolve(): %.100s", __func__, -+ krb5_get_err_text(gssapi_client.store.data, problem)); -+ } else { -+ krb5_free_context(gssapi_client.store.data); -+ gssapi_client.store.data = NULL; -+ } - } + return (ctx->major); } -@@ -357,7 +442,7 @@ ssh_gssapi_do_child(char ***envp, u_int + /* As user - called on fatal/exit */ + void +@@ -343,45 +429,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 @@ -686,7 +1292,9 @@ Index: openssh-7.1p2/gss-serv.c { OM_uint32 lmin; -@@ -367,9 +452,11 @@ ssh_gssapi_userok(char *user) + 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) @@ -696,15 +1304,21 @@ Index: openssh-7.1p2/gss-serv.c + gssapi_client.store.owner = pw; return 1; - else { -+ } else { ++ } else { /* Destroy delegated credentials if userok fails */ gss_release_buffer(&lmin, &gssapi_client.displayname); gss_release_buffer(&lmin, &gssapi_client.exportedname); -@@ -383,14 +470,90 @@ ssh_gssapi_userok(char *user) + 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 */ + /* 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 @@ -797,142 +1411,15 @@ Index: openssh-7.1p2/gss-serv.c } #endif -Index: openssh-7.1p2/gss-serv-krb5.c -=================================================================== ---- openssh-7.1p2.orig/gss-serv-krb5.c -+++ openssh-7.1p2/gss-serv-krb5.c -@@ -121,7 +121,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - krb5_error_code problem; - krb5_principal princ; - OM_uint32 maj_status, min_status; -- int len; -+ const char *new_ccname, *new_cctype; - const char *errmsg; - - if (client->creds == NULL) { -@@ -181,11 +181,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - return; - } - -- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); -+ new_cctype = krb5_cc_get_type(krb_context, ccache); -+ new_ccname = krb5_cc_get_name(krb_context, ccache); -+ - client->store.envvar = "KRB5CCNAME"; -- len = strlen(client->store.filename) + 6; -- client->store.envval = xmalloc(len); -- snprintf(client->store.envval, len, "FILE:%s", client->store.filename); -+#ifdef USE_CCAPI -+ xasprintf(&client->store.envval, "API:%s", new_ccname); -+ client->store.filename = NULL; -+#else -+ if (new_ccname[0] == ':') -+ new_ccname++; -+ xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname); -+ if (strcmp(new_cctype, "DIR") == 0) { -+ char *p; -+ p = strrchr(client->store.envval, '/'); -+ if (p) -+ *p = '\0'; -+ } -+ if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0)) -+ client->store.filename = xstrdup(new_ccname); -+#endif - - #ifdef USE_PAM - if (options.use_pam) -@@ -194,9 +209,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - - krb5_cc_close(krb_context, ccache); - -+ client->store.data = krb_context; -+ - return; - } - -+int -+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, -+ ssh_gssapi_client *client) -+{ -+ krb5_ccache ccache = NULL; -+ krb5_principal principal = NULL; -+ char *name = NULL; -+ krb5_error_code problem; -+ OM_uint32 maj_status, min_status; -+ -+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { -+ logit("krb5_cc_resolve(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ return 0; -+ } -+ -+ /* Find out who the principal in this cache is */ -+ if ((problem = krb5_cc_get_principal(krb_context, ccache, -+ &principal))) { -+ logit("krb5_cc_get_principal(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ if ((problem = krb5_unparse_name(krb_context, principal, &name))) { -+ logit("krb5_unparse_name(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ -+ if (strcmp(name,client->exportedname.value)!=0) { -+ debug("Name in local credentials cache differs. Not storing"); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ krb5_free_unparsed_name(krb_context, name); -+ return 0; -+ } -+ krb5_free_unparsed_name(krb_context, name); -+ -+ /* Name matches, so lets get on with it! */ -+ -+ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { -+ logit("krb5_cc_initialize(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ krb5_free_principal(krb_context, principal); -+ -+ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, -+ ccache))) { -+ logit("gss_krb5_copy_ccache() failed. Sorry!"); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ return 1; -+} -+ - ssh_gssapi_mech gssapi_kerberos_mech = { - "toWM5Slw5Ew8Mqkay+al2g==", - "Kerberos", -@@ -204,7 +286,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { - NULL, - &ssh_gssapi_krb5_userok, - NULL, -- &ssh_gssapi_krb5_storecreds -+ &ssh_gssapi_krb5_storecreds, -+ &ssh_gssapi_krb5_updatecreds - }; - - #endif /* KRB5 */ -Index: openssh-7.1p2/kex.c -=================================================================== ---- openssh-7.1p2.orig/kex.c -+++ openssh-7.1p2/kex.c -@@ -56,6 +56,10 @@ +diff --git a/openssh-6.6p1/kex.c b/openssh-6.6p1/kex.c +--- a/openssh-6.6p1/kex.c ++++ b/openssh-6.6p1/kex.c +@@ -47,16 +47,20 @@ + #include "mac.h" + #include "match.h" + #include "dispatch.h" + #include "monitor.h" + #include "roaming.h" #include "digest.h" #include "audit.h" @@ -943,36 +1430,106 @@ Index: openssh-7.1p2/kex.c #if OPENSSL_VERSION_NUMBER >= 0x00907000L # if defined(HAVE_EVP_SHA256) # define evp_ssh_sha256 EVP_sha256 -@@ -96,6 +100,11 @@ static const struct kexalg kexalgs[] = { - #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) + # else + extern const EVP_MD *evp_ssh_sha256(void); + # endif + #endif + +@@ -86,16 +90,21 @@ static const struct kexalg kexalgs[] = { + { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, + SSH_DIGEST_SHA512 }, + # endif + #endif + { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, + #ifdef HAVE_EVP_SHA256 { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, - #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ + #endif +#ifdef GSSAPI -+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, +#endif { NULL, -1, -1, -1}, }; -@@ -129,6 +138,12 @@ kex_alg_by_name(const char *name) - for (k = kexalgs; k->name != NULL; k++) { - if (strcmp(k->name, name) == 0) - return k; + char * + kex_alg_list(char sep) + { + char *ret = NULL; + size_t nlen, rlen = 0; +diff --git a/openssh-6.6p1/kex.h b/openssh-6.6p1/kex.h +--- a/openssh-6.6p1/kex.h ++++ b/openssh-6.6p1/kex.h +@@ -71,16 +71,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 + + typedef struct Kex Kex; + typedef struct Mac Mac; + typedef struct Comp Comp; +@@ -130,16 +133,22 @@ struct Kex { + int kex_type; + int roaming; + Buffer my; + Buffer peer; + sig_atomic_t done; + int flags; + int hash_alg; + int ec_nid; +#ifdef GSSAPI -+ if (strncmp(name, "gss-", 4) == 0) { -+ if (strncmp(k->name, name, strlen(k->name)) == 0) -+ return k; -+ } ++ int gss_deleg_creds; ++ int gss_trust_dns; ++ char *gss_host; ++ char *gss_client; +#endif - } - return NULL; - } -Index: openssh-7.1p2/kexgssc.c -=================================================================== + char *client_version_string; + char *server_version_string; + int (*verify_host_key)(Key *); + Key *(*load_host_public_key)(int); + Key *(*load_host_private_key)(int); + int (*host_key_index)(Key *); + void (*sign)(Key *, Key *, u_char **, u_int *, u_char *, u_int); + void (*kex[KEX_MAX])(Kex *); +@@ -163,16 +172,21 @@ void kexdh_server(Kex *); + void kexgex_client(Kex *); + void kexgex_server(Kex *); + void kexecdh_client(Kex *); + void kexecdh_server(Kex *); + void kexc25519_client(Kex *); + void kexc25519_server(Kex *); + + void newkeys_destroy(Newkeys *newkeys); ++ ++#ifdef GSSAPI ++void kexgss_client(Kex *); ++void kexgss_server(Kex *); ++#endif + + void + kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, + BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); + void + kexgex_hash(int, char *, char *, char *, int, char *, + int, u_char *, int, int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, + BIGNUM *, BIGNUM *, u_char **, u_int *); +diff --git a/openssh-6.6p1/kexgssc.c b/openssh-6.6p1/kexgssc.c +new file mode 100644 --- /dev/null -+++ openssh-7.1p2/kexgssc.c -@@ -0,0 +1,338 @@ ++++ b/openssh-6.6p1/kexgssc.c +@@ -0,0 +1,334 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1017,23 +1574,22 @@ Index: openssh-7.1p2/kexgssc.c +#include "log.h" +#include "packet.h" +#include "dh.h" -+#include "digest.h" + +#include "ssh-gss.h" + -+int -+kexgss_client(struct ssh *ssh) { ++void ++kexgss_client(Kex *kex) { + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; + Gssctxt *ctxt; + OM_uint32 maj_status, min_status, ret_flags; -+ u_int klen, kout, slen = 0, strlen; ++ u_int klen, kout, slen = 0, hashlen, strlen; + DH *dh; + BIGNUM *dh_server_pub = NULL; + BIGNUM *shared_secret = NULL; + BIGNUM *p = NULL; + BIGNUM *g = NULL; -+ u_char *kbuf; ++ u_char *kbuf, *hash; + u_char *serverhostkey = NULL; + u_char *empty = ""; + char *msg; @@ -1041,23 +1597,21 @@ Index: openssh-7.1p2/kexgssc.c + int type = 0; + int first = 1; + int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; + + /* Initialise our GSSAPI world */ + ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, ssh->kex->name, ssh->kex->kex_type) ++ 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, ssh->kex->gss_host)) ++ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) + fatal("Couldn't import hostname"); + -+ if (ssh->kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, ssh->kex->gss_client)) ++ if (kex->gss_client && ++ ssh_gssapi_client_identity(ctxt, kex->gss_client)) + fatal("Couldn't acquire client credentials"); + -+ switch (ssh->kex->kex_type) { ++ switch (kex->kex_type) { + case KEX_GSS_GRP1_SHA1: + dh = dh_new_group1(); + break; @@ -1066,7 +1620,7 @@ Index: openssh-7.1p2/kexgssc.c + break; + case KEX_GSS_GEX_SHA1: + debug("Doing group exchange\n"); -+ nbits = dh_estimate(ssh->kex->we_need * 8); ++ nbits = dh_estimate(kex->we_need * 8); + packet_start(SSH2_MSG_KEXGSS_GROUPREQ); + packet_put_int(min); + packet_put_int(nbits); @@ -1091,11 +1645,11 @@ Index: openssh-7.1p2/kexgssc.c + dh = dh_new_group(g, p); + break; + default: -+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + + /* Step 1 - e is dh->pub_key */ -+ dh_gen_key(dh, ssh->kex->we_need * 8); ++ dh_gen_key(dh, kex->we_need * 8); + + /* This is f, we initialise it now to make life easier */ + dh_server_pub = BN_new(); @@ -1108,7 +1662,7 @@ Index: openssh-7.1p2/kexgssc.c + debug("Calling gss_init_sec_context"); + + maj_status = ssh_gssapi_init_ctx(ctxt, -+ ssh->kex->gss_deleg_creds, token_ptr, &send_tok, ++ kex->gss_deleg_creds, token_ptr, &send_tok, + &ret_flags); + + if (GSS_ERROR(maj_status)) { @@ -1228,7 +1782,7 @@ Index: openssh-7.1p2/kexgssc.c + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); -+ if ((int)kout < 0) ++ if (kout < 0) + fatal("DH_compute_key: failed"); + + shared_secret = BN_new(); @@ -1241,39 +1795,38 @@ Index: openssh-7.1p2/kexgssc.c + memset(kbuf, 0, klen); + free(kbuf); + -+ hashlen = sizeof(hash); -+ switch (ssh->kex->kex_type) { ++ switch (kex->kex_type) { + case KEX_GSS_GRP1_SHA1: + case KEX_GSS_GRP14_SHA1: -+ kex_dh_hash( ssh->kex->client_version_string, -+ ssh->kex->server_version_string, -+ buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), -+ buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), ++ kex_dh_hash( kex->client_version_string, ++ kex->server_version_string, ++ buffer_ptr(&kex->my), buffer_len(&kex->my), ++ buffer_ptr(&kex->peer), buffer_len(&kex->peer), + (serverhostkey ? serverhostkey : empty), slen, + dh->pub_key, /* e */ + dh_server_pub, /* f */ + shared_secret, /* K */ -+ hash, &hashlen ++ &hash, &hashlen + ); + break; + case KEX_GSS_GEX_SHA1: + kexgex_hash( -+ ssh->kex->hash_alg, -+ ssh->kex->client_version_string, -+ ssh->kex->server_version_string, -+ buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), -+ buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), ++ kex->hash_alg, ++ kex->client_version_string, ++ kex->server_version_string, ++ buffer_ptr(&kex->my), buffer_len(&kex->my), ++ buffer_ptr(&kex->peer), buffer_len(&kex->peer), + (serverhostkey ? serverhostkey : empty), slen, + min, nbits, max, + dh->p, dh->g, + dh->pub_key, + dh_server_pub, + shared_secret, -+ hash, &hashlen ++ &hash, &hashlen + ); + break; + default: -+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + + gssbuf.value = hash; @@ -1291,13 +1844,13 @@ Index: openssh-7.1p2/kexgssc.c + BN_clear_free(dh_server_pub); + + /* save session id */ -+ if (ssh->kex->session_id == NULL) { -+ ssh->kex->session_id_len = hashlen; -+ ssh->kex->session_id = xmalloc(ssh->kex->session_id_len); -+ memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len); ++ if (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 (ssh->kex->gss_deleg_creds) ++ if (kex->gss_deleg_creds) + ssh_gssapi_credentials_updated(ctxt); + + if (gss_kex_context == NULL) @@ -1305,17 +1858,17 @@ Index: openssh-7.1p2/kexgssc.c + else + ssh_gssapi_delete_ctx(&ctxt); + -+ kex_derive_keys_bn(ssh, hash, hashlen, shared_secret); ++ kex_derive_keys_bn(kex, hash, hashlen, shared_secret); + BN_clear_free(shared_secret); -+ return kex_send_newkeys(ssh); ++ kex_finish(kex); +} + +#endif /* GSSAPI */ -Index: openssh-7.1p2/kexgsss.c -=================================================================== +diff --git a/openssh-6.6p1/kexgsss.c b/openssh-6.6p1/kexgsss.c +new file mode 100644 --- /dev/null -+++ openssh-7.1p2/kexgsss.c -@@ -0,0 +1,295 @@ ++++ b/openssh-6.6p1/kexgsss.c +@@ -0,0 +1,288 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1360,15 +1913,12 @@ Index: openssh-7.1p2/kexgsss.c +#include "dh.h" +#include "ssh-gss.h" +#include "monitor_wrap.h" -+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ +#include "servconf.h" -+#include "ssh-gss.h" -+#include "digest.h" + +extern ServerOptions options; + -+int -+kexgss_server(struct ssh *ssh) ++void ++kexgss_server(Kex *kex) +{ + OM_uint32 maj_status, min_status; + @@ -1383,8 +1933,8 @@ Index: openssh-7.1p2/kexgsss.c + gss_buffer_desc gssbuf, recv_tok, msg_tok; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + Gssctxt *ctxt = NULL; -+ u_int slen, klen, kout; -+ u_char *kbuf; ++ u_int slen, klen, kout, hashlen; ++ u_char *kbuf, *hash; + DH *dh; + int min = -1, max = -1, nbits = -1; + BIGNUM *shared_secret = NULL; @@ -1392,8 +1942,6 @@ Index: openssh-7.1p2/kexgsss.c + int type = 0; + gss_OID oid; + char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; + + /* Initialise GSSAPI */ + @@ -1405,8 +1953,8 @@ Index: openssh-7.1p2/kexgsss.c + if ((mechs = ssh_gssapi_server_mechanisms())) + free(mechs); + -+ debug2("%s: Identifying %s", __func__, ssh->kex->name); -+ oid = ssh_gssapi_id_kex(NULL, ssh->kex->name, ssh->kex->kex_type); ++ 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"); + @@ -1415,7 +1963,7 @@ Index: openssh-7.1p2/kexgsss.c + if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) + fatal("Unable to acquire credentials for the server"); + -+ switch (ssh->kex->kex_type) { ++ switch (kex->kex_type) { + case KEX_GSS_GRP1_SHA1: + dh = dh_new_group1(); + break; @@ -1446,10 +1994,10 @@ Index: openssh-7.1p2/kexgsss.c + packet_write_wait(); + break; + default: -+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + -+ dh_gen_key(dh, ssh->kex->we_need * 8); ++ dh_gen_key(dh, kex->we_need * 8); + + do { + debug("Wait SSH2_MSG_GSSAPI_INIT"); @@ -1519,7 +2067,7 @@ Index: openssh-7.1p2/kexgsss.c + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); -+ if ((int)kout < 0) ++ if (kout < 0) + fatal("DH_compute_key: failed"); + + shared_secret = BN_new(); @@ -1532,44 +2080,43 @@ Index: openssh-7.1p2/kexgsss.c + memset(kbuf, 0, klen); + free(kbuf); + -+ hashlen = sizeof(hash); -+ switch (ssh->kex->kex_type) { ++ switch (kex->kex_type) { + case KEX_GSS_GRP1_SHA1: + case KEX_GSS_GRP14_SHA1: + kex_dh_hash( -+ ssh->kex->client_version_string, ssh->kex->server_version_string, -+ buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), -+ buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), ++ kex->client_version_string, kex->server_version_string, ++ buffer_ptr(&kex->peer), buffer_len(&kex->peer), ++ buffer_ptr(&kex->my), buffer_len(&kex->my), + NULL, 0, /* Change this if we start sending host keys */ + dh_client_pub, dh->pub_key, shared_secret, -+ hash, &hashlen ++ &hash, &hashlen + ); + break; + case KEX_GSS_GEX_SHA1: + kexgex_hash( -+ ssh->kex->hash_alg, -+ ssh->kex->client_version_string, ssh->kex->server_version_string, -+ buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), -+ buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), ++ kex->hash_alg, ++ kex->client_version_string, kex->server_version_string, ++ buffer_ptr(&kex->peer), buffer_len(&kex->peer), ++ buffer_ptr(&kex->my), buffer_len(&kex->my), + NULL, 0, + min, nbits, max, + dh->p, dh->g, + dh_client_pub, + dh->pub_key, + shared_secret, -+ hash, &hashlen ++ &hash, &hashlen + ); + break; + default: -+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + + BN_clear_free(dh_client_pub); + -+ if (ssh->kex->session_id == NULL) { -+ ssh->kex->session_id_len = hashlen; -+ ssh->kex->session_id = xmalloc(ssh->kex->session_id_len); -+ memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len); ++ 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; @@ -1600,83 +2147,68 @@ Index: openssh-7.1p2/kexgsss.c + + DH_free(dh); + -+ kex_derive_keys_bn(ssh, hash, hashlen, shared_secret); ++ kex_derive_keys_bn(kex, hash, hashlen, shared_secret); + BN_clear_free(shared_secret); -+ kex_send_newkeys(ssh); ++ kex_finish(kex); + + /* If this was a rekey, then save out any delegated credentials we + * just exchanged. */ + if (options.gss_store_rekey) + ssh_gssapi_rekey_creds(); -+ return 0; +} +#endif /* GSSAPI */ -Index: openssh-7.1p2/kex.h -=================================================================== ---- openssh-7.1p2.orig/kex.h -+++ openssh-7.1p2/kex.h -@@ -93,6 +93,11 @@ enum kex_exchange { - KEX_DH_GEX_SHA256, - KEX_ECDH_SHA2, - KEX_C25519_SHA256, -+#ifdef GSSAPI -+ KEX_GSS_GRP1_SHA1, -+ KEX_GSS_GRP14_SHA1, -+ KEX_GSS_GEX_SHA1, -+#endif - KEX_MAX +diff --git a/openssh-6.6p1/key.c b/openssh-6.6p1/key.c +--- a/openssh-6.6p1/key.c ++++ b/openssh-6.6p1/key.c +@@ -1053,16 +1053,18 @@ static const struct keytype keytypes[] = + # endif + #endif /* OPENSSL_HAS_ECC */ + { "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00", + KEY_RSA_CERT_V00, 0, 1 }, + { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00", + KEY_DSA_CERT_V00, 0, 1 }, + { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", + KEY_ED25519_CERT, 0, 1 }, ++ { "null", "null", ++ KEY_NULL, 0, 0 }, + { NULL, NULL, -1, -1, 0 } }; -@@ -139,6 +144,12 @@ struct kex { - u_int flags; - int hash_alg; - int ec_nid; -+#ifdef GSSAPI -+ int gss_deleg_creds; -+ int gss_trust_dns; -+ char *gss_host; -+ char *gss_client; -+#endif - char *client_version_string; - char *server_version_string; - char *failed_choice; -@@ -186,6 +197,10 @@ int kexecdh_client(struct ssh *); - int kexecdh_server(struct ssh *); - int kexc25519_client(struct ssh *); - int kexc25519_server(struct ssh *); -+#ifdef GSSAPI -+int kexgss_client(struct ssh *); -+int kexgss_server(struct ssh *); -+#endif + const char * + key_type(const Key *k) + { + const struct keytype *kt; - void newkeys_destroy(struct newkeys *newkeys); +diff --git a/openssh-6.6p1/key.h b/openssh-6.6p1/key.h +--- a/openssh-6.6p1/key.h ++++ b/openssh-6.6p1/key.h +@@ -41,16 +41,17 @@ enum types { + KEY_ECDSA, + KEY_ED25519, + KEY_RSA_CERT, + KEY_DSA_CERT, + KEY_ECDSA_CERT, + KEY_ED25519_CERT, + KEY_RSA_CERT_V00, + KEY_DSA_CERT_V00, ++ KEY_NULL, + KEY_UNSPEC + }; + enum fp_type { + SSH_FP_SHA1, + SSH_FP_MD5, + SSH_FP_SHA256 + }; + enum fp_rep { +diff --git a/openssh-6.6p1/monitor.c b/openssh-6.6p1/monitor.c +--- a/openssh-6.6p1/monitor.c ++++ b/openssh-6.6p1/monitor.c +@@ -173,16 +173,18 @@ int mm_answer_pam_respond(int, Buffer *) + int mm_answer_pam_free_ctx(int, Buffer *); + #endif -Index: openssh-7.1p2/Makefile.in -=================================================================== ---- openssh-7.1p2.orig/Makefile.in -+++ openssh-7.1p2/Makefile.in -@@ -84,6 +84,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \ - atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o \ - monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ -+ kexgssc.o \ - msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ - ssh-pkcs11.o smult_curve25519_ref.o \ - poly1305.o chacha.o cipher-chachapoly.o \ -@@ -105,7 +106,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw - auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ - auth2-none.o auth2-passwd.o auth2-pubkey.o \ - monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \ -- auth2-gss.o gss-serv.o gss-serv-krb5.o \ -+ auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ - loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - sftp-server.o sftp-common.o \ - roaming_common.o roaming_serv.o \ -Index: openssh-7.1p2/monitor.c -=================================================================== ---- openssh-7.1p2.orig/monitor.c -+++ openssh-7.1p2/monitor.c -@@ -160,6 +160,8 @@ int mm_answer_gss_setup_ctx(int, Buffer + #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 *); @@ -1685,7 +2217,17 @@ Index: openssh-7.1p2/monitor.c #endif #ifdef SSH_AUDIT_EVENTS -@@ -246,11 +248,18 @@ struct mon_table mon_dispatch_proto20[] + 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 *); +@@ -254,21 +256,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}, @@ -1701,10 +2243,20 @@ Index: openssh-7.1p2/monitor.c + {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 -@@ -379,6 +388,10 @@ monitor_child_preauth(Authctxt *_authctx + {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}, +@@ -381,16 +390,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); @@ -1715,7 +2267,17 @@ Index: openssh-7.1p2/monitor.c } else { mon_dispatch = mon_dispatch_proto15; -@@ -487,6 +500,10 @@ monitor_child_postauth(struct monitor *p + monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); + } + + /* The first few requests do not require asynchronous access */ + while (!authenticated) { +@@ -486,16 +499,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); @@ -1726,10 +2288,20 @@ Index: openssh-7.1p2/monitor.c } else { mon_dispatch = mon_dispatch_postauth15; monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); -@@ -1944,6 +1961,13 @@ monitor_apply_keystate(struct monitor *p - # endif - #endif /* WITH_OPENSSL */ - kex->kex[KEX_C25519_SHA256] = kexc25519_server; + } + if (!no_pty_flag) { + monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); + } +@@ -1909,16 +1926,23 @@ mm_get_kex(Buffer *m) + fatal("mm_get_get: internal error: bad session id"); + kex->we_need = buffer_get_int(m); + 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; + kex->kex[KEX_ECDH_SHA2] = kexecdh_server; + kex->kex[KEX_C25519_SHA256] = kexc25519_server; +#ifdef GSSAPI + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; @@ -1737,10 +2309,20 @@ Index: openssh-7.1p2/monitor.c + 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; -@@ -2059,6 +2083,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer + kex->server = 1; + kex->hostkey_type = buffer_get_int(m); + kex->kex_type = buffer_get_int(m); + blob = buffer_get_string(m, &bloblen); + buffer_init(&kex->my); + buffer_append(&kex->my, blob, bloblen); + free(blob); + blob = buffer_get_string(m, &bloblen); +@@ -2133,16 +2157,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; @@ -1750,7 +2332,17 @@ Index: openssh-7.1p2/monitor.c goid.elements = buffer_get_string(m, &len); goid.length = len; -@@ -2086,6 +2113,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe + major = ssh_gssapi_server_ctx(&gsscontext, &goid); + + free(goid.elements); + + buffer_clear(m); +@@ -2160,16 +2187,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; @@ -1760,7 +2352,17 @@ Index: openssh-7.1p2/monitor.c in.value = buffer_get_string(m, &len); in.length = len; major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); -@@ -2103,6 +2133,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe + free(in.value); + + buffer_clear(m); + buffer_put_int(m, major); + buffer_put_string(m, out.value, out.length); +@@ -2177,27 +2207,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); @@ -1768,7 +2370,11 @@ Index: openssh-7.1p2/monitor.c } return (0); } -@@ -2114,6 +2145,9 @@ mm_answer_gss_checkmic(int sock, Buffer + + int + mm_answer_gss_checkmic(int sock, Buffer *m) + { + gss_buffer_desc gssbuf, mic; OM_uint32 ret; u_int len; @@ -1778,7 +2384,17 @@ Index: openssh-7.1p2/monitor.c gssbuf.value = buffer_get_string(m, &len); gssbuf.length = len; mic.value = buffer_get_string(m, &len); -@@ -2140,7 +2174,11 @@ mm_answer_gss_userok(int sock, Buffer *m + mic.length = len; + + ret = ssh_gssapi_checkmic(gsscontext, &gssbuf, &mic); + + free(gssbuf.value); +@@ -2214,29 +2248,101 @@ mm_answer_gss_checkmic(int sock, Buffer + return (0); + } + + int + mm_answer_gss_userok(int sock, Buffer *m) { int authenticated; @@ -1791,7 +2407,12 @@ Index: openssh-7.1p2/monitor.c buffer_clear(m); buffer_put_int(m, authenticated); -@@ -2153,6 +2191,74 @@ mm_answer_gss_userok(int sock, Buffer *m + + 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); } @@ -1866,24 +2487,43 @@ Index: openssh-7.1p2/monitor.c #endif /* GSSAPI */ #ifdef SSH_AUDIT_EVENTS -Index: openssh-7.1p2/monitor.h -=================================================================== ---- openssh-7.1p2.orig/monitor.h -+++ openssh-7.1p2/monitor.h -@@ -56,6 +56,8 @@ enum monitor_reqtype { - MONITOR_REQ_GSSUSEROK = 46, MONITOR_ANS_GSSUSEROK = 47, - MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49, - MONITOR_REQ_TERM = 50, -+ MONITOR_REQ_GSSSIGN = 82, MONITOR_ANS_GSSSIGN = 83, -+ MONITOR_REQ_GSSUPCREDS = 84, MONITOR_ANS_GSSUPCREDS = 85, + int + mm_answer_audit_unsupported_body(int sock, Buffer *m) + { + int what; - MONITOR_REQ_PAM_START = 100, - MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, -Index: openssh-7.1p2/monitor_wrap.c -=================================================================== ---- openssh-7.1p2.orig/monitor_wrap.c -+++ openssh-7.1p2/monitor_wrap.c -@@ -1102,7 +1102,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss +diff --git a/openssh-6.6p1/monitor.h b/openssh-6.6p1/monitor.h +--- a/openssh-6.6p1/monitor.h ++++ b/openssh-6.6p1/monitor.h +@@ -65,16 +65,19 @@ enum monitor_reqtype { + MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, + MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, + MONITOR_ANS_AUDIT_COMMAND = 114, MONITOR_REQ_AUDIT_END_COMMAND = 115, + MONITOR_REQ_AUDIT_UNSUPPORTED = 116, MONITOR_ANS_AUDIT_UNSUPPORTED = 117, + MONITOR_REQ_AUDIT_KEX = 118, MONITOR_ANS_AUDIT_KEX = 119, + MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 120, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 121, + MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 122, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 123, + ++ 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-6.6p1/monitor_wrap.c b/openssh-6.6p1/monitor_wrap.c +--- a/openssh-6.6p1/monitor_wrap.c ++++ b/openssh-6.6p1/monitor_wrap.c +@@ -1303,33 +1303,78 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss + &m); + + major = buffer_get_int(&m); + buffer_free(&m); + return(major); } int @@ -1892,7 +2532,16 @@ Index: openssh-7.1p2/monitor_wrap.c { Buffer m; int authenticated = 0; -@@ -1119,6 +1119,51 @@ mm_ssh_gssapi_userok(char *user) + + 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); } @@ -1930,25 +2579,34 @@ Index: openssh-7.1p2/monitor_wrap.c + 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 */ #ifdef SSH_AUDIT_EVENTS -Index: openssh-7.1p2/monitor_wrap.h -=================================================================== ---- openssh-7.1p2.orig/monitor_wrap.h -+++ openssh-7.1p2/monitor_wrap.h -@@ -59,8 +59,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(K + void + mm_audit_unsupported_body(int what) + { + Buffer m; + +diff --git a/openssh-6.6p1/monitor_wrap.h b/openssh-6.6p1/monitor_wrap.h +--- a/openssh-6.6p1/monitor_wrap.h ++++ b/openssh-6.6p1/monitor_wrap.h +@@ -54,18 +54,20 @@ int mm_user_key_verify(Key *, u_char *, + 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 *); @@ -1960,41 +2618,71 @@ Index: openssh-7.1p2/monitor_wrap.h #endif #ifdef USE_PAM -Index: openssh-7.1p2/readconf.c -=================================================================== ---- openssh-7.1p2.orig/readconf.c -+++ openssh-7.1p2/readconf.c -@@ -147,6 +147,8 @@ typedef enum { + 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-6.6p1/readconf.c b/openssh-6.6p1/readconf.c +--- a/openssh-6.6p1/readconf.c ++++ b/openssh-6.6p1/readconf.c +@@ -136,16 +136,18 @@ typedef enum { + oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, + oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, + oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, + oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, + oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, oGssEnableMITM, + oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, -+ oGssServerIdentity, ++ oGssServerIdentity, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, -@@ -192,11 +194,20 @@ static struct { + oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, + oVisualHostKey, oUseRoaming, + oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, + oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, + oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, +@@ -178,22 +180,31 @@ 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 }, + { "gssapienablemitmattack", oGssEnableMITM }, + { "gssapitrustdns", oGssTrustDns }, + { "gssapiclientidentity", oGssClientIdentity }, + { "gssapiserveridentity", oGssServerIdentity }, + { "gssapirenewalforcesrekey", oGssRenewalRekey }, - { "gssapienablemitmattack", oGssEnableMITM }, #else { "gssapiauthentication", oUnsupported }, + { "gssapikeyexchange", oUnsupported }, { "gssapidelegatecredentials", oUnsupported }, + { "gssapienablemitmattack", oUnsupported }, + { "gssapitrustdns", oUnsupported }, + { "gssapiclientidentity", oUnsupported }, + { "gssapirenewalforcesrekey", oUnsupported }, - { "gssapienablemitmattack", oUnsupported }, #endif { "fallbacktorsh", oDeprecated }, -@@ -896,9 +907,29 @@ parse_time: + { "usersh", oDeprecated }, + { "identityfile", oIdentityFile }, + { "identityfile2", oIdentityFile }, /* obsolete */ + { "identitiesonly", oIdentitiesOnly }, + { "hostname", oHostName }, + { "hostkeyalias", oHostKeyAlias }, +@@ -838,24 +849,44 @@ parse_time: + case oChallengeResponseAuthentication: + intptr = &options->challenge_response_authentication; + goto parse_flag; + + case oGssAuthentication: intptr = &options->gss_authentication; goto parse_flag; @@ -2005,39 +2693,65 @@ Index: openssh-7.1p2/readconf.c 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 oGssEnableMITM: intptr = &options->gss_enable_mitm; -@@ -1607,7 +1638,12 @@ initialize_options(Options * options) + 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; + +@@ -1498,18 +1529,23 @@ initialize_options(Options * options) + options->exit_on_forward_failure = -1; + options->xauth_location = NULL; + options->gateway_ports = -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->gss_enable_mitm = -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; -@@ -1736,8 +1772,14 @@ fill_default_options(Options * options) + 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; +@@ -1618,20 +1654,26 @@ 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; @@ -2045,111 +2759,78 @@ Index: openssh-7.1p2/readconf.c + options->gss_keyex = 0; if (options->gss_deleg_creds == -1) options->gss_deleg_creds = 0; + if (options->gss_enable_mitm == -1) + options->gss_enable_mitm = 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->gss_enable_mitm == -1) - options->gss_enable_mitm = 0; if (options->password_authentication == -1) -Index: openssh-7.1p2/readconf.h -=================================================================== ---- openssh-7.1p2.orig/readconf.h -+++ openssh-7.1p2/readconf.h -@@ -45,7 +45,12 @@ typedef struct { + 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-6.6p1/readconf.h b/openssh-6.6p1/readconf.h +--- a/openssh-6.6p1/readconf.h ++++ b/openssh-6.6p1/readconf.h +@@ -49,18 +49,23 @@ 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_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 */ + int gss_enable_mitm; /* Enable old style gssapi auth */ ++ 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 gss_enable_mitm; /* Enable old style gssapi auth */ int password_authentication; /* Try password * authentication. */ -Index: openssh-7.1p2/regress/cert-hostkey.sh -=================================================================== ---- openssh-7.1p2.orig/regress/cert-hostkey.sh -+++ openssh-7.1p2/regress/cert-hostkey.sh -@@ -46,7 +46,7 @@ touch $OBJ/host_revoked_plain - touch $OBJ/host_revoked_cert - cp $OBJ/host_ca_key.pub $OBJ/host_revoked_ca - --PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'` -+PLAIN_TYPES=`$SSH -Q key-plain | grep -v null | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'` - - # Prepare certificate, plain key and CA KRLs - ${SSHKEYGEN} -kf $OBJ/host_krl_empty || fatal "KRL init failed" -Index: openssh-7.1p2/regress/cert-userkey.sh -=================================================================== ---- openssh-7.1p2.orig/regress/cert-userkey.sh -+++ openssh-7.1p2/regress/cert-userkey.sh -@@ -7,7 +7,7 @@ rm -f $OBJ/authorized_keys_$USER $OBJ/us - cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak - cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak - --PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` -+PLAIN_TYPES=`$SSH -Q key-plain | grep -v null | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` - - kname() { - n=`echo "$1" | sed 's/^dsa/ssh-dss/;s/^rsa/ssh-rsa/;s/^ed/ssh-ed/'` -Index: openssh-7.1p2/regress/kextype.sh -=================================================================== ---- openssh-7.1p2.orig/regress/kextype.sh -+++ openssh-7.1p2/regress/kextype.sh -@@ -14,6 +14,9 @@ echo "KexAlgorithms=$KEXOPT" >> $OBJ/ssh - - tries="1 2 3 4" - for k in `${SSH} -Q kex`; do -+ if [ $k = "gss-gex-sha1-" -o $k = "gss-group1-sha1-" -o $k = "gss-group14-sha1-" ]; then -+ continue -+ fi - verbose "kex $k" - for i in $tries; do - ${SSH} -F $OBJ/ssh_proxy -o KexAlgorithms=$k x true -Index: openssh-7.1p2/regress/rekey.sh -=================================================================== ---- openssh-7.1p2.orig/regress/rekey.sh -+++ openssh-7.1p2/regress/rekey.sh -@@ -38,6 +38,9 @@ increase_datafile_size 300 - - opts="" - for i in `${SSH} -Q kex`; do -+ if [ $i = "gss-gex-sha1-" -o $i = "gss-group1-sha1-" -o $i = "gss-group14-sha1-" ]; then -+ continue -+ fi - opts="$opts KexAlgorithms=$i" - done - for i in `${SSH} -Q cipher`; do -@@ -56,6 +59,9 @@ done - if ${SSH} -Q cipher-auth | grep '^.*$' >/dev/null 2>&1 ; then - for c in `${SSH} -Q cipher-auth`; do - for kex in `${SSH} -Q kex`; do -+ if [ $kex = "gss-gex-sha1-" -o $kex = "gss-group1-sha1-" -o $kex = "gss-group14-sha1-" ]; then -+ continue -+ fi - verbose "client rekey $c $kex" - ssh_data_rekeying "KexAlgorithms=$kex" -oRekeyLimit=256k -oCiphers=$c - done -Index: openssh-7.1p2/servconf.c -=================================================================== ---- openssh-7.1p2.orig/servconf.c -+++ openssh-7.1p2/servconf.c -@@ -118,9 +118,11 @@ initialize_server_options(ServerOptions + 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-6.6p1/servconf.c b/openssh-6.6p1/servconf.c +--- a/openssh-6.6p1/servconf.c ++++ b/openssh-6.6p1/servconf.c +@@ -104,18 +104,21 @@ initialize_server_options(ServerOptions + options->hostbased_uses_name_from_packet_only = -1; + options->rsa_authentication = -1; + options->pubkey_authentication = -1; + 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_enable_mitm = -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; -@@ -279,10 +281,14 @@ fill_default_server_options(ServerOption + options->permit_empty_passwd = -1; + options->permit_user_env = -1; + options->use_login = -1; + options->compression = -1; + options->rekey_limit = -1; +@@ -243,20 +246,26 @@ 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; @@ -2157,33 +2838,57 @@ Index: openssh-7.1p2/servconf.c + 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->gss_enable_mitm == -1) options->gss_enable_mitm = 0; ++ if (options->gss_strict_acceptor == -1) ++ options->gss_strict_acceptor = 1; ++ if (options->gss_store_rekey == -1) ++ options->gss_store_rekey = 0; if (options->password_authentication == -1) -@@ -418,7 +424,7 @@ typedef enum { - sHostKeyAlgorithms, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, sGssEnableMITM, -- sAcceptEnv, sPermitTunnel, -+ sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, + 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; +@@ -342,16 +351,17 @@ typedef enum { + sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, + sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, + sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, + sMaxStartups, sMaxAuthTries, sMaxSessions, + sBanner, sUseDNS, sHostbasedAuthentication, + sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, + sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sGssEnableMITM, ++ sGssStrictAcceptor, sGssKeyEx, sGssStoreRekey, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, sHostCertificate, -@@ -495,12 +501,18 @@ static struct { + sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, + sKexAlgorithms, sIPQoS, sVersionAddendum, + sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, + sAuthenticationMethods, sHostKeyAgent, + sDeprecated, sUnsupported +@@ -411,21 +421,31 @@ 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 }, { "gssapienablemitmattack", sGssEnableMITM }, ++ { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, ++ { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, { "gssapienablemitmattack", sUnsupported }, ++ { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, #endif @@ -2192,7 +2897,17 @@ Index: openssh-7.1p2/servconf.c { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, -@@ -1244,6 +1256,10 @@ process_server_config_line(ServerOptions + { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */ + { "checkmail", sDeprecated, SSHCFG_GLOBAL }, + { "listenaddress", sListenAddress, SSHCFG_GLOBAL }, + { "addressfamily", sAddressFamily, SSHCFG_GLOBAL }, + { "printmotd", sPrintMotd, SSHCFG_GLOBAL }, +@@ -1094,24 +1114,36 @@ 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; @@ -2203,10 +2918,15 @@ Index: openssh-7.1p2/servconf.c case sGssCleanupCreds: intptr = &options->gss_cleanup_creds; goto parse_flag; -@@ -1256,6 +1272,10 @@ process_server_config_line(ServerOptions + + case sGssEnableMITM: intptr = &options->gss_enable_mitm; goto parse_flag; ++ case sGssStrictAcceptor: ++ intptr = &options->gss_strict_acceptor; ++ goto parse_flag; ++ + case sGssStoreRekey: + intptr = &options->gss_store_rekey; + goto parse_flag; @@ -2214,37 +2934,214 @@ Index: openssh-7.1p2/servconf.c case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -@@ -2264,6 +2284,9 @@ dump_config(ServerOptions *o) + + case sKbdInteractiveAuthentication: + intptr = &options->kbd_interactive_authentication; + goto parse_flag; + +@@ -2007,17 +2039,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(sGssCleanupCreds, o->gss_cleanup_creds); + dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); + dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); #endif dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); dump_cfg_fmtint(sKbdInteractiveAuthentication, -Index: openssh-7.1p2/servconf.h -=================================================================== ---- openssh-7.1p2.orig/servconf.h -+++ openssh-7.1p2/servconf.h -@@ -118,9 +118,11 @@ typedef struct { + o->kbd_interactive_authentication); + dump_cfg_fmtint(sChallengeResponseAuthentication, + o->challenge_response_authentication); + dump_cfg_fmtint(sPrintMotd, o->print_motd); + dump_cfg_fmtint(sPrintLastLog, o->print_lastlog); +diff --git a/openssh-6.6p1/servconf.h b/openssh-6.6p1/servconf.h +--- a/openssh-6.6p1/servconf.h ++++ b/openssh-6.6p1/servconf.h +@@ -107,18 +107,21 @@ 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_keyex; /* If true, permit GSSAPI key exchange */ int gss_cleanup_creds; /* If true, destroy cred cache on logout */ - int gss_enable_mitm; /* If true, enable old style GSSAPI */ - int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ -+ int gss_store_rekey; + int gss_enable_mitm; /* If true, enable old style GSSAPI */ ++ int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ ++ int gss_store_rekey; int password_authentication; /* If true, permit password * authentication. */ int kbd_interactive_authentication; /* If true, permit */ -Index: openssh-7.1p2/ssh_config.5 -=================================================================== ---- openssh-7.1p2.orig/ssh_config.5 -+++ openssh-7.1p2/ssh_config.5 -@@ -749,11 +749,43 @@ Specifies whether user authentication ba + 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-6.6p1/ssh-gss.h b/openssh-6.6p1/ssh-gss.h +--- a/openssh-6.6p1/ssh-gss.h ++++ b/openssh-6.6p1/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-6.6p1/ssh_config b/openssh-6.6p1/ssh_config +--- a/openssh-6.6p1/ssh_config ++++ b/openssh-6.6p1/ssh_config +@@ -32,16 +32,18 @@ Host * + ForwardX11Trusted yes + + # 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-6.6p1/ssh_config.5 b/openssh-6.6p1/ssh_config.5 +--- a/openssh-6.6p1/ssh_config.5 ++++ b/openssh-6.6p1/ssh_config.5 +@@ -677,21 +677,53 @@ host key database, separated by whitespa + 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 . Note that this option applies to protocol version 2 only. @@ -2289,26 +3186,22 @@ Index: openssh-7.1p2/ssh_config.5 .It Cm HashKnownHosts Indicates that .Xr ssh 1 -Index: openssh-7.1p2/ssh_config -=================================================================== ---- openssh-7.1p2.orig/ssh_config -+++ openssh-7.1p2/ssh_config -@@ -37,6 +37,8 @@ ForwardX11Trusted yes - # HostbasedAuthentication no - # GSSAPIAuthentication no - # GSSAPIDelegateCredentials no -+# GSSAPIKeyExchange no -+# GSSAPITrustDNS no - # BatchMode no - # CheckHostIP yes - # AddressFamily any -Index: openssh-7.1p2/sshconnect2.c -=================================================================== ---- openssh-7.1p2.orig/sshconnect2.c -+++ openssh-7.1p2/sshconnect2.c -@@ -160,9 +160,34 @@ ssh_kex2(char *host, struct sockaddr *ho - struct kex *kex; - int r; + 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-6.6p1/sshconnect2.c b/openssh-6.6p1/sshconnect2.c +--- a/openssh-6.6p1/sshconnect2.c ++++ b/openssh-6.6p1/sshconnect2.c +@@ -155,19 +155,44 @@ order_hostkeyalgs(char *host, struct soc + return ret; + } + + void + ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + { + Kex *kex; +#ifdef GSSAPI + char *orig = NULL, *gss = NULL; @@ -2322,7 +3215,7 @@ Index: openssh-7.1p2/sshconnect2.c + if (options.gss_keyex) { + /* Add the GSSAPI mechanisms currently supported on this + * client to the key exchange algorithm proposal */ -+ orig = options.kex_algorithms; ++ orig = myproposal[PROPOSAL_KEX_ALGS]; + + if (options.gss_trust_dns) + gss_host = (char *)get_canonical_hostname(1); @@ -2332,18 +3225,28 @@ Index: openssh-7.1p2/sshconnect2.c + gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); + if (gss) { + debug("Offering GSSAPI proposal: %s", gss); -+ xasprintf(&options.kex_algorithms, ++ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], + "%s,%s", gss, orig); + } + } +#endif + - myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( - options.kex_algorithms); - myproposal[PROPOSAL_ENC_ALGS_CTOS] = -@@ -193,6 +218,17 @@ ssh_kex2(char *host, struct sockaddr *ho + if (options.ciphers == (char *)-1) { + logit("No valid ciphers for protocol version 2 given, using defaults."); + options.ciphers = NULL; + } + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; + } else if (fips_mode()) { +@@ -205,32 +230,63 @@ ssh_kex2(char *host, struct sockaddr *ho + compat_pkalg_proposal( order_hostkeyalgs(host, hostaddr, port)); } + if (options.kex_algorithms != NULL) + myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( + myproposal[PROPOSAL_KEX_ALGS]); +#ifdef GSSAPI + /* If we've got GSSAPI algorithms, then we also support the @@ -2359,10 +3262,15 @@ Index: openssh-7.1p2/sshconnect2.c if (options.rekey_limit || options.rekey_interval) packet_set_rekey_limits((u_int32_t)options.rekey_limit, (time_t)options.rekey_interval); -@@ -210,11 +246,31 @@ ssh_kex2(char *host, struct sockaddr *ho + + /* start key exchange */ + kex = kex_setup(myproposal); + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 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; @@ -2370,7 +3278,6 @@ Index: openssh-7.1p2/sshconnect2.c + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; + } +#endif - kex->kex[KEX_C25519_SHA256] = kexc25519_client; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->verify_host_key=&verify_host_key_callback; @@ -2384,22 +3291,40 @@ Index: openssh-7.1p2/sshconnect2.c + kex->gss_host = options.gss_server_identity; + } else { + kex->gss_host = gss_host; -+ } ++ } + } +#endif + - dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); + xxx_kex = kex; + + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); if (options.use_roaming && !kex->roaming) { -@@ -306,6 +362,7 @@ int input_gssapi_token(int type, u_int32 - int input_gssapi_hash(int type, u_int32_t, void *); - int input_gssapi_error(int, u_int32_t, void *); - int input_gssapi_errtok(int, u_int32_t, void *); + debug("Roaming not allowed by server"); + options.use_roaming = 0; + } +@@ -310,31 +366,37 @@ int userauth_hostbased(Authctxt *); + + #ifdef GSSAPI + int userauth_gssapi(Authctxt *authctxt); + void input_gssapi_response(int type, u_int32_t, void *); + void input_gssapi_token(int type, u_int32_t, void *); + void input_gssapi_hash(int type, u_int32_t, void *); + void input_gssapi_error(int, u_int32_t, void *); + void input_gssapi_errtok(int, u_int32_t, void *); +int userauth_gsskeyex(Authctxt *authctxt); #endif void userauth(Authctxt *, char *); -@@ -321,6 +378,11 @@ static char *authmethods_get(void); + + static int sign_and_send_pubkey(Authctxt *, Identity *); + static void pubkey_prepare(Authctxt *); + static void pubkey_cleanup(Authctxt *); + static Key *load_identity_file(char *, int); + + static Authmethod *authmethod_get(char *authlist); + static Authmethod *authmethod_lookup(const char *name); + static char *authmethods_get(void); Authmethod authmethods[] = { #ifdef GSSAPI @@ -2411,7 +3336,17 @@ Index: openssh-7.1p2/sshconnect2.c {"gssapi-with-mic", userauth_gssapi, NULL, -@@ -632,19 +694,31 @@ userauth_gssapi(Authctxt *authctxt) + &options.gss_authentication, + NULL}, + {"gssapi", + userauth_gssapi, + NULL, +@@ -626,29 +688,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; @@ -2445,7 +3380,17 @@ Index: openssh-7.1p2/sshconnect2.c ok = 1; /* Mechanism works */ } else { mech++; -@@ -743,8 +817,8 @@ input_gssapi_response(int type, u_int32_ + } + } + + if (!ok) + return 0; +@@ -737,18 +811,18 @@ process_gssapi_token(void *ctxt, gss_buf + } + + /* ARGSUSED */ + void + input_gssapi_response(int type, u_int32_t plen, void *ctxt) { Authctxt *authctxt = ctxt; Gssctxt *gssctxt; @@ -2456,9 +3401,19 @@ Index: openssh-7.1p2/sshconnect2.c if (authctxt == NULL) fatal("input_gssapi_response: no authentication context"); -@@ -857,6 +931,48 @@ input_gssapi_error(int type, u_int32_t p + gssctxt = authctxt->methoddata; + + /* Setup our OID */ + oidv = packet_get_string(&oidlen); + +@@ -847,16 +921,58 @@ input_gssapi_error(int type, u_int32_t p + lang=packet_get_string(NULL); + + packet_check_eom(); + + debug("Server GSSAPI Error:\n%s", msg); + free(msg); free(lang); - return 0; } + +int @@ -2505,23 +3460,41 @@ Index: openssh-7.1p2/sshconnect2.c #endif /* GSSAPI */ int -Index: openssh-7.1p2/sshd.c -=================================================================== ---- openssh-7.1p2.orig/sshd.c -+++ openssh-7.1p2/sshd.c -@@ -1019,8 +1019,9 @@ notify_hostkeys(struct ssh *ssh) - } - debug3("%s: sent %d hostkeys", __func__, nkeys); - if (nkeys == 0) -- fatal("%s: no hostkeys", __func__); -- packet_send(); -+ debug3("%s: no hostkeys", __func__); -+ else -+ packet_send(); - sshbuf_free(buf); - } + userauth_none(Authctxt *authctxt) + { + /* initial userauth request */ + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -123,16 +123,20 @@ + #include "roaming.h" + #include "ssh-sandbox.h" + #include "version.h" -@@ -1891,10 +1892,13 @@ main(int ac, char **av) + #include "fips.h" + + #include "audit.h" + ++#ifdef USE_SECURITY_SESSION_API ++#include ++#endif ++ + #ifdef LIBWRAP + #include + #include + int allow_severity; + int deny_severity; + #endif /* LIBWRAP */ + + #ifndef O_NOCTTY +@@ -1804,20 +1808,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; } @@ -2535,7 +3508,159 @@ Index: openssh-7.1p2/sshd.c if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { logit("sshd: no hostkeys available -- exiting."); exit(1); -@@ -2635,6 +2639,48 @@ do_ssh2_kex(void) + } + + /* + * Load certificates. They are stored in an array at identical + * indices to the public keys that they relate to. +@@ -2007,16 +2014,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 +@@ -2134,16 +2195,70 @@ main(int ac, char **av) + } + #endif /* LIBWRAP */ + + /* Log the connection. */ + verbose("Connection from %s port %d on %s port %d", + remote_ip, remote_port, + get_local_ipaddr(sock_in), get_local_port()); + ++#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. + */ +@@ -2562,24 +2677,73 @@ do_ssh2_kex(void) + + if (options.rekey_limit || options.rekey_interval) + packet_set_rekey_limits((u_int32_t)options.rekey_limit, + (time_t)options.rekey_interval); + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( list_hostkey_types()); @@ -2582,11 +3707,12 @@ Index: openssh-7.1p2/sshd.c +#endif + /* start key exchange */ - if ((r = kex_setup(active_state, myproposal)) != 0) - fatal("kex_setup: %s", ssh_err(r)); -@@ -2649,6 +2695,13 @@ do_ssh2_kex(void) - # endif - #endif + kex = kex_setup(myproposal); + 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; + kex->kex[KEX_ECDH_SHA2] = kexecdh_server; kex->kex[KEX_C25519_SHA256] = kexc25519_server; +#ifdef GSSAPI + if (options.gss_keyex) { @@ -2598,11 +3724,42 @@ Index: openssh-7.1p2/sshd.c kex->server = 1; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; -Index: openssh-7.1p2/sshd_config.5 -=================================================================== ---- openssh-7.1p2.orig/sshd_config.5 -+++ openssh-7.1p2/sshd_config.5 -@@ -620,6 +620,12 @@ Specifies whether user authentication ba + 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-6.6p1/sshd_config b/openssh-6.6p1/sshd_config +--- a/openssh-6.6p1/sshd_config ++++ b/openssh-6.6p1/sshd_config +@@ -79,16 +79,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 support for the deprecated 'gssapi' authentication + # mechanism to OpenSSH 3.8p1. The newer 'gssapi-with-mic' mechanism is included + # in this release. The use of 'gssapi' is deprecated due to the presence of + # potential man-in-the-middle attacks, which 'gssapi-with-mic' is not susceptible to. + #GSSAPIEnableMITMAttack no + + +diff --git a/openssh-6.6p1/sshd_config.5 b/openssh-6.6p1/sshd_config.5 +--- a/openssh-6.6p1/sshd_config.5 ++++ b/openssh-6.6p1/sshd_config.5 +@@ -487,22 +487,50 @@ to force remote port forwardings to bind + 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 . Note that this option applies to protocol version 2 only. @@ -2615,167 +3772,36 @@ Index: openssh-7.1p2/sshd_config.5 .It Cm GSSAPICleanupCredentials Specifies whether to automatically destroy the user's credentials cache on logout. -@@ -641,6 +647,11 @@ machine's default store. - This facility is provided to assist with operation on multi homed machines. The default is .Dq yes . + Note that this option applies to protocol version 2 only. ++.It Cm GSSAPIStrictAcceptorCheck ++Determines whether to be strict about the identity of the GSSAPI acceptor ++a client authenticates against. If ++.Dq yes ++then the client must authenticate against the ++.Pa host ++service on the current hostname. If ++.Dq no ++then the client may authenticate against any service key stored in the ++machine's default store. This facility is provided to assist with operation ++on multi homed machines. ++The default is ++.Dq yes . ++Note that this option applies only to protocol version 2 GSSAPI connections, ++and setting it to ++.Dq no ++may only work with recent Kerberos GSSAPI libraries. +.It Cm GSSAPIStoreCredentialsOnRekey +Controls whether the user's GSSAPI credentials should be updated following a +successful connection rekeying. This option can be used to accepted renewed +or updated credentials from a compatible client. The default is +.Dq no . - .It Cm HostbasedAcceptedKeyTypes - Specifies the key types that will be accepted for hostbased authentication - as a comma-separated pattern list. -Index: openssh-7.1p2/sshd_config -=================================================================== ---- openssh-7.1p2.orig/sshd_config -+++ openssh-7.1p2/sshd_config -@@ -84,6 +84,8 @@ PasswordAuthentication no - # GSSAPI options - #GSSAPIAuthentication no - #GSSAPICleanupCredentials yes -+#GSSAPIStrictAcceptorCheck yes -+#GSSAPIKeyExchange no - - # Set this to 'yes' to enable support for the deprecated 'gssapi' authentication - # mechanism to OpenSSH 3.8p1. The newer 'gssapi-with-mic' mechanism is included -Index: openssh-7.1p2/ssh-gss.h -=================================================================== ---- openssh-7.1p2.orig/ssh-gss.h -+++ openssh-7.1p2/ssh-gss.h -@@ -1,6 +1,6 @@ - /* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */ - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -61,10 +61,22 @@ - - #define SSH_GSS_OIDTYPE 0x06 - -+#define SSH2_MSG_KEXGSS_INIT 30 -+#define SSH2_MSG_KEXGSS_CONTINUE 31 -+#define SSH2_MSG_KEXGSS_COMPLETE 32 -+#define SSH2_MSG_KEXGSS_HOSTKEY 33 -+#define SSH2_MSG_KEXGSS_ERROR 34 -+#define SSH2_MSG_KEXGSS_GROUPREQ 40 -+#define SSH2_MSG_KEXGSS_GROUP 41 -+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" -+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" -+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" -+ - typedef struct { - char *filename; - char *envvar; - char *envval; -+ struct passwd *owner; - void *data; - } ssh_gssapi_ccache; - -@@ -72,8 +84,11 @@ typedef struct { - gss_buffer_desc displayname; - gss_buffer_desc exportedname; - gss_cred_id_t creds; -+ gss_name_t name; - struct ssh_gssapi_mech_struct *mech; - ssh_gssapi_ccache store; -+ int used; -+ int updated; - } ssh_gssapi_client; - - typedef struct ssh_gssapi_mech_struct { -@@ -84,6 +99,7 @@ typedef struct ssh_gssapi_mech_struct { - int (*userok) (ssh_gssapi_client *, char *); - int (*localname) (ssh_gssapi_client *, char **); - void (*storecreds) (ssh_gssapi_client *); -+ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); - } ssh_gssapi_mech; - - typedef struct { -@@ -94,10 +110,11 @@ typedef struct { - gss_OID oid; /* client */ - gss_cred_id_t creds; /* server */ - gss_name_t client; /* server */ -- gss_cred_id_t client_creds; /* server */ -+ gss_cred_id_t client_creds; /* both */ - } Gssctxt; - - extern ssh_gssapi_mech *supported_mechs[]; -+extern Gssctxt *gss_kex_context; - - int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); - void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); -@@ -119,16 +136,32 @@ void ssh_gssapi_build_ctx(Gssctxt **); - void ssh_gssapi_delete_ctx(Gssctxt **); - OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); --int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); -+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); -+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); -+int ssh_gssapi_credentials_updated(Gssctxt *); - - /* In the server */ -+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, -+ const char *); -+char *ssh_gssapi_client_mechanisms(const char *, const char *); -+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, -+ const char *); -+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); -+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, -+ const char *); - OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); --int ssh_gssapi_userok(char *name); -+int ssh_gssapi_userok(char *name, struct passwd *); - OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_do_child(char ***, u_int *); - void ssh_gssapi_cleanup_creds(void); - void ssh_gssapi_storecreds(void); - -+char *ssh_gssapi_server_mechanisms(void); -+int ssh_gssapi_oid_table_ok(); -+ -+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); -+ -+void ssh_gssapi_rekey_creds(void); - #endif /* GSSAPI */ - - #endif /* _SSH_GSS_H */ -Index: openssh-7.1p2/sshkey.c -=================================================================== ---- openssh-7.1p2.orig/sshkey.c -+++ openssh-7.1p2/sshkey.c -@@ -112,6 +112,7 @@ static const struct keytype keytypes[] = - # endif /* OPENSSL_HAS_NISTP521 */ - # endif /* OPENSSL_HAS_ECC */ - #endif /* WITH_OPENSSL */ -+ { "null", "null", KEY_NULL, 0, 0 }, - { NULL, NULL, -1, -1, 0 } - }; - -Index: openssh-7.1p2/sshkey.h -=================================================================== ---- openssh-7.1p2.orig/sshkey.h -+++ openssh-7.1p2/sshkey.h -@@ -62,6 +62,7 @@ enum sshkey_types { - KEY_DSA_CERT, - KEY_ECDSA_CERT, - KEY_ED25519_CERT, -+ KEY_NULL, - KEY_UNSPEC - }; - -Index: openssh-7.1p2/auth.c -=================================================================== ---- openssh-7.1p2.orig/auth.c -+++ openssh-7.1p2/auth.c -@@ -354,6 +354,7 @@ auth_root_allowed(const char *method) - case PERMIT_NO_PASSWD: - if (strcmp(method, "publickey") == 0 || - strcmp(method, "hostbased") == 0 || -+ strcmp(method, "gssapi-keyex") == 0 || - strcmp(method, "gssapi-with-mic") == 0) - return 1; - break; + .It Cm HostbasedAuthentication + Specifies whether rhosts or /etc/hosts.equiv authentication together + with successful public key client host authentication is allowed + (host-based authentication). + This option is similar to + .Cm RhostsRSAAuthentication + and applies to protocol version 2 only. + The default is diff --git a/openssh-6.6p1-gssapimitm.patch b/openssh-6.6p1-gssapimitm.patch index 2a9278d..8684527 100644 --- a/openssh-6.6p1-gssapimitm.patch +++ b/openssh-6.6p1-gssapimitm.patch @@ -13,11 +13,41 @@ # recommended to use the 'gssapi-with-mic' mechanism. Existing installations # are encouraged to upgrade as soon as possible. -Index: b/auth2-gss.c -=================================================================== ---- a/auth2-gss.c -+++ b/auth2-gss.c -@@ -296,4 +296,10 @@ Authmethod method_gssapi = { +diff --git a/openssh-6.6p1/auth2-gss.c b/openssh-6.6p1/auth2-gss.c +--- a/openssh-6.6p1/auth2-gss.c ++++ b/openssh-6.6p1/auth2-gss.c +@@ -168,16 +168,25 @@ input_gssapi_token(int type, u_int32_t p + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + if (flags & GSS_C_INTEG_FLAG) + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, + &input_gssapi_mic); + else + dispatch_set( + SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, + &input_gssapi_exchange_complete); ++ ++ /* ++ * Old style 'gssapi' didn't have the GSSAPI_MIC ++ * and went straight to sending exchange_complete ++ */ ++ if (options.gss_enable_mitm) ++ dispatch_set( ++ SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, ++ &input_gssapi_exchange_complete); + } + } + + gss_release_buffer(&min_status, &send_tok); + } + + static void + input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) +@@ -286,9 +295,15 @@ input_gssapi_mic(int type, u_int32_t ple + } + + Authmethod method_gssapi = { + "gssapi-with-mic", + userauth_gssapi, &options.gss_authentication }; @@ -28,11 +58,15 @@ Index: b/auth2-gss.c +}; + #endif /* GSSAPI */ -Index: b/auth2.c -=================================================================== ---- a/auth2.c -+++ b/auth2.c -@@ -71,6 +71,7 @@ extern Authmethod method_kbdint; +diff --git a/openssh-6.6p1/auth2.c b/openssh-6.6p1/auth2.c +--- a/openssh-6.6p1/auth2.c ++++ b/openssh-6.6p1/auth2.c +@@ -65,23 +65,25 @@ extern Buffer loginmsg; + + 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_gssapi; @@ -40,7 +74,7 @@ Index: b/auth2.c #endif Authmethod *authmethods[] = { -@@ -78,6 +79,7 @@ Authmethod *authmethods[] = { + &method_none, &method_pubkey, #ifdef GSSAPI &method_gssapi, @@ -48,11 +82,20 @@ Index: b/auth2.c #endif &method_passwd, &method_kbdint, -Index: b/readconf.c -=================================================================== ---- a/readconf.c -+++ b/readconf.c -@@ -146,7 +146,7 @@ typedef enum { + &method_hostbased, + NULL + }; + + /* protocol */ +diff --git a/openssh-6.6p1/readconf.c b/openssh-6.6p1/readconf.c +--- a/openssh-6.6p1/readconf.c ++++ b/openssh-6.6p1/readconf.c +@@ -135,17 +135,17 @@ typedef enum { + oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, + oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, + oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, + oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, + oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, @@ -61,7 +104,17 @@ Index: b/readconf.c oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, -@@ -193,9 +193,11 @@ static struct { + oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, + oVisualHostKey, oUseRoaming, + oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, + oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, + oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, +@@ -179,19 +179,21 @@ static struct { + { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ + { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ + { "kerberosauthentication", oUnsupported }, + { "kerberostgtpassing", oUnsupported }, + { "afstokenpassing", oUnsupported }, #if defined(GSSAPI) { "gssapiauthentication", oGssAuthentication }, { "gssapidelegatecredentials", oGssDelegateCreds }, @@ -73,7 +126,17 @@ Index: b/readconf.c #endif { "fallbacktorsh", oDeprecated }, { "usersh", oDeprecated }, -@@ -897,6 +899,10 @@ parse_time: + { "identityfile", oIdentityFile }, + { "identityfile2", oIdentityFile }, /* obsolete */ + { "identitiesonly", oIdentitiesOnly }, + { "hostname", oHostName }, + { "hostkeyalias", oHostKeyAlias }, +@@ -839,16 +841,20 @@ parse_time: + + case oGssAuthentication: + intptr = &options->gss_authentication; + goto parse_flag; + case oGssDelegateCreds: intptr = &options->gss_deleg_creds; goto parse_flag; @@ -84,7 +147,17 @@ Index: b/readconf.c case oBatchMode: intptr = &options->batch_mode; -@@ -1602,6 +1608,7 @@ initialize_options(Options * options) + goto parse_flag; + + case oCheckHostIP: + intptr = &options->check_host_ip; + goto parse_flag; +@@ -1493,16 +1499,17 @@ initialize_options(Options * options) + options->xauth_location = NULL; + options->gateway_ports = -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_deleg_creds = -1; @@ -92,7 +165,17 @@ Index: b/readconf.c options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; -@@ -1731,6 +1738,8 @@ fill_default_options(Options * options) + options->rhosts_rsa_authentication = -1; + options->hostbased_authentication = -1; + options->batch_mode = -1; + options->check_host_ip = -1; + options->strict_host_key_checking = -1; +@@ -1613,16 +1620,18 @@ fill_default_options(Options * options) + 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_deleg_creds == -1) options->gss_deleg_creds = 0; @@ -101,11 +184,20 @@ Index: b/readconf.c if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -Index: b/readconf.h -=================================================================== ---- a/readconf.h -+++ b/readconf.h -@@ -46,6 +46,7 @@ typedef struct { + 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-6.6p1/readconf.h b/openssh-6.6p1/readconf.h +--- a/openssh-6.6p1/readconf.h ++++ b/openssh-6.6p1/readconf.h +@@ -50,16 +50,17 @@ typedef struct { + * 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_deleg_creds; /* Delegate GSS credentials */ @@ -113,51 +205,99 @@ Index: b/readconf.h int password_authentication; /* Try password * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -Index: b/servconf.c -=================================================================== ---- a/servconf.c -+++ b/servconf.c -@@ -119,6 +119,7 @@ initialize_server_options(ServerOptions + 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-6.6p1/servconf.c b/openssh-6.6p1/servconf.c +--- a/openssh-6.6p1/servconf.c ++++ b/openssh-6.6p1/servconf.c +@@ -104,16 +104,17 @@ initialize_server_options(ServerOptions + options->rsa_authentication = -1; + options->pubkey_authentication = -1; + 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_cleanup_creds = -1; - options->gss_strict_acceptor = -1; + options->gss_enable_mitm = -1; options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->challenge_response_authentication = -1; -@@ -279,6 +280,8 @@ fill_default_server_options(ServerOption + options->permit_empty_passwd = -1; + options->permit_user_env = -1; + options->use_login = -1; + options->compression = -1; + options->rekey_limit = -1; +@@ -241,16 +242,18 @@ fill_default_server_options(ServerOption + 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_cleanup_creds == -1) options->gss_cleanup_creds = 1; - if (options->gss_strict_acceptor == -1) - options->gss_strict_acceptor = 0; + if (options->gss_enable_mitm == -1) + options->gss_enable_mitm = 0; if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -411,7 +414,7 @@ typedef enum { - sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, - sHostKeyAlgorithms, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, -- sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, -+ sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, sGssEnableMITM, - sAcceptEnv, sPermitTunnel, + 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; +@@ -335,17 +338,17 @@ typedef enum { + sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression, + sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, + sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, + sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, + sMaxStartups, sMaxAuthTries, sMaxSessions, + sBanner, sUseDNS, sHostbasedAuthentication, + sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, + sClientAliveCountMax, sAuthorizedKeysFile, +- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, ++ sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sGssEnableMITM, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -486,10 +489,12 @@ static struct { + sHostCertificate, + sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, + sKexAlgorithms, sIPQoS, sVersionAddendum, + sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, + sAuthenticationMethods, sHostKeyAgent, + sDeprecated, sUnsupported +@@ -402,19 +405,21 @@ static struct { + { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, + { "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 }, + { "gssapienablemitmattack", sGssEnableMITM }, #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, + { "gssapienablemitmattack", sUnsupported }, #endif { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, -@@ -1239,6 +1244,10 @@ process_server_config_line(ServerOptions - intptr = &options->gss_strict_acceptor; + { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, + { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */ + { "checkmail", sDeprecated, SSHCFG_GLOBAL }, + { "listenaddress", sListenAddress, SSHCFG_GLOBAL }, + { "addressfamily", sAddressFamily, SSHCFG_GLOBAL }, +@@ -1085,16 +1090,20 @@ process_server_config_line(ServerOptions + case sGssAuthentication: + intptr = &options->gss_authentication; + goto parse_flag; + + case sGssCleanupCreds: + intptr = &options->gss_cleanup_creds; goto parse_flag; + case sGssEnableMITM: @@ -167,23 +307,41 @@ Index: b/servconf.c case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -Index: b/servconf.h -=================================================================== ---- a/servconf.h -+++ b/servconf.h -@@ -119,6 +119,7 @@ typedef struct { + + case sKbdInteractiveAuthentication: + intptr = &options->kbd_interactive_authentication; + goto parse_flag; + +diff --git a/openssh-6.6p1/servconf.h b/openssh-6.6p1/servconf.h +--- a/openssh-6.6p1/servconf.h ++++ b/openssh-6.6p1/servconf.h +@@ -108,16 +108,17 @@ typedef struct { + * 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_cleanup_creds; /* If true, destroy cred cache on logout */ -+ int gss_enable_mitm; /* If true, enable old style GSSAPI */ - int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ ++ int gss_enable_mitm; /* If true, enable old style GSSAPI */ int password_authentication; /* If true, permit password * authentication. */ -Index: b/ssh_config -=================================================================== ---- a/ssh_config -+++ b/ssh_config -@@ -56,4 +56,11 @@ ForwardX11Trusted yes + 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-6.6p1/ssh_config b/openssh-6.6p1/ssh_config +--- a/openssh-6.6p1/ssh_config ++++ b/openssh-6.6p1/ssh_config +@@ -51,9 +51,16 @@ ForwardX11Trusted yes + # Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc + # MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160 + # EscapeChar ~ + # Tunnel no + # TunnelDevice any:any # PermitLocalCommand no # VisualHostKey no # ProxyCommand ssh -q -W %h:%p gateway.example.com @@ -195,11 +353,15 @@ Index: b/ssh_config +# GSSAPIEnableMITMAttack no + # RekeyLimit 1G 1h -Index: b/sshconnect2.c -=================================================================== ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -326,6 +326,11 @@ Authmethod authmethods[] = { +diff --git a/openssh-6.6p1/sshconnect2.c b/openssh-6.6p1/sshconnect2.c +--- a/openssh-6.6p1/sshconnect2.c ++++ b/openssh-6.6p1/sshconnect2.c +@@ -318,16 +318,21 @@ static char *authmethods_get(void); + + Authmethod authmethods[] = { + #ifdef GSSAPI + {"gssapi-with-mic", + userauth_gssapi, NULL, &options.gss_authentication, NULL}, @@ -211,7 +373,17 @@ Index: b/sshconnect2.c #endif {"hostbased", userauth_hostbased, -@@ -703,7 +708,9 @@ process_gssapi_token(void *ctxt, gss_buf + NULL, + &options.hostbased_authentication, + NULL}, + {"publickey", + userauth_pubkey, +@@ -685,17 +690,19 @@ process_gssapi_token(void *ctxt, gss_buf + + packet_put_string(send_tok.value, send_tok.length); + packet_send(); + gss_release_buffer(&ms, &send_tok); + } if (status == GSS_S_COMPLETE) { /* send either complete or MIC, depending on mechanism */ @@ -222,11 +394,20 @@ Index: b/sshconnect2.c packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); packet_send(); } else { -Index: b/sshd_config -=================================================================== ---- a/sshd_config -+++ b/sshd_config -@@ -85,6 +85,13 @@ PasswordAuthentication no + ssh_gssapi_buildmic(&b, authctxt->server_user, + authctxt->service, "gssapi-with-mic"); + + gssbuf.value = buffer_ptr(&b); + gssbuf.length = buffer_len(&b); +diff --git a/openssh-6.6p1/sshd_config b/openssh-6.6p1/sshd_config +--- a/openssh-6.6p1/sshd_config ++++ b/openssh-6.6p1/sshd_config +@@ -80,16 +80,23 @@ PasswordAuthentication no + #KerberosOrLocalPasswd yes + #KerberosTicketCleanup yes + #KerberosGetAFSToken no + + # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes @@ -240,3 +421,8 @@ Index: b/sshd_config # 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 + # PAM authentication, then enable this but set PasswordAuthentication diff --git a/openssh-6.6p1-ldap.patch b/openssh-6.6p1-ldap.patch index 5e3f7a1..a91ff94 100644 --- a/openssh-6.6p1-ldap.patch +++ b/openssh-6.6p1-ldap.patch @@ -1,14 +1,26 @@ -diff -up openssh-6.8p1/HOWTO.ldap-keys.ldap openssh-6.8p1/HOWTO.ldap-keys ---- openssh-6.8p1/HOWTO.ldap-keys.ldap 2015-03-18 11:11:29.029801467 +0100 -+++ openssh-6.8p1/HOWTO.ldap-keys 2015-03-18 11:11:29.029801467 +0100 -@@ -0,0 +1,122 @@ +# 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-6.6p1/HOWTO.ldap-keys b/openssh-6.6p1/HOWTO.ldap-keys +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/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. ++ * For OpenLDAP or SunONE Use attached schema, otherwise you have to create ++ it. + * LDAP user entry + User entry: + - attached to the 'ldapPublicKey' objectclass @@ -16,7 +28,8 @@ diff -up openssh-6.8p1/HOWTO.ldap-keys.ldap openssh-6.8p1/HOWTO.ldap-keys + - 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. ++ * 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 @@ -36,8 +49,8 @@ diff -up openssh-6.8p1/HOWTO.ldap-keys.ldap openssh-6.8p1/HOWTO.ldap-keys + sshPublicKey: command="kill -9 1" ssh-rss AAAAM5... +4) on the ssh side set in sshd_config + * Set up the backend -+ AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-wrapper -+ AuthorizedKeysCommandUser ++ AuthorizedKeysCommand "@LIBEXECDIR@/ssh-ldap-wrapper" ++ AuthorizedKeysCommandRunAs + * Do not forget to set + PubkeyAuthentication yes + * Swith off unnecessary auth methods @@ -48,10 +61,7 @@ diff -up openssh-6.8p1/HOWTO.ldap-keys.ldap openssh-6.8p1/HOWTO.ldap-keys + * There is a possibility to change ldap.conf location + * There are some debug options + * Example -+ /usr/libexec/openssh -s -f /etc/ldap.conf -w -d >> /tmp/ldapdebuglog.txt -+7) Configure SELinux boolean which allows ldap-helper to bind ldap server -+ Run this command -+ # setsebool -P authlogin_nsswitch_use_ldap on ++ @LIBEXECDIR@/ssh-ldap-wrapper -s -f /etc/ldap.conf -w -d >> /tmp/ldapdebuglog.txt + +HOW TO MIGRATE FROM LPK + @@ -67,28 +77,20 @@ diff -up openssh-6.8p1/HOWTO.ldap-keys.ldap openssh-6.8p1/HOWTO.ldap-keys + * ssh-ldap-helper -d -d -d -d -s +3) use tcpdump ... other ldap client etc. + -+HOW TO CONFIGURE SSH FOR OTHER LDAP CONFIGURATION / SERVER /SCHEMA -+ -+You can adjust search format string in /etc/ldap.conf using -+ 1) SSH_Filter option to limit results for only specified users -+ (this appends search condition after original query) -+ 2) Search_Format option to define your own search string using expansion -+ characters %u for username, %c for objectclass and %f for above mentioned filter. -+ -+Example: -+Search_Format (&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%u)%f) -+ +ADVANTAGES + -+1) Blocking an user account can be done directly from LDAP (if sshd is using PubkeyAuthentication + AuthorizedKeysCommand with ldap only). ++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. ++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. @@ -107,7 +109,8 @@ diff -up openssh-6.8p1/HOWTO.ldap-keys.ldap openssh-6.8p1/HOWTO.ldap-keys + * 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 ) ++ * http://lam.sf.net/ ++ ( http://lam.sourceforge.net/documentation/supportedSchemas.htm ) + +4) contributors/ideas/greets + - Eric AUGE @@ -118,16 +121,15 @@ diff -up openssh-6.8p1/HOWTO.ldap-keys.ldap openssh-6.8p1/HOWTO.ldap-keys + - frederic peters. + - Finlay dobbie. + - Stefan Fisher. -+ - Robin H. Johnson. -+ - Adrian Bridgett. -+ -+5) Author -+ Jan F. Chadima -+ -diff -up openssh-6.8p1/Makefile.in.ldap openssh-6.8p1/Makefile.in ---- openssh-6.8p1/Makefile.in.ldap 2015-03-17 06:49:20.000000000 +0100 -+++ openssh-6.8p1/Makefile.in 2015-03-18 11:13:10.147561177 +0100 -@@ -25,6 +25,8 @@ SSH_PROGRAM=@bindir@/ssh +diff --git a/openssh-6.6p1/Makefile.in b/openssh-6.6p1/Makefile.in +--- a/openssh-6.6p1/Makefile.in ++++ b/openssh-6.6p1/Makefile.in +@@ -20,16 +20,18 @@ srcdir=@srcdir@ + 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 @@ -136,18 +138,38 @@ diff -up openssh-6.8p1/Makefile.in.ldap openssh-6.8p1/Makefile.in SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper PRIVSEP_PATH=@PRIVSEP_PATH@ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ -@@ -61,8 +63,9 @@ XAUTH_PATH=@XAUTH_PATH@ + STRIP_OPT=@STRIP_OPT@ + + PATHS= -DSSHDIR=\"$(sysconfdir)\" \ + -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ + -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ +@@ -56,17 +58,19 @@ INSTALL=@INSTALL@ + PERL=@PERL@ + SED=@SED@ + ENT=@ENT@ + XAUTH_PATH=@XAUTH_PATH@ LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ EXEEXT=@EXEEXT@ MANFMT=@MANFMT@ -+INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ -TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ++INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ ++ +TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) - LIBOPENSSH_OBJS=\ - ssh_api.o \ -@@ -112,8 +115,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw + LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ + canohost.o channels.o cipher.o cipher-aes.o \ + cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \ + compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \ + log.o match.o md-sha256.o moduli.o nchan.o packet.o \ + readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \ + atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ +@@ -96,18 +100,18 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw + kexc25519s.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 \ + roaming_common.o roaming_serv.o \ sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ sandbox-seccomp-filter.o sandbox-capsicum.o @@ -158,28 +180,55 @@ diff -up openssh-6.8p1/Makefile.in.ldap openssh-6.8p1/Makefile.in MANTYPE = @MANTYPE@ CONFIGFILES=sshd_config.out ssh_config.out moduli.out -@@ -184,6 +187,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss + 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' \ +@@ -171,16 +175,19 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss + $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.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-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o sshbuf-getput-basic.o ssherr.o -+ $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o sshbuf-getput-basic.o ssherr.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) -+ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -@@ -311,6 +317,10 @@ install-files: ++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 $(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) + + # test driver for the loginrec code - not built by default + logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o +@@ -273,30 +280,38 @@ 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) -+ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ -+ $(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \ -+ $(INSTALL) -m 0700 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) ++ 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 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -@@ -327,6 +337,10 @@ install-files: + $(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 + $(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 @@ -190,7 +239,17 @@ diff -up openssh-6.8p1/Makefile.in.ldap openssh-6.8p1/Makefile.in -rm -f $(DESTDIR)$(bindir)/slogin ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 -@@ -356,6 +370,13 @@ install-sysconf: + ln -s ./ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 + + install-sysconf: + if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \ + $(srcdir)/mkinstalldirs $(DESTDIR)$(sysconfdir); \ +@@ -316,16 +331,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 @@ -204,7 +263,17 @@ diff -up openssh-6.8p1/Makefile.in.ldap openssh-6.8p1/Makefile.in host-key: ssh-keygen$(EXEEXT) @if [ -z "$(DESTDIR)" ] ; then \ -@@ -419,6 +440,8 @@ uninstall: + if [ -f "$(sysconfdir)/ssh_host_key" ] ; then \ + echo "$(sysconfdir)/ssh_host_key already exists, skipping." ; \ + else \ + ./ssh-keygen -t rsa1 -f $(sysconfdir)/ssh_host_key -N "" ; \ + fi ; \ +@@ -379,27 +401,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) @@ -213,20 +282,34 @@ diff -up openssh-6.8p1/Makefile.in.ldap openssh-6.8p1/Makefile.in -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 -@@ -430,6 +453,7 @@ uninstall: + -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 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 - regress-prep: -diff -up openssh-6.8p1/configure.ac.ldap openssh-6.8p1/configure.ac ---- openssh-6.8p1/configure.ac.ldap 2015-03-17 06:49:20.000000000 +0100 -+++ openssh-6.8p1/configure.ac 2015-03-18 11:11:29.030801464 +0100 -@@ -1605,6 +1605,106 @@ if test "x$use_pie" != "xno"; then - fi - fi + regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c + [ -d `pwd`/regress ] || mkdir -p `pwd`/regress + [ -f `pwd`/regress/Makefile ] || \ + ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \ + $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +diff --git a/openssh-6.6p1/configure.ac b/openssh-6.6p1/configure.ac +--- a/openssh-6.6p1/configure.ac ++++ b/openssh-6.6p1/configure.ac +@@ -1599,16 +1599,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" @@ -328,12 +411,18 @@ diff -up openssh-6.8p1/configure.ac.ldap openssh-6.8p1/configure.ac +) +AC_SUBST(INSTALL_SSH_LDAP_HELPER) + - dnl Checks for library functions. Please keep in alphabetical order - AC_CHECK_FUNCS([ \ - Blowfish_initstate \ -diff -up openssh-6.8p1/ldap-helper.c.ldap openssh-6.8p1/ldap-helper.c ---- openssh-6.8p1/ldap-helper.c.ldap 2015-03-18 11:11:29.030801464 +0100 -+++ openssh-6.8p1/ldap-helper.c 2015-03-18 11:11:29.030801464 +0100 + 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-6.6p1/ldap-helper.c b/openssh-6.6p1/ldap-helper.c +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ldap-helper.c @@ -0,0 +1,155 @@ +/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -490,9 +579,10 @@ diff -up openssh-6.8p1/ldap-helper.c.ldap openssh-6.8p1/ldap-helper.c +void *buffer_get_string(Buffer *b, u_int *l) { return NULL; } +void buffer_put_string(Buffer *b, const void *f, u_int l) {} + -diff -up openssh-6.8p1/ldap-helper.h.ldap openssh-6.8p1/ldap-helper.h ---- openssh-6.8p1/ldap-helper.h.ldap 2015-03-18 11:11:29.031801462 +0100 -+++ openssh-6.8p1/ldap-helper.h 2015-03-18 11:11:29.031801462 +0100 +diff --git a/openssh-6.6p1/ldap-helper.h b/openssh-6.6p1/ldap-helper.h +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ldap-helper.h @@ -0,0 +1,32 @@ +/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -526,10 +616,11 @@ diff -up openssh-6.8p1/ldap-helper.h.ldap openssh-6.8p1/ldap-helper.h +extern int config_warning_config_file; + +#endif /* LDAP_HELPER_H */ -diff -up openssh-6.8p1/ldap.conf.ldap openssh-6.8p1/ldap.conf ---- openssh-6.8p1/ldap.conf.ldap 2015-03-18 11:11:29.031801462 +0100 -+++ openssh-6.8p1/ldap.conf 2015-03-18 11:11:29.031801462 +0100 -@@ -0,0 +1,95 @@ +diff --git a/openssh-6.6p1/ldap.conf b/openssh-6.6p1/ldap.conf +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/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 @@ -618,17 +709,11 @@ diff -up openssh-6.8p1/ldap.conf.ldap openssh-6.8p1/ldap.conf +#tls_cert +#tls_key + -+# OpenLDAP search_format -+# format used to search for users in LDAP directory using substitution -+# for %u for user name and %f for SSH_Filter option (optional, empty by default) -+#search_format (&(objectclass=%c)(objectclass=ldapPublicKey)(uid=%u)%f) -+ -+#AccountClass posixAccount -+ -diff -up openssh-6.8p1/ldapbody.c.ldap openssh-6.8p1/ldapbody.c ---- openssh-6.8p1/ldapbody.c.ldap 2015-03-18 11:11:29.031801462 +0100 -+++ openssh-6.8p1/ldapbody.c 2015-03-18 11:11:29.031801462 +0100 -@@ -0,0 +1,493 @@ +diff --git a/openssh-6.6p1/ldapbody.c b/openssh-6.6p1/ldapbody.c +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/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. @@ -662,9 +747,8 @@ diff -up openssh-6.8p1/ldapbody.c.ldap openssh-6.8p1/ldapbody.c +#include "ldapbody.h" +#include +#include -+#include "misc.h" + -+#define LDAPSEARCH_FORMAT "(&(objectclass=%c)(objectclass=ldapPublicKey)(uid=%u)%f)" ++#define LDAPSEARCH_FORMAT "(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s)%s)" +#define PUBKEYATTR "sshPublicKey" +#define LDAP_LOGFILE "%s/ldap.%d" + @@ -798,7 +882,7 @@ diff -up openssh-6.8p1/ldapbody.c.ldap openssh-6.8p1/ldapbody.c + ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &options.debug); +#endif /* LBER_OPT_DEBUG_LEVEL */ +#ifdef LDAP_OPT_DEBUG_LEVEL -+ (void) ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug); ++ ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug); +#endif /* LDAP_OPT_DEBUG_LEVEL */ + debug3 ("Set LDAP debug to %d", options.debug); + } @@ -1051,8 +1135,8 @@ diff -up openssh-6.8p1/ldapbody.c.ldap openssh-6.8p1/ldapbody.c +process_user (const char *user, FILE *output) +{ + LDAPMessage *res, *e; -+ char *buffer, *format; -+ int rc, i; ++ char *buffer; ++ int bufflen, rc, i; + struct timeval timeout; + + debug ("LDAP process user"); @@ -1065,10 +1149,12 @@ diff -up openssh-6.8p1/ldapbody.c.ldap openssh-6.8p1/ldapbody.c + } + + /* build filter for LDAP request */ -+ format = LDAPSEARCH_FORMAT; -+ if (options.search_format != NULL) -+ format = options.search_format; -+ buffer = percent_expand(format, "c", options.account_class, "u", user, "f", options.ssh_filter, (char *)NULL); ++ 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); + @@ -1122,9 +1208,10 @@ diff -up openssh-6.8p1/ldapbody.c.ldap openssh-6.8p1/ldapbody.c + return; +} + -diff -up openssh-6.8p1/ldapbody.h.ldap openssh-6.8p1/ldapbody.h ---- openssh-6.8p1/ldapbody.h.ldap 2015-03-18 11:11:29.031801462 +0100 -+++ openssh-6.8p1/ldapbody.h 2015-03-18 11:11:29.031801462 +0100 +diff --git a/openssh-6.6p1/ldapbody.h b/openssh-6.6p1/ldapbody.h +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ldapbody.h @@ -0,0 +1,37 @@ +/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -1163,10 +1250,11 @@ diff -up openssh-6.8p1/ldapbody.h.ldap openssh-6.8p1/ldapbody.h + +#endif /* LDAPBODY_H */ + -diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c ---- openssh-6.8p1/ldapconf.c.ldap 2015-03-18 11:11:29.032801460 +0100 -+++ openssh-6.8p1/ldapconf.c 2015-03-18 11:11:29.032801460 +0100 -@@ -0,0 +1,728 @@ +diff --git a/openssh-6.6p1/ldapconf.c b/openssh-6.6p1/ldapconf.c +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ldapconf.c +@@ -0,0 +1,682 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* + * Copyright (c) 2009 Jan F. Chadima. All rights reserved. @@ -1210,8 +1298,8 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + 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, lSearch_Format, -+ lAccountClass, lDeprecated, lUnsupported ++ lTLS_RandFile, lLogDir, lDebug, lSSH_Filter, ++ lDeprecated, lUnsupported +} OpCodes; + +/* Textual representations of the tokens. */ @@ -1263,8 +1351,6 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + { "LogDir", lLogDir }, + { "Debug", lDebug }, + { "SSH_Filter", lSSH_Filter }, -+ { "search_format", lSearch_Format }, -+ { "AccountClass", lAccountClass }, + { NULL, lBadOption } +}; + @@ -1291,35 +1377,6 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + return lBadOption; +} + -+/* Characters considered whitespace in strsep calls. */ -+#define WHITESPACE " \t\r\n" -+ -+/* return next token in configuration line */ -+static char * -+ldap_strdelim(char **s) -+{ -+ char *old; -+ int wspace = 0; -+ -+ if (*s == NULL) -+ return NULL; -+ -+ old = *s; -+ -+ *s = strpbrk(*s, WHITESPACE); -+ if (*s == NULL) -+ return (old); -+ -+ *s[0] = '\0'; -+ -+ /* Skip any extra whitespace after first token */ -+ *s += strspn(*s + 1, WHITESPACE) + 1; -+ if (*s[0] == '=' && !wspace) -+ *s += strspn(*s + 1, WHITESPACE) + 1; -+ -+ return (old); -+} -+ +/* + * Processes a single option line as used in the configuration files. This + * only sets those values that have not already been set. @@ -1343,11 +1400,11 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + + s = line; + /* Get the keyword. (Each line is supposed to begin with a keyword). */ -+ if ((keyword = ldap_strdelim(&s)) == NULL) ++ if ((keyword = strdelim(&s)) == NULL) + return 0; + /* Ignore leading whitespace. */ + if (*keyword == '\0') -+ keyword = ldap_strdelim(&s); ++ keyword = strdelim(&s); + if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') + return 0; + @@ -1383,7 +1440,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + case lBindPW: + charptr = &options.bindpw; +parse_string: -+ arg = ldap_strdelim(&s); ++ arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (*charptr == NULL) @@ -1396,7 +1453,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + + case lScope: + intptr = &options.scope; -+ arg = ldap_strdelim(&s); ++ arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing sub/one/base argument.", filename, linenum); + value = 0; /* To avoid compiler warning... */ @@ -1414,7 +1471,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + + case lDeref: + intptr = &options.scope; -+ arg = ldap_strdelim(&s); ++ 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... */ @@ -1435,7 +1492,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + case lPort: + intptr = &options.port; +parse_int: -+ arg = ldap_strdelim(&s); ++ arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (arg[0] < '0' || arg[0] > '9') @@ -1452,7 +1509,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + case lTimeLimit: + intptr = &options.timelimit; +parse_time: -+ arg = ldap_strdelim(&s); ++ arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%s line %d: missing time value.", + filename, linenum); @@ -1473,7 +1530,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + + case lBind_Policy: + intptr = &options.bind_policy; -+ arg = ldap_strdelim(&s); ++ arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing soft/hard argument.", filename, linenum); + value = 0; /* To avoid compiler warning... */ @@ -1484,7 +1541,6 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + else + fatal("%.200s line %d: Bad soft/hard argument.", filename, linenum); + if (*intptr == -1) -+ *intptr = value; + break; + + case lSSLPath: @@ -1493,7 +1549,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + + case lSSL: + intptr = &options.ssl; -+ arg = ldap_strdelim(&s); ++ 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... */ @@ -1512,7 +1568,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + case lReferrals: + intptr = &options.referrals; +parse_flag: -+ arg = ldap_strdelim(&s); ++ arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); + value = 0; /* To avoid compiler warning... */ @@ -1532,7 +1588,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + + case lTLS_CheckPeer: + intptr = &options.tls_checkpeer; -+ arg = ldap_strdelim(&s); ++ 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... */ @@ -1549,7 +1605,6 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + else + fatal("%.200s line %d: Bad never/hard/demand/alow/try argument.", filename, linenum); + if (*intptr == -1) -+ *intptr = value; + break; + + case lTLS_CaCertFile: @@ -1588,14 +1643,6 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + xstringptr = &options.ssh_filter; + goto parse_xstring; + -+ case lSearch_Format: -+ charptr = &options.search_format; -+ goto parse_string; -+ -+ case lAccountClass: -+ charptr = &options.account_class; -+ goto parse_string; -+ + case lDeprecated: + debug("%s line %d: Deprecated option \"%s\"", + filename, linenum, keyword); @@ -1611,7 +1658,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + } + + /* Check that there is no garbage at end of line. */ -+ if ((arg = ldap_strdelim(&s)) != NULL && *arg != '\0') { ++ if ((arg = strdelim(&s)) != NULL && *arg != '\0') { + fatal("%.200s line %d: garbage at end of line; \"%.200s\".", + filename, linenum, arg); + } @@ -1629,7 +1676,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c +{ + FILE *f; + char line[1024]; -+ int linenum; ++ int active, linenum; + int bad_options = 0; + struct stat sb; + @@ -1648,6 +1695,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + * 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. */ @@ -1698,8 +1746,6 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + options.logdir = NULL; + options.debug = -1; + options.ssh_filter = NULL; -+ options.search_format = NULL; -+ options.account_class = NULL; +} + +/* @@ -1742,7 +1788,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + 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); ++ options.uri = xrealloc (options.uri, len + 1, 1); + } + if (options.binddn == NULL) + options.binddn = ""; @@ -1770,8 +1816,6 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + options.debug = 0; + if (options.ssh_filter == NULL) + options.ssh_filter = ""; -+ if (options.account_class == NULL) -+ options.account_class = "posixAccount"; +} + +static const char * @@ -1891,14 +1935,13 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c + dump_cfg_string(lLogDir, options.logdir); + dump_cfg_int(lDebug, options.debug); + dump_cfg_string(lSSH_Filter, options.ssh_filter); -+ dump_cfg_string(lSearch_Format, options.search_format); -+ dump_cfg_string(lAccountClass, options.account_class); +} + -diff -up openssh-6.8p1/ldapconf.h.ldap openssh-6.8p1/ldapconf.h ---- openssh-6.8p1/ldapconf.h.ldap 2015-03-18 11:11:29.032801460 +0100 -+++ openssh-6.8p1/ldapconf.h 2015-03-18 11:11:29.032801460 +0100 -@@ -0,0 +1,73 @@ +diff --git a/openssh-6.6p1/ldapconf.h b/openssh-6.6p1/ldapconf.h +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/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. @@ -1960,8 +2003,6 @@ diff -up openssh-6.8p1/ldapconf.h.ldap openssh-6.8p1/ldapconf.h + char *logdir; + int debug; + char *ssh_filter; -+ char *search_format; -+ char *account_class; +} Options; + +extern Options options; @@ -1972,9 +2013,10 @@ diff -up openssh-6.8p1/ldapconf.h.ldap openssh-6.8p1/ldapconf.h +void dump_config(void); + +#endif /* LDAPCONF_H */ -diff -up openssh-6.8p1/ldapincludes.h.ldap openssh-6.8p1/ldapincludes.h ---- openssh-6.8p1/ldapincludes.h.ldap 2015-03-18 11:11:29.032801460 +0100 -+++ openssh-6.8p1/ldapincludes.h 2015-03-18 11:11:29.032801460 +0100 +diff --git a/openssh-6.6p1/ldapincludes.h b/openssh-6.6p1/ldapincludes.h +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ldapincludes.h @@ -0,0 +1,41 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -2017,9 +2059,10 @@ diff -up openssh-6.8p1/ldapincludes.h.ldap openssh-6.8p1/ldapincludes.h +#endif + +#endif /* LDAPINCLUDES_H */ -diff -up openssh-6.8p1/ldapmisc.c.ldap openssh-6.8p1/ldapmisc.c ---- openssh-6.8p1/ldapmisc.c.ldap 2015-03-18 11:11:29.032801460 +0100 -+++ openssh-6.8p1/ldapmisc.c 2015-03-18 11:11:29.032801460 +0100 +diff --git a/openssh-6.6p1/ldapmisc.c b/openssh-6.6p1/ldapmisc.c +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ldapmisc.c @@ -0,0 +1,79 @@ + +#include "ldapincludes.h" @@ -2100,9 +2143,10 @@ diff -up openssh-6.8p1/ldapmisc.c.ldap openssh-6.8p1/ldapmisc.c +} +#endif + -diff -up openssh-6.8p1/ldapmisc.h.ldap openssh-6.8p1/ldapmisc.h ---- openssh-6.8p1/ldapmisc.h.ldap 2015-03-18 11:11:29.032801460 +0100 -+++ openssh-6.8p1/ldapmisc.h 2015-03-18 11:11:29.032801460 +0100 +diff --git a/openssh-6.6p1/ldapmisc.h b/openssh-6.6p1/ldapmisc.h +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ldapmisc.h @@ -0,0 +1,35 @@ +/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -2139,9 +2183,102 @@ diff -up openssh-6.8p1/ldapmisc.h.ldap openssh-6.8p1/ldapmisc.h + +#endif /* LDAPMISC_H */ + -diff -up openssh-6.8p1/openssh-lpk-openldap.schema.ldap openssh-6.8p1/openssh-lpk-openldap.schema ---- openssh-6.8p1/openssh-lpk-openldap.schema.ldap 2015-03-18 11:11:29.033801457 +0100 -+++ openssh-6.8p1/openssh-lpk-openldap.schema 2015-03-18 11:11:29.033801457 +0100 +diff --git a/openssh-6.6p1/openbsd-compat/base64.c b/openssh-6.6p1/openbsd-compat/base64.c +--- a/openssh-6.6p1/openbsd-compat/base64.c ++++ b/openssh-6.6p1/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-6.6p1/openbsd-compat/base64.h b/openssh-6.6p1/openbsd-compat/base64.h +--- a/openssh-6.6p1/openbsd-compat/base64.h ++++ b/openssh-6.6p1/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-6.6p1/openssh-lpk-openldap.schema b/openssh-6.6p1/openssh-lpk-openldap.schema +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/openssh-lpk-openldap.schema @@ -0,0 +1,21 @@ +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey @@ -2164,9 +2301,10 @@ diff -up openssh-6.8p1/openssh-lpk-openldap.schema.ldap openssh-6.8p1/openssh-lp + DESC 'MANDATORY: OpenSSH LPK objectclass' + MUST ( sshPublicKey $ uid ) + ) -diff -up openssh-6.8p1/openssh-lpk-sun.schema.ldap openssh-6.8p1/openssh-lpk-sun.schema ---- openssh-6.8p1/openssh-lpk-sun.schema.ldap 2015-03-18 11:11:29.033801457 +0100 -+++ openssh-6.8p1/openssh-lpk-sun.schema 2015-03-18 11:11:29.033801457 +0100 +diff --git a/openssh-6.6p1/openssh-lpk-sun.schema b/openssh-6.6p1/openssh-lpk-sun.schema +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/openssh-lpk-sun.schema @@ -0,0 +1,23 @@ +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey @@ -2191,9 +2329,10 @@ diff -up openssh-6.8p1/openssh-lpk-sun.schema.ldap openssh-6.8p1/openssh-lpk-sun + DESC 'MANDATORY: OpenSSH LPK objectclass' + MUST ( sshPublicKey $ uid ) + ) -diff -up openssh-6.8p1/ssh-ldap-helper.8.ldap openssh-6.8p1/ssh-ldap-helper.8 ---- openssh-6.8p1/ssh-ldap-helper.8.ldap 2015-03-18 11:11:29.033801457 +0100 -+++ openssh-6.8p1/ssh-ldap-helper.8 2015-03-18 11:11:29.033801457 +0100 +diff --git a/openssh-6.6p1/ssh-ldap-helper.8 b/openssh-6.6p1/ssh-ldap-helper.8 +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ssh-ldap-helper.8 @@ -0,0 +1,79 @@ +.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $ +.\" @@ -2234,7 +2373,7 @@ diff -up openssh-6.8p1/ssh-ldap-helper.8.ldap openssh-6.8p1/ssh-ldap-helper.8 +by setting +.Cm AuthorizedKeysCommand +to -+.Dq /usr/libexec/ssh-ldap-wrapper . ++.Dq @LIBEXECDIR@/ssh-ldap-wrapper . +.Pp +.Nm +is not intended to be invoked by the user, but from @@ -2274,18 +2413,20 @@ diff -up openssh-6.8p1/ssh-ldap-helper.8.ldap openssh-6.8p1/ssh-ldap-helper.8 +OpenSSH 5.5 + PKA-LDAP . +.Sh AUTHORS +.An Jan F. Chadima Aq jchadima@redhat.com -diff -up openssh-6.8p1/ssh-ldap-wrapper.ldap openssh-6.8p1/ssh-ldap-wrapper ---- openssh-6.8p1/ssh-ldap-wrapper.ldap 2015-03-18 11:11:29.033801457 +0100 -+++ openssh-6.8p1/ssh-ldap-wrapper 2015-03-18 11:11:29.033801457 +0100 +diff --git a/openssh-6.6p1/ssh-ldap-wrapper b/openssh-6.6p1/ssh-ldap-wrapper +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/ssh-ldap-wrapper @@ -0,0 +1,4 @@ +#!/bin/sh + -+exec /usr/libexec/openssh/ssh-ldap-helper -s "$1" ++exec @LIBEXECDIR@/ssh-ldap-helper -s "$1" + -diff -up openssh-6.8p1/ssh-ldap.conf.5.ldap openssh-6.8p1/ssh-ldap.conf.5 ---- openssh-6.8p1/ssh-ldap.conf.5.ldap 2015-03-18 11:11:29.033801457 +0100 -+++ openssh-6.8p1/ssh-ldap.conf.5 2015-03-18 11:11:29.033801457 +0100 -@@ -0,0 +1,385 @@ +diff --git a/openssh-6.6p1/ssh-ldap.conf.5 b/openssh-6.6p1/ssh-ldap.conf.5 +new file mode 100644 +--- /dev/null ++++ b/openssh-6.6p1/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. @@ -2644,17 +2785,8 @@ diff -up openssh-6.8p1/ssh-ldap.conf.5.ldap openssh-6.8p1/ssh-ldap.conf.5 +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 search. ++Specifies the user filter applied on the LDAP serch. +The default is no filter. -+.It Cm AccountClass -+Specifies the LDAP class used to find user accounts. -+The default is posixAccount. -+.It Cm search_format -+Specifies the user format of search string in LDAP substituting %u for user name -+and %f for additional ssh filter -+.Cm SSH_Filter -+(optional). -+The default value is (&(objectclass=%c)(objectclass=ldapPublicKey)(uid=%u)%f) +.El +.Sh FILES +.Bl -tag -width Ds @@ -2671,51 +2803,3 @@ diff -up openssh-6.8p1/ssh-ldap.conf.5.ldap openssh-6.8p1/ssh-ldap.conf.5 +OpenSSH 5.5 + PKA-LDAP . +.Sh AUTHORS +.An Jan F. Chadima Aq jchadima@redhat.com -diff --git a/openssh-lpk-openldap.ldif b/openssh-lpk-openldap.ldif -new file mode 100644 -index 0000000..9adf4b8 ---- /dev/null -+++ b/openssh-lpk-openldap.ldif -@@ -0,0 +1,19 @@ -+# -+# LDAP Public Key Patch schema for use with openssh-ldappubkey -+# useful with PKA-LDAP also -+# -+# Author: Eric AUGE -+# -+# LDIF for openLDAP Directory Server. -+# Based on the original schema, modified by Jakub Jelen. -+# -+ -+dn: cn=openssh-lpk,cn=schema,cn=config -+objectClass: olcSchemaConfig -+cn: openssh-lpk -+olcAttributeTypes: {0}( 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 ) -+olcObjectClasses: {0}( 1.3.6.1.4.1.24552.500.1.1.2.0 -+ NAME 'ldapPublicKey' DESC 'MANDATORY: OpenSSH LPK objectclass' -+ SUP top AUXILIARY MUST ( sshPublicKey $ uid ) ) -diff --git a/openssh-lpk-sun.ldif b/openssh-lpk-sun.ldif -new file mode 100644 -index 0000000..9adf4b8 ---- /dev/null -+++ b/openssh-lpk-sun.ldif -@@ -0,0 +1,17 @@ -+# -+# LDAP Public Key Patch schema for use with openssh-ldappubkey -+# useful with PKA-LDAP also -+# -+# Author: Eric AUGE -+# -+# LDIF for Sun Directory Server. -+# Based on the original schema, modified by Jakub Jelen. -+# -+ -+dn: cn=schema -+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 ) -+objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 -+ NAME 'ldapPublicKey' DESC 'MANDATORY: OpenSSH LPK objectclass' -+ SUP top AUXILIARY MUST ( sshPublicKey $ uid ) ) diff --git a/openssh-6.6p1-no_fork-no_pid_file.patch b/openssh-6.6p1-no_fork-no_pid_file.patch new file mode 100644 index 0000000..9ad6c49 --- /dev/null +++ b/openssh-6.6p1-no_fork-no_pid_file.patch @@ -0,0 +1,24 @@ +# Do not write a PID file when not daemonizing (e.g. when running from systemd) + +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/sshd.c +@@ -1994,17 +1994,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 (!debug_flag) { ++ if (!(debug_flag || no_daemon_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-6.6p1-pam-check-locks.patch b/openssh-6.6p1-pam-check-locks.patch index dacd3a5..1ac4580 100644 --- a/openssh-6.6p1-pam-check-locks.patch +++ b/openssh-6.6p1-pam-check-locks.patch @@ -2,11 +2,15 @@ # UsePAM is used # bnc#708678, FATE#312033 -Index: b/auth.c -=================================================================== ---- a/auth.c -+++ b/auth.c -@@ -109,7 +109,7 @@ allowed_user(struct passwd * pw) +diff --git a/openssh-6.6p1/auth.c b/openssh-6.6p1/auth.c +--- a/openssh-6.6p1/auth.c ++++ b/openssh-6.6p1/auth.c +@@ -103,17 +103,17 @@ allowed_user(struct passwd * pw) + 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; #ifdef USE_SHADOW @@ -15,7 +19,17 @@ Index: b/auth.c spw = getspnam(pw->pw_name); #ifdef HAS_SHADOW_EXPIRE if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) -@@ -129,7 +129,7 @@ allowed_user(struct passwd * pw) + return 0; + #endif /* HAS_SHADOW_EXPIRE */ + #endif /* USE_SHADOW */ + + /* grab passwd field for locked account check */ +@@ -123,17 +123,17 @@ allowed_user(struct passwd * pw) + #ifdef USE_LIBIAF + passwd = get_iaf_password(pw); + #else + passwd = spw->sp_pwdp; + #endif /* USE_LIBIAF */ #endif /* check for locked account */ @@ -24,11 +38,20 @@ Index: b/auth.c int locked = 0; #ifdef LOCKED_PASSWD_STRING -Index: b/servconf.c -=================================================================== ---- a/servconf.c -+++ b/servconf.c -@@ -74,6 +74,7 @@ initialize_server_options(ServerOptions + if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) + locked = 1; + #endif + #ifdef LOCKED_PASSWD_PREFIX + if (strncmp(passwd, LOCKED_PASSWD_PREFIX, +diff --git a/openssh-6.6p1/servconf.c b/openssh-6.6p1/servconf.c +--- a/openssh-6.6p1/servconf.c ++++ b/openssh-6.6p1/servconf.c +@@ -66,16 +66,17 @@ extern Buffer cfg; + + void + initialize_server_options(ServerOptions *options) + { + memset(options, 0, sizeof(*options)); /* Portable-specific options */ options->use_pam = -1; @@ -36,7 +59,17 @@ Index: b/servconf.c /* Standard Options */ options->num_ports = 0; -@@ -187,6 +188,8 @@ fill_default_server_options(ServerOption + options->ports_from_cmdline = 0; + options->listen_addrs = NULL; + options->address_family = -1; + options->num_host_key_files = 0; + options->num_host_cert_files = 0; +@@ -157,16 +158,18 @@ initialize_server_options(ServerOptions + } + + void + fill_default_server_options(ServerOptions *options) + { /* Portable-specific options */ if (options->use_pam == -1) options->use_pam = 0; @@ -45,16 +78,36 @@ Index: b/servconf.c /* Standard Options */ if (options->protocol == SSH_PROTO_UNKNOWN) -@@ -392,7 +395,7 @@ fill_default_server_options(ServerOption + options->protocol = SSH_PROTO_2; + if (options->num_host_key_files == 0) { + /* fill default hostkeys for protocols */ + if (options->protocol & SSH_PROTO_1) + options->host_key_files[options->num_host_key_files++] = +@@ -317,17 +320,17 @@ fill_default_server_options(ServerOption + #endif + + } + + /* Keyword tokens. */ typedef enum { sBadOption, /* == unknown option */ /* Portable-specific options */ - sUsePAM, + sUsePAM, sUsePAMChecklocks, /* Standard Options */ - sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, - sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel, -@@ -442,8 +445,10 @@ static struct { + sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, + sPermitRootLogin, sLogFacility, sLogLevel, + sRhostsRSAAuthentication, sRSAAuthentication, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, + sKerberosGetAFSToken, + sKerberosTgtPassing, sChallengeResponseAuthentication, + sPasswordAuthentication, sKbdInteractiveAuthentication, +@@ -362,18 +365,20 @@ typedef enum { + static struct { + const char *name; + ServerOpCodes opcode; + u_int flags; + } keywords[] = { /* Portable-specific options */ #ifdef USE_PAM { "usepam", sUsePAM, SSHCFG_GLOBAL }, @@ -65,7 +118,17 @@ Index: b/servconf.c #endif { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, /* Standard Options */ -@@ -1004,6 +1009,9 @@ process_server_config_line(ServerOptions + { "port", sPort, SSHCFG_GLOBAL }, + { "hostkey", sHostKeyFile, SSHCFG_GLOBAL }, + { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */ + { "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL }, + { "pidfile", sPidFile, SSHCFG_GLOBAL }, +@@ -870,16 +875,19 @@ process_server_config_line(ServerOptions + } + } + + switch (opcode) { + /* Portable-specific options */ case sUsePAM: intptr = &options->use_pam; goto parse_flag; @@ -75,11 +138,20 @@ Index: b/servconf.c /* Standard Options */ case sBadOption: -Index: b/servconf.h -=================================================================== ---- a/servconf.h -+++ b/servconf.h -@@ -173,6 +173,7 @@ typedef struct { + return -1; + case sPort: + /* ignore ports from configfile if cmdline specifies ports */ + if (options->ports_from_cmdline) + return 0; +diff --git a/openssh-6.6p1/servconf.h b/openssh-6.6p1/servconf.h +--- a/openssh-6.6p1/servconf.h ++++ b/openssh-6.6p1/servconf.h +@@ -160,16 +160,17 @@ typedef struct { + */ + + u_int num_authkeys_files; /* Files containing public keys */ + char *authorized_keys_files[MAX_AUTHKEYS_FILES]; + char *adm_forced_command; int use_pam; /* Enable auth via PAM */ @@ -87,13 +159,22 @@ Index: b/servconf.h int permit_tun; -Index: b/sshd_config.0 -=================================================================== ---- a/sshd_config.0 -+++ b/sshd_config.0 -@@ -950,6 +950,14 @@ DESCRIPTION + int num_permitted_opens; + + char *chroot_directory; + char *revoked_keys_file; + char *trusted_user_ca_keys; +diff --git a/openssh-6.6p1/sshd_config.0 b/openssh-6.6p1/sshd_config.0 +--- a/openssh-6.6p1/sshd_config.0 ++++ b/openssh-6.6p1/sshd_config.0 +@@ -728,16 +728,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 M-bM-^@M-^\noM-bM-^@M-^]. + non-root user. The default is ``no''. + UsePAMCheckLocks + When set to ``yes'', the checks whether the account has been @@ -106,11 +187,20 @@ Index: b/sshd_config.0 UsePrivilegeSeparation Specifies whether sshd(8) separates privileges by creating an unprivileged child process to deal with incoming network traffic. -Index: b/sshd_config.5 -=================================================================== ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -1574,6 +1574,18 @@ is enabled, you will not be able to run + 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 + default is ``yes''. If UsePrivilegeSeparation is set to +diff --git a/openssh-6.6p1/sshd_config.5 b/openssh-6.6p1/sshd_config.5 +--- a/openssh-6.6p1/sshd_config.5 ++++ b/openssh-6.6p1/sshd_config.5 +@@ -1214,16 +1214,28 @@ or + .Pp + If + .Cm UsePAM + is enabled, you will not be able to run + .Xr sshd 8 as a non-root user. The default is .Dq no . @@ -129,3 +219,8 @@ Index: b/sshd_config.5 .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-6.6p1-seccomp_getuid.patch b/openssh-6.6p1-seccomp_getuid.patch index 328f37b..28efbcd 100644 --- a/openssh-6.6p1-seccomp_getuid.patch +++ b/openssh-6.6p1-seccomp_getuid.patch @@ -3,20 +3,27 @@ add 'getuid' syscall to list of allowed ones to prevent the sanboxed thread from being killed by the seccomp filter -Index: b/sandbox-seccomp-filter.c -=================================================================== ---- a/sandbox-seccomp-filter.c -+++ b/sandbox-seccomp-filter.c -@@ -147,6 +147,12 @@ static const struct sock_filter preauth_ - #ifdef __NR_getpid +diff --git a/openssh-6.6p1/sandbox-seccomp-filter.c b/openssh-6.6p1/sandbox-seccomp-filter.c +--- a/openssh-6.6p1/sandbox-seccomp-filter.c ++++ b/openssh-6.6p1/sandbox-seccomp-filter.c +@@ -85,16 +85,20 @@ static const struct sock_filter preauth_ + offsetof(struct seccomp_data, arch)), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL), + /* Load the syscall number for checking. */ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, + offsetof(struct seccomp_data, nr)), + SC_DENY(open, EACCES), SC_ALLOW(getpid), - #endif -+#ifdef __NR_getuid + SC_ALLOW(getuid), -+#endif +#ifdef __NR_getuid32 + SC_ALLOW(getuid32), +#endif - #ifdef __NR_gettimeofday SC_ALLOW(gettimeofday), + SC_ALLOW(clock_gettime), + #ifdef __NR_time /* not defined on EABI ARM */ + SC_ALLOW(time), #endif + SC_ALLOW(read), + SC_ALLOW(write), + SC_ALLOW(close), diff --git a/openssh-6.6p1-seed-prng.patch b/openssh-6.6p1-seed-prng.patch index 257f497..9a99148 100644 --- a/openssh-6.6p1-seed-prng.patch +++ b/openssh-6.6p1-seed-prng.patch @@ -1,11 +1,15 @@ # extended support for (re-)seeding the OpenSSL PRNG from /dev/random # bnc#703221, FATE#312172 -Index: b/audit-bsm.c -=================================================================== ---- a/audit-bsm.c -+++ b/audit-bsm.c -@@ -509,4 +509,10 @@ audit_generate_ephemeral_server_key(cons +diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c +--- a/openssh-6.6p1/audit-bsm.c ++++ b/openssh-6.6p1/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 */ } @@ -16,11 +20,15 @@ Index: b/audit-bsm.c + /* not implemented */ +} #endif /* BSM */ -Index: b/audit-linux.c -=================================================================== ---- a/audit-linux.c -+++ b/audit-linux.c -@@ -407,4 +407,26 @@ audit_generate_ephemeral_server_key(cons +diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c +--- a/openssh-6.6p1/audit-linux.c ++++ b/openssh-6.6p1/audit-linux.c +@@ -398,9 +398,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"); } @@ -47,11 +55,15 @@ Index: b/audit-linux.c + error("cannot write into audit"); +} #endif /* USE_LINUX_AUDIT */ -Index: b/audit.c -=================================================================== ---- a/audit.c -+++ b/audit.c -@@ -309,5 +309,11 @@ audit_generate_ephemeral_server_key(cons +diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c +--- a/openssh-6.6p1/audit.c ++++ b/openssh-6.6p1/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); } @@ -63,22 +75,30 @@ Index: b/audit.c +} # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ #endif /* SSH_AUDIT_EVENTS */ -Index: b/audit.h -=================================================================== ---- a/audit.h -+++ b/audit.h -@@ -68,5 +68,6 @@ void audit_session_key_free(int ctos); +diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h +--- a/openssh-6.6p1/audit.h ++++ b/openssh-6.6p1/audit.h +@@ -63,10 +63,11 @@ void audit_key(int, int *, const Key *); + void audit_unsupported(int); + void audit_kex(int, char *, char *, char *); + void audit_unsupported_body(int); + void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); + void audit_session_key_free(int ctos); void audit_session_key_free_body(int ctos, pid_t, uid_t); void audit_destroy_sensitive_data(const char *, pid_t, uid_t); void audit_generate_ephemeral_server_key(const char *); +void audit_linux_prng_seed(long, const char *); #endif /* _SSH_AUDIT_H */ -Index: b/entropy.c -=================================================================== ---- a/entropy.c -+++ b/entropy.c -@@ -54,6 +54,7 @@ +diff --git a/openssh-6.6p1/entropy.c b/openssh-6.6p1/entropy.c +--- a/openssh-6.6p1/entropy.c ++++ b/openssh-6.6p1/entropy.c +@@ -45,16 +45,17 @@ + + #include "ssh.h" + #include "misc.h" + #include "xmalloc.h" + #include "atomicio.h" #include "pathnames.h" #include "log.h" #include "buffer.h" @@ -86,7 +106,17 @@ Index: b/entropy.c /* * Portable OpenSSH PRNG seeding: -@@ -229,6 +230,9 @@ seed_rng(void) + * 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 +@@ -229,11 +230,14 @@ 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 */ @@ -96,23 +126,32 @@ Index: b/entropy.c if (RAND_status() != 1) fatal("PRNG is not seeded"); } -Index: b/openbsd-compat/Makefile.in -=================================================================== ---- a/openbsd-compat/Makefile.in -+++ b/openbsd-compat/Makefile.in -@@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf +diff --git a/openssh-6.6p1/openbsd-compat/Makefile.in b/openssh-6.6p1/openbsd-compat/Makefile.in +--- a/openssh-6.6p1/openbsd-compat/Makefile.in ++++ b/openssh-6.6p1/openbsd-compat/Makefile.in +@@ -15,17 +15,17 @@ AR=@AR@ + RANLIB=@RANLIB@ + INSTALL=@INSTALL@ + LDFLAGS=-L. @LDFLAGS@ - 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 + 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 realpath.o rresvport.o setenv.o setproctitle.o sha2.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 -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 $< -Index: b/openbsd-compat/port-linux-prng.c -=================================================================== + + all: libopenbsd-compat.a + + $(COMPAT): ../config.h + $(OPENBSD): ../config.h +diff --git a/openssh-6.6p1/openbsd-compat/port-linux-prng.c b/openssh-6.6p1/openbsd-compat/port-linux-prng.c +new file mode 100644 --- /dev/null -+++ b/openbsd-compat/port-linux-prng.c ++++ b/openssh-6.6p1/openbsd-compat/port-linux-prng.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 Jan F. Chadima @@ -193,11 +232,15 @@ Index: b/openbsd-compat/port-linux-prng.c + fatal ("EOF reading %s", random); + } +} -Index: b/openbsd-compat/port-linux.h -=================================================================== ---- a/openbsd-compat/port-linux.h -+++ b/openbsd-compat/port-linux.h -@@ -19,6 +19,10 @@ +diff --git a/openssh-6.6p1/openbsd-compat/port-linux.h b/openssh-6.6p1/openbsd-compat/port-linux.h +--- a/openssh-6.6p1/openbsd-compat/port-linux.h ++++ b/openssh-6.6p1/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 @@ -208,11 +251,20 @@ Index: b/openbsd-compat/port-linux.h #ifdef WITH_SELINUX int ssh_selinux_enabled(void); void ssh_selinux_setup_pty(char *, const char *); -Index: b/ssh-add.1 -=================================================================== ---- a/ssh-add.1 -+++ b/ssh-add.1 -@@ -171,6 +171,20 @@ to make this work.) + 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-6.6p1/ssh-add.1 b/openssh-6.6p1/ssh-add.1 +--- a/openssh-6.6p1/ssh-add.1 ++++ b/openssh-6.6p1/ssh-add.1 +@@ -156,16 +156,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. @@ -233,11 +285,20 @@ Index: b/ssh-add.1 .El .Sh FILES .Bl -tag -width Ds -Index: b/ssh-agent.1 -=================================================================== ---- a/ssh-agent.1 -+++ b/ssh-agent.1 -@@ -194,6 +194,23 @@ sockets used to contain the connection t + .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-6.6p1/ssh-agent.1 b/openssh-6.6p1/ssh-agent.1 +--- a/openssh-6.6p1/ssh-agent.1 ++++ b/openssh-6.6p1/ssh-agent.1 +@@ -196,16 +196,33 @@ Contains the protocol version 2 ED25519 + .It Pa ~/.ssh/id_rsa + Contains the protocol version 2 RSA authentication identity of the user. + .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 @@ -261,11 +322,20 @@ Index: b/ssh-agent.1 .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , -Index: b/ssh-keygen.1 -=================================================================== ---- a/ssh-keygen.1 -+++ b/ssh-keygen.1 -@@ -842,6 +842,23 @@ Contains Diffie-Hellman groups used for + .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-6.6p1/ssh-keygen.1 b/openssh-6.6p1/ssh-keygen.1 +--- a/openssh-6.6p1/ssh-keygen.1 ++++ b/openssh-6.6p1/ssh-keygen.1 +@@ -827,16 +827,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 @@ -289,11 +359,20 @@ Index: b/ssh-keygen.1 .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , -Index: b/ssh-keysign.8 -=================================================================== ---- a/ssh-keysign.8 -+++ b/ssh-keysign.8 -@@ -80,6 +80,23 @@ must be set-uid root if host-based authe + .Xr ssh-agent 1 , + .Xr moduli 5 , + .Xr sshd 8 + .Rs + .%R RFC 4716 +diff --git a/openssh-6.6p1/ssh-keysign.8 b/openssh-6.6p1/ssh-keysign.8 +--- a/openssh-6.6p1/ssh-keysign.8 ++++ b/openssh-6.6p1/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 @@ -317,11 +396,20 @@ Index: b/ssh-keysign.8 .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-keygen 1 , -Index: b/ssh.1 -=================================================================== ---- a/ssh.1 -+++ b/ssh.1 -@@ -1415,6 +1415,20 @@ For more information, see the + .Xr ssh_config 5 , + .Xr sshd 8 + .Sh HISTORY + .Nm + first appeared in +diff --git a/openssh-6.6p1/ssh.1 b/openssh-6.6p1/ssh.1 +--- a/openssh-6.6p1/ssh.1 ++++ b/openssh-6.6p1/ssh.1 +@@ -1304,16 +1304,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 . @@ -342,11 +430,20 @@ Index: b/ssh.1 .Sh FILES .Bl -tag -width Ds -compact .It Pa ~/.rhosts -Index: b/sshd.8 -=================================================================== ---- a/sshd.8 -+++ b/sshd.8 -@@ -944,6 +944,23 @@ concurrently for different ports, this c + 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-6.6p1/sshd.8 b/openssh-6.6p1/sshd.8 +--- a/openssh-6.6p1/sshd.8 ++++ b/openssh-6.6p1/sshd.8 +@@ -946,16 +946,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 @@ -370,11 +467,20 @@ Index: b/sshd.8 .Sh SEE ALSO .Xr scp 1 , .Xr sftp 1 , -Index: b/sshd.c -=================================================================== ---- a/sshd.c -+++ b/sshd.c -@@ -55,6 +55,8 @@ + .Xr ssh 1 , + .Xr ssh-add 1 , + .Xr ssh-agent 1 , + .Xr ssh-keygen 1 , + .Xr ssh-keyscan 1 , +diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c +--- a/openssh-6.6p1/sshd.c ++++ b/openssh-6.6p1/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" @@ -383,7 +489,17 @@ Index: b/sshd.c #include #include -@@ -214,6 +216,13 @@ struct { + #include + #include + #ifdef HAVE_PATHS_H + #include + #endif +@@ -218,16 +220,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; /* @@ -397,7 +513,17 @@ Index: b/sshd.c * Flag indicating whether the RSA server key needs to be regenerated. * Is set in the SIGALRM handler and cleared when the key is regenerated. */ -@@ -1400,6 +1409,11 @@ server_accept_loop(int *sock_in, int *so + 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; +@@ -1322,16 +1331,21 @@ 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; } @@ -409,3 +535,8 @@ Index: b/sshd.c /* * 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-6.6p1-sftp_force_permissions.patch b/openssh-6.6p1-sftp_force_permissions.patch index e1a6c5c..697662c 100644 --- a/openssh-6.6p1-sftp_force_permissions.patch +++ b/openssh-6.6p1-sftp_force_permissions.patch @@ -3,11 +3,15 @@ # http://lists.mindrot.org/pipermail/openssh-unix-dev/2010-November/029044.html # http://marc.info/?l=openssh-unix-dev&m=128896838930893 -Index: b/sftp-server.8 -=================================================================== ---- a/sftp-server.8 -+++ b/sftp-server.8 -@@ -38,6 +38,7 @@ +diff --git a/openssh-6.6p1/sftp-server.8 b/openssh-6.6p1/sftp-server.8 +--- a/openssh-6.6p1/sftp-server.8 ++++ b/openssh-6.6p1/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 @@ -15,7 +19,17 @@ Index: b/sftp-server.8 .Ek .Nm .Fl Q Ar protocol_feature -@@ -138,6 +139,10 @@ Sets an explicit + .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. @@ -25,12 +39,21 @@ Index: b/sftp-server.8 +777, 755, 750, 666, 644, 640, etc. Option -u is ineffective if -m is set. .El .Pp - On some systems, -Index: b/sftp-server.c -=================================================================== ---- a/sftp-server.c -+++ b/sftp-server.c -@@ -78,6 +78,10 @@ static int readonly; + For logging to work, + .Nm + must be able to access + .Pa /dev/log . + Use of + .Nm +diff --git a/openssh-6.6p1/sftp-server.c b/openssh-6.6p1/sftp-server.c +--- a/openssh-6.6p1/sftp-server.c ++++ b/openssh-6.6p1/sftp-server.c +@@ -75,16 +75,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; @@ -41,18 +64,38 @@ Index: b/sftp-server.c /* portable attributes, etc. */ typedef struct Stat Stat; -@@ -692,6 +696,10 @@ process_open(u_int32_t id) + struct Stat { + char *name; + char *long_name; + Attrib attrib; + }; +@@ -670,16 +674,20 @@ process_open(u_int32_t id) + int handle, fd, flags, mode, status = SSH2_FX_FAILURE; + + name = get_string(NULL); + pflags = get_int(); /* portable flags */ debug3("request %u: open flags %d", id, pflags); + a = get_attrib(); 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 */ -+ } + 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 && -@@ -1494,7 +1502,8 @@ sftp_server_usage(void) + ((flags & O_ACCMODE) == O_WRONLY || + (flags & O_ACCMODE) == O_RDWR)) { + verbose("Refusing open request in read-only mode"); + status = SSH2_FX_PERMISSION_DENIED; + } else { +@@ -1425,17 +1433,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] " @@ -62,7 +105,17 @@ Index: b/sftp-server.c " %s -Q protocol_feature\n", __progname, __progname); exit(1); -@@ -1519,7 +1528,7 @@ sftp_server_main(int argc, char **argv, + } + + int + sftp_server_main(int argc, char **argv, struct passwd *user_pw) + { +@@ -1450,17 +1459,17 @@ sftp_server_main(int argc, char **argv, + extern char *__progname; + + __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, @@ -71,7 +124,17 @@ Index: b/sftp-server.c switch (ch) { case 'Q': if (strcasecmp(optarg, "requests") != 0) { -@@ -1579,6 +1588,13 @@ sftp_server_main(int argc, char **argv, + fprintf(stderr, "Invalid query type\n"); + exit(1); + } + for (i = 0; handlers[i].handler != NULL; i++) + printf("%s\n", handlers[i].name); +@@ -1510,16 +1519,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; @@ -85,3 +148,8 @@ Index: b/sftp-server.c case 'h': default: sftp_server_usage(); + } + } + + log_init(__progname, log_level, log_facility, log_stderr); + diff --git a/openssh-6.6p1-sftp_homechroot.patch b/openssh-6.6p1-sftp_homechroot.patch index e9af539..71f9c83 100644 --- a/openssh-6.6p1-sftp_homechroot.patch +++ b/openssh-6.6p1-sftp_homechroot.patch @@ -1,10 +1,14 @@ # run sftp sessions inside a chroot -Index: b/session.c -=================================================================== ---- a/session.c -+++ b/session.c -@@ -127,6 +127,8 @@ void do_child(Session *, const char *); +diff --git a/openssh-6.6p1/session.c b/openssh-6.6p1/session.c +--- a/openssh-6.6p1/session.c ++++ b/openssh-6.6p1/session.c +@@ -120,16 +120,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 *); @@ -13,7 +17,17 @@ Index: b/session.c static void do_authenticated1(Authctxt *); static void do_authenticated2(Authctxt *); -@@ -816,6 +818,11 @@ do_exec(Session *s, const char *command) + static int session_pty_req(Session *); + + /* import */ + extern ServerOptions options; + extern char *__progname; +@@ -827,16 +829,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"); } @@ -25,78 +39,95 @@ Index: b/session.c if (s->ttyfd != -1) { tty = s->tty; if (strncmp(tty, "/dev/", 5) == 0) -@@ -1453,6 +1460,62 @@ do_nologin(struct passwd *pw) + tty += 5; + } + + verbose("Starting session: %s%s%s for %s from %.200s port %d", + session_type, +@@ -1463,67 +1470,132 @@ 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; ++ 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"); -+ } ++ 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. */ -@@ -1462,6 +1525,7 @@ safely_chroot(const char *path, uid_t ui + static void + safely_chroot(const char *path, uid_t uid) + { const char *cp; - char component[PATH_MAX]; + char component[MAXPATHLEN]; struct stat st; + int last; if (*path != '/') fatal("chroot path does not begin at root"); -@@ -1473,7 +1537,7 @@ safely_chroot(const char *path, uid_t ui + 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;) { @@ -105,7 +136,12 @@ Index: b/session.c strlcpy(component, path, sizeof(component)); else { cp++; -@@ -1486,7 +1550,7 @@ safely_chroot(const char *path, uid_t ui + 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)); @@ -114,24 +150,40 @@ Index: b/session.c fatal("bad ownership or modes for chroot " "directory %s\"%s\"", cp == NULL ? "" : "component ", component); -@@ -1495,6 +1559,13 @@ safely_chroot(const char *path, uid_t ui + 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\": " -Index: b/sftp-chrootenv.h -=================================================================== + "%s", path, strerror(errno)); + if (chroot(path) == -1) + fatal("chroot(\"%s\"): %s", path, strerror(errno)); + if (chdir("/") == -1) + fatal("%s: chdir(/) after chroot: %s", + __func__, strerror(errno)); ++ + verbose("Changed root directory to \"%s\"", path); + } + + /* Set login name, uid, gid, and groups. */ + void + do_setusercontext(struct passwd *pw) + { + char *chroot_path, *tmp; +diff --git a/openssh-6.6p1/sftp-chrootenv.h b/openssh-6.6p1/sftp-chrootenv.h +new file mode 100644 --- /dev/null -+++ b/sftp-chrootenv.h ++++ b/openssh-6.6p1/sftp-chrootenv.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009 Jan F Chadima. All rights reserved. @@ -163,11 +215,15 @@ Index: b/sftp-chrootenv.h + +#endif + -Index: b/sftp-common.c -=================================================================== ---- a/sftp-common.c -+++ b/sftp-common.c -@@ -48,6 +48,7 @@ +diff --git a/openssh-6.6p1/sftp-common.c b/openssh-6.6p1/sftp-common.c +--- a/openssh-6.6p1/sftp-common.c ++++ b/openssh-6.6p1/sftp-common.c +@@ -42,16 +42,17 @@ + #endif + + #include "xmalloc.h" + #include "buffer.h" + #include "log.h" #include "sftp.h" #include "sftp-common.h" @@ -175,7 +231,17 @@ Index: b/sftp-common.c /* Clear contents of attributes structure */ void -@@ -221,13 +222,13 @@ ls_file(const char *name, const struct s + attrib_clear(Attrib *a) + { + a->flags = 0; + a->size = 0; + a->uid = 0; +@@ -193,23 +194,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); @@ -191,11 +257,20 @@ Index: b/sftp-common.c group = group_from_gid(st->st_gid, 0); } else { snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); -Index: b/sftp-server-main.c -=================================================================== ---- a/sftp-server-main.c -+++ b/sftp-server-main.c -@@ -22,11 +22,14 @@ + group = gbuf; + } + if (ltime != NULL) { + now = time(NULL); + if (now - (365*24*60*60)/2 < st->st_mtime && +diff --git a/openssh-6.6p1/sftp-server-main.c b/openssh-6.6p1/sftp-server-main.c +--- a/openssh-6.6p1/sftp-server-main.c ++++ b/openssh-6.6p1/sftp-server-main.c +@@ -17,21 +17,24 @@ + + #include "includes.h" + + #include + #include #include #include #include @@ -210,11 +285,20 @@ Index: b/sftp-server-main.c void cleanup_exit(int i) { -Index: b/sftp.c -=================================================================== ---- a/sftp.c -+++ b/sftp.c -@@ -117,6 +117,8 @@ int remote_glob(struct sftp_conn *, cons + sftp_server_cleanup_exit(i); + } + + int + main(int argc, char **argv) +diff --git a/openssh-6.6p1/sftp.c b/openssh-6.6p1/sftp.c +--- a/openssh-6.6p1/sftp.c ++++ b/openssh-6.6p1/sftp.c +@@ -109,16 +109,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; @@ -223,13 +307,22 @@ Index: b/sftp.c /* Separators for interactive commands */ #define WHITESPACE " \t\r\n" -Index: b/sshd_config.0 -=================================================================== ---- a/sshd_config.0 -+++ b/sshd_config.0 -@@ -258,6 +258,14 @@ DESCRIPTION - (especially those outside the jail). Misconfiguration can lead - to unsafe environments which sshd(8) cannot detect. + /* 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-6.6p1/sshd_config.0 b/openssh-6.6p1/sshd_config.0 +--- a/openssh-6.6p1/sshd_config.0 ++++ b/openssh-6.6p1/sshd_config.0 +@@ -189,16 +189,24 @@ DESCRIPTION + session this requires at least a shell, typically sh(1), and + basic /dev nodes such as null(4), zero(4), stdin(4), stdout(4), + stderr(4), arandom(4) and tty(4) devices. For file transfer + sessions using ``sftp'', no additional configuration of the + environment is necessary if the in-process sftp server is used, + though sessions which use logging do require /dev/log inside the + chroot directory (see sftp-server(8) for details). + In the special case when only sftp is used, not ssh nor scp, it + is possible to use ChrootDirectory %h or ChrootDirectory @@ -242,11 +335,20 @@ Index: b/sshd_config.0 The default is not to chroot(2). Ciphers -Index: b/sshd_config.5 -=================================================================== ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -421,6 +421,17 @@ inside the chroot directory on some oper + Specifies the ciphers allowed for protocol version 2. Multiple + ciphers must be comma-separated. The supported ciphers are: + + ``3des-cbc'', ``aes128-cbc'', ``aes192-cbc'', ``aes256-cbc'', + ``aes128-ctr'', ``aes192-ctr'', ``aes256-ctr'', +diff --git a/openssh-6.6p1/sshd_config.5 b/openssh-6.6p1/sshd_config.5 +--- a/openssh-6.6p1/sshd_config.5 ++++ b/openssh-6.6p1/sshd_config.5 +@@ -324,16 +324,27 @@ For file transfer sessions using + no additional configuration of the environment is necessary if the + in-process sftp server is used, + though sessions which use logging do require + .Pa /dev/log + inside the chroot directory (see .Xr sftp-server 8 for details). .Pp @@ -261,6 +363,11 @@ Index: b/sshd_config.5 +must fulfill the usual conditions. No aditional files are required to be present +in the directory. +.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). + The default is not to + .Xr chroot 2 . + .It Cm Ciphers + Specifies the ciphers allowed for protocol version 2. + Multiple ciphers must be comma-separated. + The supported ciphers are: + .Pp + .Dq 3des-cbc , diff --git a/openssh-6.6p1.tar.gz b/openssh-6.6p1.tar.gz new file mode 100644 index 0000000..f9e5859 --- /dev/null +++ b/openssh-6.6p1.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:48c1f0664b4534875038004cc4f3555b8329c2a81c1df48db5c517800de203bb +size 1282502 diff --git a/openssh-6.6p1.tar.gz.asc b/openssh-6.6p1.tar.gz.asc new file mode 100644 index 0000000..defd54e --- /dev/null +++ b/openssh-6.6p1.tar.gz.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (OpenBSD) + +iQGlAwUAUyEVxtPl9Wttkg0wAQr39wx/SkCPbWVsEG2Do7IXKg1FudhKIt8QGQZC +4bNvnwFbFZ/RNEv+BZRKH7AmgNLXn6/VTlRkifF3osrvJ6gh8EfQMkNPB5WcRz5h +c4KdAcL6u/KFxku0x/hjqUaAV980HlUFvAmGv3/YTL8n14uRBRlrVCnG5q1LmIv7 +piBnb+FrAivrNV+PUMkkrC6XKrfR2ns+ZtfgwBQGQ/VuJTQZPOUMp/GLViHBxz4l +G0H52bolzAIunzBxXF9fWwFU8JFtCEharFr7jYuLQzViUPCaf3L9w3yPb2S24wnU +772CEyGbdCJVLmtD9ObaNKk0We6hdc6Dz+mx/JbHkoWSw0LYdHFbjFR75vjNENYh +evRgqLCP91micfhZDQqX6tOLnMfBjxCjHsCYvMlDACiEvxb1Ct6Fm9m1lXIGUsh3 +ssScaCvQItMAvQdjQOdCXS7Zcucfzzx3Fd8Q2X/h2R81yYv6JjYQy7aBV/DaFDzP +/BhCwnq5sP6XW6rHRZGYXhMaAEjZml8ySRFEzW+esnGf9vSJgnQ+Kw== +=H2K/ +-----END PGP SIGNATURE----- diff --git a/openssh-6.7p1-audit.patch b/openssh-6.7p1-audit.patch deleted file mode 100644 index 3d0e959..0000000 --- a/openssh-6.7p1-audit.patch +++ /dev/null @@ -1,2360 +0,0 @@ -Index: openssh-7.1p2/audit-bsm.c -=================================================================== ---- openssh-7.1p2.orig/audit-bsm.c -+++ openssh-7.1p2/audit-bsm.c -@@ -375,10 +375,23 @@ audit_connection_from(const char *host, - #endif - } - --void -+int - audit_run_command(const char *command) - { - /* not implemented */ -+ return 0; -+} -+ -+void -+audit_end_command(int handle, const char *command) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_count_session_open(void) -+{ -+ /* not necessary */ - } - - void -@@ -393,6 +406,12 @@ audit_session_close(struct logininfo *li - /* not implemented */ - } - -+int -+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) -+{ -+ /* not implemented */ -+} -+ - void - audit_event(ssh_audit_event_t event) - { -@@ -454,4 +473,40 @@ audit_event(ssh_audit_event_t event) - debug("%s: unhandled event %d", __func__, event); - } - } -+ -+void -+audit_unsupported_body(int what) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, 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 */ -Index: openssh-7.1p2/audit.c -=================================================================== ---- openssh-7.1p2.orig/audit.c -+++ openssh-7.1p2/audit.c -@@ -28,6 +28,7 @@ - - #include - #include -+#include - - #ifdef SSH_AUDIT_EVENTS - -@@ -36,6 +37,11 @@ - #include "key.h" - #include "hostfile.h" - #include "auth.h" -+#include "ssh-gss.h" -+#include "monitor_wrap.h" -+#include "xmalloc.h" -+#include "misc.h" -+#include "servconf.h" - - /* - * Care must be taken when using this since it WILL NOT be initialized when -@@ -43,6 +49,7 @@ - * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. - */ - extern Authctxt *the_authctxt; -+extern ServerOptions options; - - /* Maybe add the audit class to struct Authmethod? */ - ssh_audit_event_t -@@ -71,13 +78,10 @@ audit_classify_auth(const char *method) - const char * - audit_username(void) - { -- static const char unknownuser[] = "(unknown user)"; -- static const char invaliduser[] = "(invalid user)"; -+ static const char unknownuser[] = "(unknown)"; - -- if (the_authctxt == NULL || the_authctxt->user == NULL) -+ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) - return (unknownuser); -- if (!the_authctxt->valid) -- return (invaliduser); - return (the_authctxt->user); - } - -@@ -111,6 +115,40 @@ audit_event_lookup(ssh_audit_event_t ev) - return(event_lookup[i].name); - } - -+void -+audit_key(int host_user, int *rv, const Key *key) -+{ -+ char *fp; -+ const char *crypto_name; -+ -+ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); -+ if (key->type == KEY_RSA1) -+ crypto_name = "ssh-rsa1"; -+ else -+ crypto_name = key_ssh_name(key); -+ if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0) -+ *rv = 0; -+ free(fp); -+} -+ -+void -+audit_unsupported(int what) -+{ -+ PRIVSEP(audit_unsupported_body(what)); -+} -+ -+void -+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) -+{ -+ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid())); -+} -+ -+void -+audit_session_key_free(int ctos) -+{ -+ PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid())); -+} -+ - # ifndef CUSTOM_SSH_AUDIT_EVENTS - /* - * Null implementations of audit functions. -@@ -140,6 +178,17 @@ audit_event(ssh_audit_event_t event) - } - - /* -+ * Called when a child process has called, or will soon call, -+ * audit_session_open. -+ */ -+void -+audit_count_session_open(void) -+{ -+ debug("audit count session open euid %d user %s", geteuid(), -+ audit_username()); -+} -+ -+/* - * Called when a user session is started. Argument is the tty allocated to - * the session, or NULL if no tty was allocated. - * -@@ -174,13 +223,91 @@ audit_session_close(struct logininfo *li - /* - * This will be called when a user runs a non-interactive command. Note that - * it may be called multiple times for a single connection since SSH2 allows -- * multiple sessions within a single connection. -+ * multiple sessions within a single connection. Returns a "handle" for -+ * audit_end_command. - */ --void -+int - audit_run_command(const char *command) - { - debug("audit run command euid %d user %s command '%.200s'", geteuid(), - audit_username(), command); -+ return 0; -+} -+ -+/* -+ * This will be called when the non-interactive command finishes. Note that -+ * it may be called multiple times for a single connection since SSH2 allows -+ * multiple sessions within a single connection. "handle" should come from -+ * the corresponding audit_run_command. -+ */ -+void -+audit_end_command(int handle, const char *command) -+{ -+ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), -+ audit_username(), command); -+} -+ -+/* -+ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. -+ * -+ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. -+ */ -+int -+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) -+{ -+ debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", -+ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, -+ 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 */ -Index: openssh-7.1p2/audit.h -=================================================================== ---- openssh-7.1p2.orig/audit.h -+++ openssh-7.1p2/audit.h -@@ -28,6 +28,7 @@ - # define _SSH_AUDIT_H - - #include "loginrec.h" -+#include "key.h" - - enum ssh_audit_event_type { - SSH_LOGIN_EXCEED_MAXTRIES, -@@ -47,11 +48,25 @@ enum ssh_audit_event_type { - }; - typedef enum ssh_audit_event_type ssh_audit_event_t; - -+int listening_for_clients(void); -+ - void audit_connection_from(const char *, int); - void audit_event(ssh_audit_event_t); -+void audit_count_session_open(void); - void audit_session_open(struct logininfo *); - void audit_session_close(struct logininfo *); --void audit_run_command(const char *); -+int audit_run_command(const char *); -+void audit_end_command(int, const char *); - ssh_audit_event_t audit_classify_auth(const char *); -+int audit_keyusage(int, const char *, unsigned, char *, int); -+void audit_key(int, int *, const Key *); -+void audit_unsupported(int); -+void audit_kex(int, char *, char *, char *, 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 */ -Index: openssh-7.1p2/audit-linux.c -=================================================================== ---- openssh-7.1p2.orig/audit-linux.c -+++ openssh-7.1p2/audit-linux.c -@@ -35,13 +35,25 @@ - - #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; - -@@ -49,11 +61,11 @@ linux_audit_record_event(int uid, const - if (audit_fd < 0) { - if (errno == EINVAL || errno == EPROTONOSUPPORT || - errno == EAFNOSUPPORT) -- return 1; /* No audit support in kernel */ -+ return; /* No audit support in kernel */ - else -- return 0; /* Must prevent login */ -+ goto fatal_report; /* Must prevent login */ - } -- rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, -+ rc = audit_log_acct_message(audit_fd, event, - NULL, "login", username ? username : "(unknown)", - username == NULL ? uid : -1, hostname, ip, ttyn, success); - saved_errno = errno; -@@ -65,35 +77,154 @@ linux_audit_record_event(int uid, const - 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 */ -+} - --void -+int - audit_run_command(const char *command) - { -- /* not implemented */ -+ if (!user_login_count++) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGIN); -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_START); -+ return 0; -+} -+ -+void -+audit_end_command(int handle, const char *command) -+{ -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_END); -+ if (user_login_count && !--user_login_count) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGOUT); -+} -+ -+void -+audit_count_session_open(void) -+{ -+ user_login_count++; - } - - void - audit_session_open(struct logininfo *li) - { -- if (linux_audit_record_event(li->uid, NULL, li->hostname, -- NULL, li->line, 1) == 0) -- fatal("linux_audit_write_entry failed: %s", strerror(errno)); -+ if (!user_login_count++) -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_LOGIN); -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_START); - } - - void - audit_session_close(struct logininfo *li) - { -- /* not implemented */ -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_END); -+ if (user_login_count && !--user_login_count) -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_LOGOUT); - } - - void -@@ -101,21 +232,43 @@ audit_event(ssh_audit_event_t event) - { - switch(event) { - case SSH_AUTH_SUCCESS: -- case SSH_CONNECTION_CLOSE: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 1, event); -+ break; -+ - case SSH_NOLOGIN: -- case SSH_LOGIN_EXCEED_MAXTRIES: - case SSH_LOGIN_ROOT_DENIED: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, event); -+ linux_audit_user_logxxx(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); - break; - -+ case SSH_LOGIN_EXCEED_MAXTRIES: - case SSH_AUTH_FAIL_NONE: - case SSH_AUTH_FAIL_PASSWD: - case SSH_AUTH_FAIL_KBDINT: - case SSH_AUTH_FAIL_PUBKEY: - case SSH_AUTH_FAIL_HOSTBASED: - case SSH_AUTH_FAIL_GSSAPI: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, event); -+ break; -+ -+ case SSH_CONNECTION_CLOSE: -+ if (user_login_count) { -+ while (user_login_count--) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_END); -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGOUT); -+ } -+ break; -+ -+ case SSH_CONNECTION_ABANDON: - case SSH_INVALID_USER: -- linux_audit_record_event(-1, audit_username(), NULL, -- get_remote_ipaddr(), "sshd", 0); -+ linux_audit_user_logxxx(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); - break; - - default: -@@ -123,4 +276,135 @@ audit_event(ssh_audit_event_t event) - } - } - -+void -+audit_unsupported_body(int what) -+{ -+#ifdef AUDIT_CRYPTO_SESSION -+ char buf[AUDIT_LOG_SIZE]; -+ const static char *name[] = { "cipher", "mac", "comp" }; -+ char *s; -+ int audit_fd; -+ -+ snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ", -+ name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), -+ get_local_port()); -+ free(s); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) -+ /* no problem, the next instruction will be fatal() */ -+ return; -+ audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, -+ buf, NULL, get_remote_ipaddr(), NULL, 0); -+ audit_close(audit_fd); -+#endif -+} -+ -+const static char *direction[] = { "from-server", "from-client", "both" }; -+ -+void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, 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 */ -Index: openssh-7.1p2/auditstub.c -=================================================================== ---- /dev/null -+++ openssh-7.1p2/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) -+{ -+} -Index: openssh-7.1p2/auth2.c -=================================================================== ---- openssh-7.1p2.orig/auth2.c -+++ openssh-7.1p2/auth2.c -@@ -241,9 +241,6 @@ input_userauth_request(int type, u_int32 - } else { - logit("input_userauth_request: invalid user %s", user); - authctxt->pw = fakepw(); --#ifdef SSH_AUDIT_EVENTS -- PRIVSEP(audit_event(SSH_INVALID_USER)); --#endif - } - #ifdef USE_PAM - if (options.use_pam) -Index: openssh-7.1p2/auth2-hostbased.c -=================================================================== ---- openssh-7.1p2.orig/auth2-hostbased.c -+++ openssh-7.1p2/auth2-hostbased.c -@@ -138,7 +138,7 @@ userauth_hostbased(Authctxt *authctxt) - /* test for allowed key and correct signature */ - authenticated = 0; - if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && -- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), -+ PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b), - buffer_len(&b))) == 1) - authenticated = 1; - -@@ -155,6 +155,18 @@ done: - return authenticated; - } - -+int -+hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) -+{ -+ int rv; -+ -+ rv = key_verify(key, sig, slen, data, datalen); -+#ifdef SSH_AUDIT_EVENTS -+ audit_key(0, &rv, key); -+#endif -+ return rv; -+} -+ - /* return 1 if given hostkey is allowed */ - int - hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, -Index: openssh-7.1p2/auth2-pubkey.c -=================================================================== ---- openssh-7.1p2.orig/auth2-pubkey.c -+++ openssh-7.1p2/auth2-pubkey.c -@@ -173,7 +173,7 @@ userauth_pubkey(Authctxt *authctxt) - /* test for correct signature */ - authenticated = 0; - if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && -- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), -+ PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b), - buffer_len(&b))) == 1) { - authenticated = 1; - /* Record the successful key to prevent reuse */ -@@ -251,6 +251,18 @@ pubkey_auth_info(Authctxt *authctxt, con - free(extra); - } - -+int -+user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) -+{ -+ int rv; -+ -+ rv = key_verify(key, sig, slen, data, datalen); -+#ifdef SSH_AUDIT_EVENTS -+ audit_key(1, &rv, key); -+#endif -+ return rv; -+} -+ - /* - * Splits 's' into an argument vector. Handles quoted string and basic - * escape characters (\\, \", \'). Caller must free the argument vector -Index: openssh-7.1p2/auth.c -=================================================================== ---- openssh-7.1p2.orig/auth.c -+++ openssh-7.1p2/auth.c -@@ -645,9 +645,6 @@ getpwnamallow(const char *user) - record_failed_login(user, - get_canonical_hostname(options.use_dns), "ssh"); - #endif --#ifdef SSH_AUDIT_EVENTS -- audit_event(SSH_INVALID_USER); --#endif /* SSH_AUDIT_EVENTS */ - return (NULL); - } - if (!allowed_user(pw)) -Index: openssh-7.1p2/auth.h -=================================================================== ---- openssh-7.1p2.orig/auth.h -+++ openssh-7.1p2/auth.h -@@ -192,6 +192,7 @@ void abandon_challenge_response(Authctxt - - char *expand_authorized_keys(const char *, struct passwd *pw); - char *authorized_principals_file(struct passwd *); -+int user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); - - FILE *auth_openkeyfile(const char *, struct passwd *, int); - FILE *auth_openprincipals(const char *, struct passwd *, int); -@@ -210,6 +211,7 @@ int get_hostkey_index(Key *, int, struc - int ssh1_session_key(BIGNUM *); - int sshd_hostkey_sign(Key *, Key *, u_char **, size_t *, - const u_char *, size_t, 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))); -Index: openssh-7.1p2/auth-rsa.c -=================================================================== ---- openssh-7.1p2.orig/auth-rsa.c -+++ openssh-7.1p2/auth-rsa.c -@@ -95,7 +95,10 @@ auth_rsa_verify_response(Key *key, BIGNU - { - u_char buf[32], mdbuf[16]; - struct ssh_digest_ctx *md; -- int len; -+ int len, rv; -+#ifdef SSH_AUDIT_EVENTS -+ char *fp; -+#endif - - /* don't allow short keys */ - if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { -@@ -119,12 +122,18 @@ auth_rsa_verify_response(Key *key, BIGNU - ssh_digest_free(md); - - /* Verify that the response is the original challenge. */ -- if (timingsafe_bcmp(response, mdbuf, 16) != 0) { -- /* Wrong answer. */ -- return (0); -+ rv = timingsafe_bcmp(response, mdbuf, 16) == 0; -+ -+#ifdef SSH_AUDIT_EVENTS -+ fp = 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; - } -- /* Correct answer. */ -- return (1); -+ free(fp); -+#endif -+ -+ return rv; - } - - /* -Index: openssh-7.1p2/cipher.c -=================================================================== ---- openssh-7.1p2.orig/cipher.c -+++ openssh-7.1p2/cipher.c -@@ -57,26 +57,6 @@ extern const EVP_CIPHER *evp_ssh1_3des(v - 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[] = { - #ifdef WITH_SSH1 - { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, -Index: openssh-7.1p2/cipher.h -=================================================================== ---- openssh-7.1p2.orig/cipher.h -+++ openssh-7.1p2/cipher.h -@@ -62,7 +62,26 @@ - #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; -Index: openssh-7.1p2/kex.c -=================================================================== ---- openssh-7.1p2.orig/kex.c -+++ openssh-7.1p2/kex.c -@@ -54,6 +54,7 @@ - #include "ssherr.h" - #include "sshbuf.h" - #include "digest.h" -+#include "audit.h" - - #if OPENSSL_VERSION_NUMBER >= 0x00907000L - # if defined(HAVE_EVP_SHA256) -@@ -534,8 +535,12 @@ choose_enc(struct sshenc *enc, char *cli - { - char *name = match_list(client, server, NULL); - -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(0); -+#endif - return SSH_ERR_NO_CIPHER_ALG_MATCH; -+ } - if ((enc->cipher = cipher_by_name(name)) == NULL) - return SSH_ERR_INTERNAL_ERROR; - enc->name = name; -@@ -553,8 +558,12 @@ choose_mac(struct ssh *ssh, struct sshma - { - char *name = match_list(client, server, NULL); - -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(1); -+#endif - return SSH_ERR_NO_MAC_ALG_MATCH; -+ } - if (mac_setup(mac, name) < 0) - return SSH_ERR_INTERNAL_ERROR; - /* truncate the key */ -@@ -571,8 +580,12 @@ choose_comp(struct sshcomp *comp, char * - { - char *name = match_list(client, server, NULL); - -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(2); -+#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) { -@@ -738,6 +751,10 @@ kex_choose_conf(struct ssh *ssh) - 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; -@@ -913,3 +930,34 @@ dump_digest(char *msg, u_char *digest, i - sshbuf_dump_data(digest, len, stderr); - } - #endif -+ -+static void -+enc_destroy(struct sshenc *enc) -+{ -+ if (enc == NULL) -+ return; -+ -+ if (enc->key) { -+ memset(enc->key, 0, enc->key_len); -+ free(enc->key); -+ } -+ -+ if (enc->iv) { -+ memset(enc->iv, 0, enc->block_size); -+ 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)); -+} -+ -Index: openssh-7.1p2/kex.h -=================================================================== ---- openssh-7.1p2.orig/kex.h -+++ openssh-7.1p2/kex.h -@@ -187,6 +187,8 @@ int kexecdh_server(struct ssh *); - int kexc25519_client(struct ssh *); - int kexc25519_server(struct ssh *); - -+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 *); -Index: openssh-7.1p2/key.h -=================================================================== ---- openssh-7.1p2.orig/key.h -+++ openssh-7.1p2/key.h -@@ -50,6 +50,7 @@ typedef struct sshkey Key; - #define key_ecdsa_bits_to_nid sshkey_ecdsa_bits_to_nid - #define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid - #define key_is_cert sshkey_is_cert -+#define key_is_private sshkey_is_private - #define key_type_plain sshkey_type_plain - #define key_curve_name_to_nid sshkey_curve_name_to_nid - #define key_curve_nid_to_bits sshkey_curve_nid_to_bits -Index: openssh-7.1p2/mac.c -=================================================================== ---- openssh-7.1p2.orig/mac.c -+++ openssh-7.1p2/mac.c -@@ -226,6 +226,20 @@ mac_clear(struct sshmac *mac) - mac->umac_ctx = NULL; - } - -+void -+mac_destroy(struct sshmac *mac) -+{ -+ if (mac == NULL) -+ return; -+ -+ if (mac->key) { -+ memset(mac->key, 0, mac->key_len); -+ free(mac->key); -+ } -+ -+ memset(mac, 0, sizeof(*mac)); -+} -+ - /* XXX copied from ciphers_valid */ - #define MAC_SEP "," - int -Index: openssh-7.1p2/mac.h -=================================================================== ---- openssh-7.1p2.orig/mac.h -+++ openssh-7.1p2/mac.h -@@ -47,5 +47,6 @@ 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 */ -Index: openssh-7.1p2/Makefile.in -=================================================================== ---- openssh-7.1p2.orig/Makefile.in -+++ openssh-7.1p2/Makefile.in -@@ -91,7 +91,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - 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 -+ kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o auditstub.o - - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect1.o sshconnect2.o mux.o \ -Index: openssh-7.1p2/monitor.c -=================================================================== ---- openssh-7.1p2.orig/monitor.c -+++ openssh-7.1p2/monitor.c -@@ -102,6 +102,7 @@ - #include "ssh2.h" - #include "roaming.h" - #include "authfd.h" -+#include "audit.h" - #include "match.h" - #include "ssherr.h" - -@@ -117,6 +118,8 @@ extern Buffer auth_debug; - extern int auth_debug_init; - extern Buffer loginmsg; - -+extern void destroy_sensitive_data(int); -+ - /* State exported from the child */ - static struct sshbuf *child_state; - -@@ -162,6 +165,11 @@ int mm_answer_gss_checkmic(int, Buffer * - #ifdef SSH_AUDIT_EVENTS - int mm_answer_audit_event(int, Buffer *); - int mm_answer_audit_command(int, Buffer *); -+int mm_answer_audit_end_command(int, Buffer *); -+int mm_answer_audit_unsupported_body(int, Buffer *); -+int mm_answer_audit_kex_body(int, Buffer *); -+int mm_answer_audit_session_key_free_body(int, Buffer *); -+int mm_answer_audit_server_key_free(int, Buffer *); - #endif - - static int monitor_read_log(struct monitor *); -@@ -218,6 +226,10 @@ struct mon_table mon_dispatch_proto20[] - #endif - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - #ifdef BSD_AUTH - {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, -@@ -249,6 +261,11 @@ struct mon_table mon_dispatch_postauth20 - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, - {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, -+ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - {0, 0, NULL} - }; -@@ -281,6 +298,10 @@ struct mon_table mon_dispatch_proto15[] - #endif - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - #endif /* WITH_SSH1 */ - {0, 0, NULL} -@@ -294,6 +315,11 @@ struct mon_table mon_dispatch_postauth15 - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, - {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, -+ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - #endif /* WITH_SSH1 */ - {0, 0, NULL} -@@ -1414,9 +1440,11 @@ mm_answer_keyverify(int sock, Buffer *m) - Key *key; - u_char *signature, *data, *blob; - u_int signaturelen, datalen, bloblen; -+ int type = 0; - int verified = 0; - int valid_data = 0; - -+ type = buffer_get_int(m); - blob = buffer_get_string(m, &bloblen); - signature = buffer_get_string(m, &signaturelen); - data = buffer_get_string(m, &datalen); -@@ -1424,6 +1452,8 @@ mm_answer_keyverify(int sock, Buffer *m) - if (hostbased_cuser == NULL || hostbased_chost == NULL || - !monitor_allowed_key(blob, bloblen)) - fatal("%s: bad key, not previously allowed", __func__); -+ if (type != key_blobtype) -+ fatal("%s: bad key type", __func__); - - key = key_from_blob(blob, bloblen); - if (key == NULL) -@@ -1444,7 +1474,17 @@ mm_answer_keyverify(int sock, Buffer *m) - if (!valid_data) - fatal("%s: bad signature data blob", __func__); - -- verified = key_verify(key, signature, signaturelen, data, datalen); -+ switch (key_blobtype) { -+ case MM_USERKEY: -+ verified = user_key_verify(key, signature, signaturelen, data, datalen); -+ break; -+ case MM_HOSTKEY: -+ verified = hostbased_key_verify(key, signature, signaturelen, data, datalen); -+ break; -+ default: -+ verified = 0; -+ break; -+ } - debug3("%s: key %p signature %s", - __func__, key, (verified == 1) ? "verified" : "unverified"); - -@@ -1505,6 +1545,12 @@ mm_session_close(Session *s) - debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); - session_pty_cleanup2(s); - } -+#ifdef SSH_AUDIT_EVENTS -+ if (s->command != NULL) { -+ debug3("%s: command %d", __func__, s->command_handle); -+ session_end_command2(s); -+ } -+#endif - session_unused(s->self); - } - -@@ -1787,6 +1833,8 @@ mm_answer_term(int sock, Buffer *req) - sshpam_cleanup(); - #endif - -+ destroy_sensitive_data(0); -+ - while (waitpid(pmonitor->m_pid, &status, 0) == -1) - if (errno != EINTR) - exit(1); -@@ -1829,11 +1877,43 @@ mm_answer_audit_command(int socket, Buff - { - u_int len; - char *cmd; -+ Session *s; - - debug3("%s entering", __func__); - cmd = buffer_get_string(m, &len); -+ - /* sanity check command, if so how? */ -- audit_run_command(cmd); -+ s = session_new(); -+ if (s == NULL) -+ fatal("%s: error allocating a session", __func__); -+ s->command = cmd; -+ 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); - } -@@ -1883,6 +1963,7 @@ monitor_apply_keystate(struct monitor *p - void - mm_get_keystate(struct monitor *pmonitor) - { -+ Buffer m; - debug3("%s: Waiting for new keys", __func__); - - if ((child_state = sshbuf_new()) == NULL) -@@ -1890,6 +1971,21 @@ mm_get_keystate(struct monitor *pmonitor - mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, - child_state); - debug3("%s: GOT new keys", __func__); -+ -+#ifdef SSH_AUDIT_EVENTS -+ if (compat20) { -+ buffer_init(&m); -+ mm_request_receive_expect(pmonitor->m_sendfd, -+ MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); -+ mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m); -+ buffer_free(&m); -+ } -+#endif -+ -+ /* Drain any buffered messages from the child */ -+ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) -+ ; -+ - } - - -@@ -2059,3 +2155,86 @@ mm_answer_gss_userok(int sock, Buffer *m - } - #endif /* GSSAPI */ - -+#ifdef SSH_AUDIT_EVENTS -+int -+mm_answer_audit_unsupported_body(int sock, Buffer *m) -+{ -+ int what; -+ -+ what = buffer_get_int(m); -+ -+ audit_unsupported_body(what); -+ -+ buffer_clear(m); -+ -+ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); -+ return 0; -+} -+ -+int -+mm_answer_audit_kex_body(int sock, Buffer *m) -+{ -+ int ctos, len; -+ char *cipher, *mac, *compress, *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 */ -Index: openssh-7.1p2/monitor.h -=================================================================== ---- openssh-7.1p2.orig/monitor.h -+++ openssh-7.1p2/monitor.h -@@ -63,7 +63,13 @@ enum monitor_reqtype { - MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, - MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, - MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, -- MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, -+ MONITOR_REQ_AUDIT_EVENT = 112, -+ MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115, -+ MONITOR_REQ_AUDIT_END_COMMAND = 116, -+ MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119, -+ MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121, -+ MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, -+ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124 - - }; - -Index: openssh-7.1p2/monitor_wrap.c -=================================================================== ---- openssh-7.1p2.orig/monitor_wrap.c -+++ openssh-7.1p2/monitor_wrap.c -@@ -443,7 +443,7 @@ mm_key_allowed(enum mm_keytype type, cha - */ - - 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; -@@ -457,6 +457,7 @@ mm_key_verify(Key *key, u_char *sig, u_i - return (0); - - buffer_init(&m); -+ buffer_put_int(&m, type); - buffer_put_string(&m, blob, len); - buffer_put_string(&m, sig, siglen); - buffer_put_string(&m, data, datalen); -@@ -474,6 +475,18 @@ mm_key_verify(Key *key, u_char *sig, u_i - return (verified); - } - -+int -+mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) -+{ -+ return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen); -+} -+ -+int -+mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) -+{ -+ return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen); -+} -+ - void - mm_send_keystate(struct monitor *monitor) - { -@@ -986,10 +999,11 @@ mm_audit_event(ssh_audit_event_t event) - buffer_free(&m); - } - --void -+int - mm_audit_run_command(const char *command) - { - Buffer m; -+ int handle; - - debug3("%s entering command %s", __func__, command); - -@@ -997,6 +1011,26 @@ mm_audit_run_command(const char *command - buffer_put_cstring(&m, command); - - mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m); -+ -+ handle = buffer_get_int(&m); -+ buffer_free(&m); -+ -+ return (handle); -+} -+ -+void -+mm_audit_end_command(int handle, const char *command) -+{ -+ Buffer m; -+ -+ debug3("%s entering command %s", __func__, command); -+ -+ buffer_init(&m); -+ buffer_put_int(&m, handle); -+ buffer_put_cstring(&m, command); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m); - buffer_free(&m); - } - #endif /* SSH_AUDIT_EVENTS */ -@@ -1087,3 +1121,70 @@ mm_ssh_gssapi_userok(char *user) - } - #endif /* GSSAPI */ - -+#ifdef SSH_AUDIT_EVENTS -+void -+mm_audit_unsupported_body(int what) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_int(&m, what); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, -+ &m); -+ -+ buffer_free(&m); -+} -+ -+void -+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid, -+ uid_t uid) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_int(&m, ctos); -+ buffer_put_cstring(&m, cipher); -+ buffer_put_cstring(&m, (mac ? mac : "")); -+ buffer_put_cstring(&m, compress); -+ buffer_put_cstring(&m, fps); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, -+ &m); -+ -+ buffer_free(&m); -+} -+ -+void -+mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_int(&m, ctos); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, -+ &m); -+ buffer_free(&m); -+} -+ -+void -+mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_cstring(&m, fp); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m); -+ buffer_free(&m); -+} -+#endif /* SSH_AUDIT_EVENTS */ -Index: openssh-7.1p2/monitor_wrap.h -=================================================================== ---- openssh-7.1p2.orig/monitor_wrap.h -+++ openssh-7.1p2/monitor_wrap.h -@@ -49,7 +49,8 @@ int mm_key_allowed(enum mm_keytype, char - 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 *); -@@ -74,7 +75,12 @@ void mm_sshpam_free_ctx(void *); - #ifdef SSH_AUDIT_EVENTS - #include "audit.h" - void mm_audit_event(ssh_audit_event_t); --void mm_audit_run_command(const char *); -+int mm_audit_run_command(const char *); -+void mm_audit_end_command(int, const char *); -+void mm_audit_unsupported_body(int); -+void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); -+void mm_audit_session_key_free_body(int, pid_t, uid_t); -+void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); - #endif - - struct Session; -Index: openssh-7.1p2/packet.c -=================================================================== ---- openssh-7.1p2.orig/packet.c -+++ openssh-7.1p2/packet.c -@@ -67,6 +67,7 @@ - #include "key.h" /* typedefs XXX */ - - #include "xmalloc.h" -+#include "audit.h" - #include "crc32.h" - #include "deattack.h" - #include "compat.h" -@@ -447,6 +448,13 @@ ssh_packet_get_connection_out(struct ssh - return ssh->state->connection_out; - } - -+static int -+packet_state_has_keys (const struct session_state *state) -+{ -+ return state != NULL && -+ (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL); -+} -+ - /* - * Returns the IP-address of the remote host as a string. The returned - * string must not be freed. -@@ -477,13 +485,6 @@ ssh_packet_close(struct ssh *ssh) - if (!state->initialized) - return; - state->initialized = 0; -- if (state->connection_in == state->connection_out) { -- shutdown(state->connection_out, SHUT_RDWR); -- close(state->connection_out); -- } else { -- close(state->connection_in); -- close(state->connection_out); -- } - sshbuf_free(state->input); - sshbuf_free(state->output); - sshbuf_free(state->outgoing_packet); -@@ -515,14 +516,24 @@ ssh_packet_close(struct ssh *ssh) - 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(2); -+ } - if (ssh->remote_ipaddr) { - 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; - } -@@ -942,6 +953,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod - } - if (state->newkeys[mode] != NULL) { - debug("set_newkeys: rekeying"); -+ audit_session_key_free(mode); - if ((r = cipher_cleanup(cc)) != 0) - return r; - enc = &state->newkeys[mode]->enc; -@@ -2291,6 +2303,75 @@ 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)) -+ || (backup_state != NULL && packet_state_has_keys(backup_state->state)); -+ if (active_state != NULL) -+ packet_destroy_state(active_state->state); -+ if (backup_state != NULL) -+ packet_destroy_state(backup_state->state); -+ if (audit_it) { -+#ifdef SSH_AUDIT_EVENTS -+ if (privsep) -+ audit_session_key_free(2); -+ else -+ audit_session_key_free_body(2, getpid(), getuid()); -+#endif -+ } -+} -+ - /* XXX TODO update roaming to new API (does not work anyway) */ - /* - * Save the state for the real connection, and use a separate state when -@@ -2300,18 +2381,12 @@ void - ssh_packet_backup_state(struct ssh *ssh, - struct ssh *backup_state) - { -- struct ssh *tmp; -- - close(ssh->state->connection_in); - ssh->state->connection_in = -1; - close(ssh->state->connection_out); - ssh->state->connection_out = -1; -- if (backup_state) -- tmp = backup_state; -- else -- tmp = ssh_alloc_session_state(); - backup_state = ssh; -- ssh = tmp; -+ ssh = ssh_alloc_session_state(); - } - - /* XXX FIXME FIXME FIXME */ -@@ -2330,9 +2405,7 @@ ssh_packet_restore_state(struct ssh *ssh - backup_state = ssh; - ssh = tmp; - ssh->state->connection_in = backup_state->state->connection_in; -- backup_state->state->connection_in = -1; - ssh->state->connection_out = backup_state->state->connection_out; -- backup_state->state->connection_out = -1; - len = sshbuf_len(backup_state->state->input); - if (len > 0) { - if ((r = sshbuf_putb(ssh->state->input, -@@ -2341,6 +2414,11 @@ ssh_packet_restore_state(struct ssh *ssh - sshbuf_reset(backup_state->state->input); - add_recv_bytes(len); - } -+ backup_state->state->connection_in = -1; -+ backup_state->state->connection_out = -1; -+ packet_destroy_state(backup_state->state); -+ free(backup_state); -+ backup_state = NULL; - } - - /* Reset after_authentication and reset compression in post-auth privsep */ -Index: openssh-7.1p2/packet.h -=================================================================== ---- openssh-7.1p2.orig/packet.h -+++ openssh-7.1p2/packet.h -@@ -189,7 +189,7 @@ int sshpkt_get_end(struct ssh *ssh); - const u_char *sshpkt_ptr(struct ssh *, size_t *lenp); - - /* OLD API */ --extern struct ssh *active_state; -+extern struct ssh *active_state, *backup_state; - #include "opacket.h" - - #if !defined(WITH_OPENSSL) -@@ -203,4 +203,5 @@ extern struct ssh *active_state; - # undef EC_POINT - #endif - -+void packet_destroy_all(int, int); - #endif /* PACKET_H */ -Index: openssh-7.1p2/sandbox-seccomp-filter.c -=================================================================== ---- openssh-7.1p2.orig/sandbox-seccomp-filter.c -+++ openssh-7.1p2/sandbox-seccomp-filter.c -@@ -150,6 +150,12 @@ static const struct sock_filter preauth_ - #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 -Index: openssh-7.1p2/session.c -=================================================================== ---- openssh-7.1p2.orig/session.c -+++ openssh-7.1p2/session.c -@@ -139,7 +139,7 @@ extern int log_stderr; - extern int debug_flag; - extern u_int utmp_len; - extern int startup_pipe; --extern void destroy_sensitive_data(void); -+extern void destroy_sensitive_data(int); - extern Buffer loginmsg; - - /* original command from peer. */ -@@ -729,6 +729,14 @@ do_exec_pty(Session *s, const char *comm - /* Parent. Close the slave side of the pseudo tty. */ - close(ttyfd); - -+#ifndef HAVE_OSF_SIA -+ /* do_login in the child did not affect state in this process, -+ compensate. From an architectural standpoint, this is extremely -+ ugly. */ -+ if (!(options.use_login && command == NULL)) -+ audit_count_session_open(); -+#endif -+ - /* Enter interactive session. */ - s->ptymaster = ptymaster; - packet_set_interactive(1, -@@ -823,15 +831,19 @@ do_exec(Session *s, const char *command) - get_remote_port()); - - #ifdef SSH_AUDIT_EVENTS -+ if (s->command != NULL || s->command_handle != -1) -+ fatal("do_exec: command already set"); - if (command != NULL) -- PRIVSEP(audit_run_command(command)); -+ s->command = xstrdup(command); - else if (s->ttyfd == -1) { - char *shell = s->pw->pw_shell; - - if (shell[0] == '\0') /* empty shell means /bin/sh */ - shell =_PATH_BSHELL; -- PRIVSEP(audit_run_command(shell)); -+ s->command = xstrdup(shell); - } -+ if (s->command != NULL && s->ptyfd == -1) -+ s->command_handle = PRIVSEP(audit_run_command(s->command)); - #endif - if (s->ttyfd != -1) - ret = do_exec_pty(s, command); -@@ -1684,7 +1696,10 @@ do_child(Session *s, const char *command - int r = 0; - - /* remove hostkey from the child's memory */ -- destroy_sensitive_data(); -+ destroy_sensitive_data(1); -+ /* Don't audit this - both us and the parent would be talking to the -+ monitor over a single socket, with no synchronization. */ -+ packet_destroy_all(0, 1); - - /* Force a password change */ - if (s->authctxt->force_pwchange) { -@@ -1911,6 +1926,7 @@ session_unused(int id) - sessions[id].ttyfd = -1; - sessions[id].ptymaster = -1; - sessions[id].x11_chanids = NULL; -+ sessions[id].command_handle = -1; - sessions[id].next_unused = sessions_first_unused; - sessions_first_unused = id; - } -@@ -1993,6 +2009,19 @@ session_open(Authctxt *authctxt, int cha - } - - Session * -+session_by_id(int id) -+{ -+ if (id >= 0 && id < sessions_nalloc) { -+ Session *s = &sessions[id]; -+ if (s->used) -+ return s; -+ } -+ debug("session_by_id: unknown id %d", id); -+ session_dump(); -+ return NULL; -+} -+ -+Session * - session_by_tty(char *tty) - { - int i; -@@ -2509,6 +2538,32 @@ session_exit_message(Session *s, int sta - chan_write_failed(c); - } - -+#ifdef SSH_AUDIT_EVENTS -+void -+session_end_command2(Session *s) -+{ -+ if (s->command != NULL) { -+ if (s->command_handle != -1) -+ audit_end_command(s->command_handle, s->command); -+ free(s->command); -+ s->command = NULL; -+ s->command_handle = -1; -+ } -+} -+ -+static void -+session_end_command(Session *s) -+{ -+ if (s->command != NULL) { -+ if (s->command_handle != -1) -+ PRIVSEP(audit_end_command(s->command_handle, s->command)); -+ free(s->command); -+ s->command = NULL; -+ s->command_handle = -1; -+ } -+} -+#endif -+ - void - session_close(Session *s) - { -@@ -2549,6 +2604,10 @@ session_close(Session *s) - - if (s->ttyfd != -1) - session_pty_cleanup(s); -+#ifdef SSH_AUDIT_EVENTS -+ if (s->command) -+ session_end_command(s); -+#endif - free(s->term); - free(s->display); - free(s->x11_chanids); -@@ -2763,6 +2822,15 @@ do_authenticated2(Authctxt *authctxt) - server_loop2(authctxt); - } - -+static void -+do_cleanup_one_session(Session *s) -+{ -+ session_pty_cleanup2(s); -+#ifdef SSH_AUDIT_EVENTS -+ session_end_command2(s); -+#endif -+} -+ - void - do_cleanup(Authctxt *authctxt) - { -@@ -2811,5 +2879,5 @@ do_cleanup(Authctxt *authctxt) - * or if running in monitor. - */ - if (!use_privsep || mm_is_monitor()) -- session_destroy_all(session_pty_cleanup2); -+ session_destroy_all(do_cleanup_one_session); - } -Index: openssh-7.1p2/session.h -=================================================================== ---- openssh-7.1p2.orig/session.h -+++ openssh-7.1p2/session.h -@@ -61,6 +61,12 @@ struct Session { - char *name; - char *val; - } *env; -+ -+ /* exec */ -+#ifdef SSH_AUDIT_EVENTS -+ int command_handle; -+ char *command; -+#endif - }; - - void do_authenticated(Authctxt *); -@@ -73,8 +79,10 @@ void session_close_by_pid(pid_t, int); - void session_close_by_channel(int, void *); - void session_destroy_all(void (*)(Session *)); - void session_pty_cleanup2(Session *); -+void session_end_command2(Session *); - - Session *session_new(void); -+Session *session_by_id(int); - Session *session_by_tty(char *); - void session_close(Session *); - void do_setusercontext(struct passwd *); -Index: openssh-7.1p2/sshd.c -=================================================================== ---- openssh-7.1p2.orig/sshd.c -+++ openssh-7.1p2/sshd.c -@@ -122,6 +122,7 @@ - #endif - #include "monitor_wrap.h" - #include "roaming.h" -+#include "audit.h" - #include "ssh-sandbox.h" - #include "version.h" - #include "ssherr.h" -@@ -254,7 +255,7 @@ Buffer loginmsg; - struct passwd *privsep_pw = NULL; - - /* Prototypes for various functions defined later in this file. */ --void destroy_sensitive_data(void); -+void destroy_sensitive_data(int); - void demote_sensitive_data(void); - - #ifdef WITH_SSH1 -@@ -275,6 +276,15 @@ close_listen_socks(void) - num_listen_socks = -1; - } - -+/* -+ * Is this process listening for clients (i.e. not specific to any specific -+ * client connection?) -+ */ -+int listening_for_clients(void) -+{ -+ return num_listen_socks > 0; -+} -+ - static void - close_startup_pipes(void) - { -@@ -554,22 +564,45 @@ sshd_exchange_identification(int sock_in - } - } - --/* Destroy the host and server keys. They will no longer be needed. */ -+/* -+ * Destroy the host and server keys. They will no longer be needed. Careful, -+ * this can be called from cleanup_exit() - i.e. from just about anywhere. -+ */ - void --destroy_sensitive_data(void) -+destroy_sensitive_data(int privsep) - { - int i; -+ pid_t pid; -+ uid_t uid; - - if (sensitive_data.server_key) { - key_free(sensitive_data.server_key); - sensitive_data.server_key = NULL; - } -+ pid = getpid(); -+ uid = getuid(); - for (i = 0; i < options.num_host_key_files; i++) { - if (sensitive_data.host_keys[i]) { -+ char *fp; -+ -+ if (key_is_private(sensitive_data.host_keys[i])) -+ fp = 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) { -+ if (privsep) -+ PRIVSEP(audit_destroy_sensitive_data(fp, -+ pid, uid)); -+ else -+ audit_destroy_sensitive_data(fp, -+ pid, uid); -+ free(fp); -+ } - } -- if (sensitive_data.host_certificates[i]) { -+ if (sensitive_data.host_certificates -+ && sensitive_data.host_certificates[i]) { - key_free(sensitive_data.host_certificates[i]); - sensitive_data.host_certificates[i] = NULL; - } -@@ -583,6 +616,8 @@ void - demote_sensitive_data(void) - { - Key *tmp; -+ pid_t pid; -+ uid_t uid; - int i; - - if (sensitive_data.server_key) { -@@ -591,13 +626,25 @@ demote_sensitive_data(void) - sensitive_data.server_key = tmp; - } - -+ pid = getpid(); -+ uid = getuid(); - for (i = 0; i < options.num_host_key_files; i++) { - if (sensitive_data.host_keys[i]) { -+ char *fp; -+ -+ if (key_is_private(sensitive_data.host_keys[i])) -+ fp = 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) { -+ audit_destroy_sensitive_data(fp, pid, uid); -+ free(fp); -+ } - } - /* Certs do not need demotion */ - } -@@ -667,7 +714,7 @@ privsep_preauth(Authctxt *authctxt) - - if (use_privsep == PRIVSEP_ON) - box = ssh_sandbox_init(pmonitor); -- pid = fork(); -+ pmonitor->m_pid = pid = fork(); - if (pid == -1) { - fatal("fork of unprivileged child failed"); - } else if (pid != 0) { -@@ -751,6 +798,12 @@ privsep_postauth(Authctxt *authctxt) - else if (pmonitor->m_pid != 0) { - verbose("User child is on pid %ld", (long)pmonitor->m_pid); - buffer_clear(&loginmsg); -+ if (*pmonitor->m_pkex != NULL ){ -+ newkeys_destroy((*pmonitor->m_pkex)->newkeys[MODE_OUT]); -+ newkeys_destroy((*pmonitor->m_pkex)->newkeys[MODE_IN]); -+ audit_session_key_free_body(2, getpid(), getuid()); -+ packet_destroy_all(0, 0); -+ } - monitor_child_postauth(pmonitor); - - /* NEVERREACHED */ -@@ -1273,6 +1326,7 @@ server_accept_loop(int *sock_in, int *so - if (received_sigterm) { - logit("Received signal %d; terminating.", - (int) received_sigterm); -+ destroy_sensitive_data(0); - close_listen_socks(); - if (options.pid_file != NULL) - unlink(options.pid_file); -@@ -2216,6 +2270,7 @@ main(int ac, char **av) - */ - if (use_privsep) { - mm_send_keystate(pmonitor); -+ packet_destroy_all(1, 1); - exit(0); - } - -@@ -2258,7 +2313,7 @@ main(int ac, char **av) - privsep_postauth(authctxt); - /* the monitor process [priv] will not return */ - if (!compat20) -- destroy_sensitive_data(); -+ destroy_sensitive_data(0); - } - - packet_set_timeout(options.client_alive_interval, -@@ -2272,6 +2327,9 @@ main(int ac, char **av) - do_authenticated(authctxt); - - /* The connection has been terminated. */ -+ packet_destroy_all(1, 1); -+ destroy_sensitive_data(1); -+ - packet_get_bytes(&ibytes, &obytes); - verbose("Transferred: sent %llu, received %llu bytes", - (unsigned long long)obytes, (unsigned long long)ibytes); -@@ -2432,6 +2490,10 @@ do_ssh1_kex(void) - if (cookie[i] != packet_get_char()) - packet_disconnect("IP Spoofing check bytes do not match."); - -+#ifdef SSH_AUDIT_EVENTS -+ audit_kex(2, cipher_name(cipher_type), "crc", "none", "none"); -+#endif -+ - debug("Encryption type: %.200s", cipher_name(cipher_type)); - - /* Get the encrypted integer. */ -@@ -2491,7 +2553,7 @@ do_ssh1_kex(void) - } - - /* Destroy the private and public keys. No longer. */ -- destroy_sensitive_data(); -+ destroy_sensitive_data(1); - - if (use_privsep) - mm_ssh1_session_id(session_id); -@@ -2614,6 +2676,16 @@ do_ssh2_kex(void) - void - cleanup_exit(int i) - { -+ static int in_cleanup = 0; -+ int is_privsep_child; -+ -+ /* cleanup_exit can be called at the very least from the privsep -+ wrappers used for auditing. Make sure we don't recurse -+ indefinitely. */ -+ if (in_cleanup) -+ _exit(i); -+ in_cleanup = 1; -+ - if (the_authctxt) { - do_cleanup(the_authctxt); - if (use_privsep && privsep_is_preauth && -@@ -2625,9 +2697,14 @@ cleanup_exit(int i) - pmonitor->m_pid, strerror(errno)); - } - } -+ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; -+ if (sensitive_data.host_keys != NULL) -+ destroy_sensitive_data(is_privsep_child); -+ packet_destroy_all(1, is_privsep_child); - #ifdef SSH_AUDIT_EVENTS - /* done after do_cleanup so it can cancel the PAM auth 'thread' */ -- if (!use_privsep || mm_is_monitor()) -+ if ((the_authctxt == NULL || !the_authctxt->authenticated) && -+ (!use_privsep || mm_is_monitor())) - audit_event(SSH_CONNECTION_ABANDON); - #endif - _exit(i); -Index: openssh-7.1p2/sshkey.c -=================================================================== ---- openssh-7.1p2.orig/sshkey.c -+++ openssh-7.1p2/sshkey.c -@@ -299,6 +299,33 @@ sshkey_type_is_valid_ca(int type) - } - - int -+sshkey_is_private(const struct sshkey *k) -+{ -+ switch (k->type) { -+#ifdef WITH_OPENSSL -+ case KEY_RSA_CERT: -+ case KEY_RSA1: -+ case KEY_RSA: -+ return k->rsa->d != NULL; -+ case KEY_DSA_CERT: -+ case KEY_DSA: -+ return k->dsa->priv_key != NULL; -+#ifdef OPENSSL_HAS_ECC -+ case KEY_ECDSA_CERT: -+ case KEY_ECDSA: -+ return EC_KEY_get0_private_key(k->ecdsa) != NULL; -+#endif /* OPENSSL_HAS_ECC */ -+#endif /* WITH_OPENSSL */ -+ case KEY_ED25519_CERT: -+ case KEY_ED25519: -+ return (k->ed25519_pk != NULL); -+ default: -+ /* fatal("key_is_private: bad key type %d", k->type); */ -+ return 0; -+ } -+} -+ -+int - sshkey_is_cert(const struct sshkey *k) - { - if (k == NULL) -Index: openssh-7.1p2/sshkey.h -=================================================================== ---- openssh-7.1p2.orig/sshkey.h -+++ openssh-7.1p2/sshkey.h -@@ -132,6 +132,7 @@ u_int sshkey_size(const struct sshkey - int sshkey_generate(int type, u_int bits, struct sshkey **keyp); - int sshkey_from_private(const struct sshkey *, struct sshkey **); - int sshkey_type_from_name(const char *); -+int sshkey_is_private(const struct sshkey *); - int sshkey_is_cert(const struct sshkey *); - int sshkey_type_is_cert(int); - int sshkey_type_plain(int); diff --git a/openssh-7.1p2.tar.gz b/openssh-7.1p2.tar.gz deleted file mode 100644 index fccea51..0000000 --- a/openssh-7.1p2.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dd75f024dcf21e06a0d6421d582690bf987a1f6323e32ad6619392f3bfde6bbd -size 1475829 diff --git a/openssh-7.1p2.tar.gz.asc b/openssh-7.1p2.tar.gz.asc deleted file mode 100644 index 95644fa..0000000 --- a/openssh-7.1p2.tar.gz.asc +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2 - -iQGsBAABCgAGBQJWlvZKAAoJENPl9Wttkg0w0kwMfRd8u1P8+RDXoF32uhtOwQAY -31cJz2gBf2jnBV/BEzxBNCvpObE9ECCMyWK0RSCjHQBxfwoW4YdkAArBZxbexXtU -fXOlUdcB1cc4OqgvvufktMt5txg17VSKv8tI23mCT0Ibs3dppz+PNAH2LzcKWTXb -Hr7PQzY4qufZ336R6ADKuXqfUFDNx7oLEiehTrSC7AhIM3Wagqv2dRBJNkW/Ci3w -qWnTQ6IOD5A//EDLVW0SqQ1/4n7mWBmkoiRw0xzFxRnnHKjhwIGqwj5oOoDFzZOa -6XtOcIwh9VXemTl5Gq+ZaiaRFA1TRHsVXVT1TgSUgB3Muy3PyOFHmHEZlLyfPrNV -/WjoV18zosVGd2egGB8jK6xzftpPeoVndiWPwSIz52E6xBtoCVXr0ksjz3wbgx+9 -NOVF58Zo19eN6Nf1H4EP3K0aNDnjM5lsByphGGk5W7sQUc0u4Yvw4Rbc9VGV8I/Z -Sddw5WProNQXmsO06eO2ey8POUI4CaKTe8UWfc74MXkF93m8MD7VdmB4lYCsFi8= -=0gQS ------END PGP SIGNATURE----- diff --git a/openssh-alloc_size.patch b/openssh-alloc_size.patch deleted file mode 100644 index 369ad72..0000000 --- a/openssh-alloc_size.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- openssh-7.1p2.orig/xmalloc.h -+++ openssh-7.1p2/xmalloc.h -@@ -16,10 +16,10 @@ - * called by a name other than "ssh" or "Secure Shell". - */ - --void *xmalloc(size_t); --void *xcalloc(size_t, size_t); --void *xreallocarray(void *, size_t, size_t); --char *xstrdup(const char *); -+void *xmalloc(size_t) __attribute__((__malloc__, __alloc_size__(1))); -+void *xcalloc(size_t, size_t) __attribute__((__malloc__, __alloc_size__(1,2))); -+void *xreallocarray(void *, size_t, size_t) __attribute__((__alloc_size__(2,3))); -+char *xstrdup(const char *) __attribute__((__malloc__)); - int xasprintf(char **, const char *, ...) - __attribute__((__format__ (printf, 2, 3))) - __attribute__((__nonnull__ (2))); ---- openssh-7.1p2.orig/openbsd-compat/openbsd-compat.h -+++ openssh-7.1p2/openbsd-compat/openbsd-compat.h -@@ -66,7 +66,7 @@ char *getcwd(char *pt, size_t size); - #endif - - #ifndef HAVE_REALLOCARRAY --void *reallocarray(void *, size_t, size_t); -+void *reallocarray(void *, size_t, size_t) __attribute__((__alloc_size__(2,3))); - #endif - - #if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) diff --git a/openssh-allow_getrandom.patch b/openssh-allow_getrandom.patch deleted file mode 100644 index d95f1e1..0000000 --- a/openssh-allow_getrandom.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- openssh-7.1p2.orig/sandbox-seccomp-filter.c -+++ openssh-7.1p2/sandbox-seccomp-filter.c -@@ -153,6 +153,9 @@ static const struct sock_filter preauth_ - #ifdef __NR_getuid32 - SC_ALLOW(getuid32), - #endif -+#ifdef __NR_getrandom -+ SC_ALLOW(getrandom), -+#endif - #ifdef __NR_gettimeofday - SC_ALLOW(gettimeofday), - #endif diff --git a/openssh-askpass-gnome.changes b/openssh-askpass-gnome.changes index 34c72ba..3a8dbfa 100644 --- a/openssh-askpass-gnome.changes +++ b/openssh-askpass-gnome.changes @@ -1,9 +1,3 @@ -------------------------------------------------------------------- -Mon Jan 18 06:58:40 UTC 2016 - tchvatal@suse.com - -- Cleanup with spec-cleaner -- Update of the master OpenSSH to 7.1p2 - ------------------------------------------------------------------- Fri Apr 11 21:50:51 UTC 2014 - pcerny@suse.com diff --git a/openssh-askpass-gnome.spe_ b/openssh-askpass-gnome.spec similarity index 98% rename from openssh-askpass-gnome.spe_ rename to openssh-askpass-gnome.spec index fcf802e..6410b72 100644 --- a/openssh-askpass-gnome.spe_ +++ b/openssh-askpass-gnome.spec @@ -16,15 +16,7 @@ # -%define _name openssh Name: openssh-askpass-gnome -Version: 7.1p2 -Release: 0 -Summary: A GNOME-Based Passphrase Dialog for OpenSSH -License: BSD-3-Clause -Group: Productivity/Networking/SSH -Url: http://www.openssh.com/ -Source: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz BuildRequires: autoconf BuildRequires: automake BuildRequires: gtk2-devel @@ -34,7 +26,15 @@ BuildRequires: openssl-devel BuildRequires: pam-devel BuildRequires: tcpd-devel BuildRequires: update-desktop-files +Version: 6.6p1 +Release: 0 Requires: openssh = %{version} +Summary: A GNOME-Based Passphrase Dialog for OpenSSH +License: BSD-3-Clause +Group: Productivity/Networking/SSH +Url: http://www.openssh.com/ +%define _name openssh +Source: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build %description diff --git a/openssh-fix-b64_xx-detection.patch b/openssh-fix-b64_xx-detection.patch deleted file mode 100644 index 5ccd89a..0000000 --- a/openssh-fix-b64_xx-detection.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- openssh-7.1p2.orig/configure.ac -+++ openssh-7.1p2/configure.ac -@@ -2873,6 +2873,10 @@ else - AC_CHECK_FUNCS([crypt]) - fi - -+AC_CHECK_DECLS([b64_ntop, b64_pton], [], [], [#include ]) -+AC_SEARCH_LIBS([__b64_ntop], [resolv]) -+AC_SEARCH_LIBS([__b64_pton], [resolv]) -+ - AC_CHECK_FUNCS([ \ - arc4random \ - arc4random_buf \ ---- openssh-7.1p2.orig/Makefile.in -+++ openssh-7.1p2/Makefile.in -@@ -45,7 +45,7 @@ PATHS= -DSSHDIR=\"$(sysconfdir)\" \ - CC=@CC@ - LD=@LD@ - CFLAGS=@CFLAGS@ --CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -+CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -include config.h - LIBS=@LIBS@ - K5LIBS=@K5LIBS@ - GSSLIBS=@GSSLIBS@ diff --git a/openssh.changes b/openssh.changes index 3fa3171..74240a0 100644 --- a/openssh.changes +++ b/openssh.changes @@ -1,94 +1,3 @@ -------------------------------------------------------------------- -Mon Feb 8 16:54:22 UTC 2016 - crrodriguez@opensuse.org - -- openssh-alloc_size.patch: anotate xmalloc.h with alloc_size - attribute so the compiler knows these functions allocate memory - so overflow or misuse can be detected sooner. -- openssh-allow_getrandom.patch; allow the getrandom(2) system - call in the seccomp sandbox, upstream commit 26ad18247213 -- openssh-fix-b64_xx-detection.patch: configure.ac has incorrect - tests for b64_ntop, b64_pton on linux/glibc. - -------------------------------------------------------------------- -Wed Jan 20 11:18:48 UTC 2016 - tchvatal@suse.com - -- Take refreshed and updated audit patch from redhat - * Remove our old patches: - + openssh-6.6p1-audit1-remove_duplicit_audit.patch - + openssh-6.6p1-audit2-better_audit_of_user_actions.patch - + openssh-6.6p1-audit3-key_auth_usage-fips.patch - + openssh-6.6p1-audit3-key_auth_usage.patch - + openssh-6.6p1-audit4-kex_results-fips.patch - + openssh-6.6p1-audit4-kex_results.patch - + openssh-6.6p1-audit5-session_key_destruction.patch - + openssh-6.6p1-audit6-server_key_destruction.patch - + openssh-6.6p1-audit7-libaudit_compat.patch - + openssh-6.6p1-audit8-libaudit_dns_timeouts.patch - * add openssh-6.7p1-audit.patch -- Reenable the openssh-6.6p1-ldap.patch -- Update the fips patch from RH build openssh-6.6p1-fips.patch -- Update and refresh openssh-6.6p1-gssapi_key_exchange.patch -- Remove fips-check patch as it is merged to fips patch - * openssh-6.6p1-fips-checks.patch -- Rebase and enable chroot patch: - * openssh-6.6p1-sftp_homechroot.patch -- Reenable rebased patch for linux seed: - * openssh-6.6p1-seed-prng.patch -- Reenable key converting patch: - * openssh-6.6p1-key-converter.patch - -------------------------------------------------------------------- -Mon Jan 18 07:33:17 UTC 2016 - tchvatal@suse.com - -- Version update to 7.1p2: - * various upstream bugfixes and cleanups -- Remove upstreamed patch: - * openssh-6.6p1-curve25519-6.6.1p1.patch - * CVE-2016-0777_CVE-2016-0778.patch -- Remove patches fixed differently in upstream: - * openssh-6.6p1-fingerprint_hash.patch - * openssh-6.6p1-no_fork-no_pid_file.patch -- Disable patch for fips, needs a lot of work: - * openssh-6.6p1-fips.patch - * openssh-6.6p1-audit3-key_auth_usage-fips.patch -- Refresh non-applying patches: - * openssh-6.6p1-blocksigalrm.patch - * openssh-6.6p1-eal3.patch - * openssh-6.6p1-gssapimitm.patch - * openssh-6.6p1-pam-check-locks.patch - * openssh-6.6p1-disable-openssl-abi-check.patch - * openssh-6.6p1-sftp_force_permissions.patch - * openssh-6.6p1-seccomp_getuid.patch - * openssh-6.6p1-ldap.patch -- Disable non-applying patches requiring review: - * openssh-6.6p1-audit2-better_audit_of_user_actions.patch - * openssh-6.6p1-audit3-key_auth_usage.patch - * openssh-6.6p1-audit4-kex_results.patch - * openssh-6.6p1-audit4-kex_results-fips.patch - * openssh-6.6p1-audit5-session_key_destruction.patch - * openssh-6.6p1-audit6-server_key_destruction.patch - * openssh-6.6p1-seed-prng.patch - * openssh-6.6p1-gssapi_key_exchange.patch - * openssh-6.6p1-sftp_homechroot.patch - * openssh-6.6p1-fips-checks.patch - * openssh-6.6p1-ldap.patch - -------------------------------------------------------------------- -Mon Jan 18 07:06:52 UTC 2016 - tchvatal@suse.com - -- Merge few of conditionals as we do not support many of the specified - version ranges - -------------------------------------------------------------------- -Mon Jan 18 06:52:33 UTC 2016 - tchvatal@suse.com - -- Rename README.SuSE to README.SUSE - -------------------------------------------------------------------- -Mon Jan 18 06:50:36 UTC 2016 - tchvatal@suse.com - -- Cleanup with spec-cleaner - ------------------------------------------------------------------- Thu Jan 14 15:35:55 UTC 2016 - astieger@suse.com diff --git a/openssh.spe_ b/openssh.spec similarity index 75% rename from openssh.spe_ rename to openssh.spec index 844a12a..d44cb90 100644 --- a/openssh.spe_ +++ b/openssh.spec @@ -16,46 +16,95 @@ # -%define sandbox_seccomp 0 -%define _fwdir %{_sysconfdir}/sysconfig/SuSEfirewall2.d -%define _fwdefdir %{_fwdir}/services -%define _appdefdir %( grep "configdirspec=" $( which xmkmf ) | sed -r 's,^[^=]+=.*-I(.*)/config.*$,\\1/app-defaults,' ) -%{!?_initddir:%global _initddir %{_initrddir}} -%if 0%{?suse_version} >= 1100 +%if 0%{suse_version} >= 1100 %define has_fw_dir 1 -%define has_libselinux 1 %else %define has_fw_dir 0 +%endif + +%if 0%{suse_version} >= 1110 +%define has_libselinux 1 +%else %define has_libselinux 0 %endif + %if 0%{?suse_version} >= 1130 +%define needs_all_dirs 1 +%else +%define needs_all_dirs 0 +%endif + +%if 0%{?suse_version} >= 1140 %define needs_libedit 1 -%define has_krb_mini 1 %else %define needs_libedit 0 +%endif + +%if 0%{?suse_version} > 1140 +%define has_krb_mini 1 +%else %define has_krb_mini 0 %endif + %if 0%{?suse_version} > 1220 %define uses_systemd 1 %else %define uses_systemd 0 %endif + +%define sandbox_seccomp 0 %ifarch %ix86 x86_64 %if 0%{?suse_version} > 1220 %define sandbox_seccomp 1 %endif %endif + +%define _fwdir %{_sysconfdir}/sysconfig/SuSEfirewall2.d +%define _fwdefdir %{_fwdir}/services +%define _appdefdir %( grep "configdirspec=" $( which xmkmf ) | sed -r 's,^[^=]+=.*-I(.*)/config.*$,\\1/app-defaults,' ) +%{!?_initddir:%global _initddir %{_initrddir}} + Name: openssh -Version: 7.1p2 +BuildRequires: audit-devel +BuildRequires: autoconf +BuildRequires: groff +%if %{has_krb_mini} +BuildRequires: krb5-mini-devel +%else +BuildRequires: krb5-devel +%endif +%if %{needs_libedit} +BuildRequires: libedit-devel +%endif +%if %{has_libselinux} +BuildRequires: libselinux-devel +%endif +BuildRequires: openldap2-devel +BuildRequires: openssl +BuildRequires: openssl-devel +BuildRequires: pam-devel +%if %{uses_systemd} +BuildRequires: pkgconfig(systemd) +%{?systemd_requires} +%else +PreReq: %{insserv_prereq} +%endif +PreReq: pwdutils %{fillup_prereq} coreutils +Conflicts: nonfreessh +Recommends: xauth +Recommends: %{name}-helpers +Version: 6.6p1 Release: 0 Summary: Secure Shell Client and Server (Remote Login Program) License: BSD-3-Clause and MIT Group: Productivity/Networking/SSH Url: http://www.openssh.com/ Source: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz +Source42: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc +Source43: openssh.keyring Source1: sshd.init Source2: sshd.pamd -Source3: README.SUSE +Source3: README.SuSE Source4: README.kerberos Source5: ssh.reg Source6: ssh-askpass @@ -63,8 +112,7 @@ Source7: sshd.fw Source8: sysconfig.ssh Source9: sshd-gen-keys-start Source10: sshd.service -Source42: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc -Source43: openssh.keyring +Patch0: openssh-6.6p1-curve25519-6.6.1p1.patch Patch1: openssh-6.6p1-key-converter.patch Patch2: openssh-6.6p1-X11-forwarding.patch Patch3: openssh-6.6p1-lastlog.patch @@ -80,55 +128,32 @@ Patch12: openssh-6.6p1-xauth.patch Patch13: openssh-6.6p1-default-protocol.patch Patch14: openssh-6.6p1-pts.patch Patch15: openssh-6.6p1-pam-check-locks.patch +Patch16: openssh-6.6p1-fingerprint_hash.patch Patch17: openssh-6.6p1-fips.patch -# PATCH-FIX-SUSE: audit patch taken from redhat -Patch18: openssh-6.7p1-audit.patch +Patch18: openssh-6.6p1-audit1-remove_duplicit_audit.patch +Patch19: openssh-6.6p1-audit2-better_audit_of_user_actions.patch +Patch20: openssh-6.6p1-audit3-key_auth_usage.patch +Patch21: openssh-6.6p1-audit3-key_auth_usage-fips.patch +Patch22: openssh-6.6p1-audit4-kex_results.patch +Patch23: openssh-6.6p1-audit4-kex_results-fips.patch +Patch24: openssh-6.6p1-audit5-session_key_destruction.patch +Patch25: openssh-6.6p1-audit6-server_key_destruction.patch +Patch26: openssh-6.6p1-audit7-libaudit_compat.patch +Patch27: openssh-6.6p1-audit8-libaudit_dns_timeouts.patch Patch28: openssh-6.6p1-seed-prng.patch Patch29: openssh-6.6p1-gssapi_key_exchange.patch Patch30: openssh-6.6p1-login_options.patch Patch31: openssh-6.6p1-disable-openssl-abi-check.patch +Patch32: openssh-6.6p1-no_fork-no_pid_file.patch Patch33: openssh-6.6p1-host_ident.patch Patch34: openssh-6.6p1-sftp_homechroot.patch Patch35: openssh-6.6p1-sftp_force_permissions.patch Patch36: openssh-6.6p1-seccomp_getuid.patch Patch37: openssh-6.6p1-X_forward_with_disabled_ipv6.patch +Patch38: openssh-6.6p1-fips-checks.patch Patch39: openssh-6.6p1-ldap.patch -Patch40: openssh-alloc_size.patch -Patch41: openssh-allow_getrandom.patch -Patch42: openssh-fix-b64_xx-detection.patch -BuildRequires: audit-devel -BuildRequires: autoconf -BuildRequires: fipscheck-devel -BuildRequires: groff -BuildRequires: openldap2-devel -BuildRequires: openssl -BuildRequires: openssl-devel -BuildRequires: pam-devel -Requires(post): %fillup_prereq -Requires(pre): coreutils -Requires(pre): pwdutils -Recommends: %{name}-helpers -Recommends: xauth -Conflicts: nonfreessh +Patch40: CVE-2016-0777_CVE-2016-0778.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build -%if %{has_krb_mini} -BuildRequires: krb5-mini-devel -%else -BuildRequires: krb5-devel -%endif -%if %{needs_libedit} -BuildRequires: libedit-devel -%endif -%if %{has_libselinux} -BuildRequires: libselinux-devel -%endif -%if %{uses_systemd} -BuildRequires: pkgconfig(systemd) -%{?systemd_requires} -%else -Requires(pre): %insserv_prereq -Requires(preun): %insserv_prereq -%endif %description SSH (Secure Shell) is a program for logging into and executing commands @@ -139,6 +164,7 @@ hosts over an insecure network. xorg-x11 (X Window System) connections and arbitrary TCP/IP ports can also be forwarded over the secure channel. + %package helpers Summary: OpenSSH AuthorizedKeysCommand helpers Group: Productivity/Networking/SSH @@ -147,6 +173,7 @@ Requires: openssh %description helpers Helper applications for OpenSSH which retrieve keys from various sources. + %package fips Summary: OpenSSH FIPS cryptomodule hashes Group: Productivity/Networking/SSH @@ -156,51 +183,77 @@ Requires: openssh Hashes that together with the main package form the FIPS certifiable cryptomodule. + %prep %setup -q -%patch1 -p2 +%patch0 -p2 +#patch1 -p2 %patch2 -p2 %patch3 -p2 %patch4 -p2 %patch5 -p2 %patch6 -p2 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 +%patch7 -p2 +%patch8 -p2 +%patch9 -p2 %patch10 -p2 %patch11 -p2 %patch12 -p2 %patch13 -p2 %patch14 -p2 -%patch15 -p1 -%patch18 -p1 -%patch28 -p1 -%patch29 -p1 +%patch15 -p2 +%patch16 -p2 +%patch17 -p2 +%patch18 -p2 +%patch19 -p2 +%patch20 -p2 +%patch21 -p2 +%patch22 -p2 +%patch23 -p2 +%patch24 -p2 +%patch25 -p2 +%patch26 -p2 +%if 0%{?suse_version} > 1310 +%patch27 -p2 +%endif +%patch28 -p2 +%patch29 -p2 %patch30 -p2 -%patch31 -p1 +%patch31 -p2 +%patch32 -p2 %patch33 -p2 -%patch34 -p1 -%patch35 -p1 -%patch36 -p1 +%patch34 -p2 +%patch35 -p2 +%patch36 -p2 %patch37 -p2 -%patch39 -p1 -%patch40 -p1 -%patch41 -p1 -%patch42 -p1 -%patch17 -p1 - +%patch38 -p2 +%patch39 -p2 +%patch40 -p0 cp %{SOURCE3} %{SOURCE4} . %build +# set libexec dir in the LDAP patch +sed -i.libexec 's,@LIBEXECDIR@,%{_libexecdir}/ssh,' \ + $( grep -Rl @LIBEXECDIR@ \ + $( grep "^+++" %{PATCH39} | sed -r 's@^.+/([^/\t ]+).*$@\1@' ) + ) + autoreconf -fiv -%ifarch s390 s390x %{sparc} +%ifarch s390 s390x %sparc PIEFLAGS="-fPIE" %else PIEFLAGS="-fpie" %endif CFLAGS="%{optflags} $PIEFLAGS -fstack-protector" +#%if 0%{?suse_version} < 1230 +#CFLAGS="-lrt $CFLAGS" +#%endif CXXFLAGS="%{optflags} $PIEFLAGS -fstack-protector" LDFLAGS="-pie -Wl,--as-needed" +#%if 0%{?suse_version} < 1230 +#LDFLAGS="-lrt $LDFLAGS" +#%endif +#CPPFLAGS="%{optflags} -DUSE_INTERNAL_B64" export LDFLAGS CFLAGS CXXFLAGS CPPFLAGS ./configure \ --prefix=%{_prefix} \ @@ -217,7 +270,7 @@ export LDFLAGS CFLAGS CXXFLAGS CPPFLAGS --with-ssl-engine \ --with-pam \ --with-kerberos5=%{_prefix} \ - --with-privsep-path=%{_localstatedir}/lib/empty \ + --with-privsep-path=/var/lib/empty \ %if %{sandbox_seccomp} --with-sandbox=seccomp_filter \ %else @@ -238,11 +291,14 @@ export LDFLAGS CFLAGS CXXFLAGS CPPFLAGS ### configure end make %{?_smp_mflags} +#make %{?_smp_mflags} -C converter + %install -make DESTDIR=%{buildroot} install %{?_smp_mflags} +make install DESTDIR=%{buildroot} +#make install DESTDIR=%{buildroot} -C converter install -d -m 755 %{buildroot}%{_sysconfdir}/pam.d -install -d -m 755 %{buildroot}%{_localstatedir}/lib/sshd +install -d -m 755 %{buildroot}/var/lib/sshd install -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/pam.d/sshd install -d -m 755 %{buildroot}%{_sysconfdir}/slp.reg.d/ install -m 644 %{SOURCE5} %{buildroot}%{_sysconfdir}/slp.reg.d/ @@ -250,20 +306,22 @@ install -d -m 755 %{buildroot}%{_initddir} %if %{uses_systemd} install -m 0755 %{SOURCE1} . install -D -m 0644 %{SOURCE10} %{buildroot}%{_unitdir}/sshd.service -ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rcsshd +ln -s /usr/sbin/service %{buildroot}%{_sbindir}/rcsshd %else 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}%{_localstatedir}/adm/fillup-templates -install -m 644 %{SOURCE8} %{buildroot}%{_localstatedir}/adm/fillup-templates +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 -sed -i -e s@%{_prefix}/libexec@%{_libexecdir}@g %{buildroot}%{_sysconfdir}/ssh/sshd_config +sed -i -e s@/usr/libexec@%{_libexecdir}@g %{buildroot}%{_sysconfdir}/ssh/sshd_config %if %{has_fw_dir} +#install firewall definitions format is described here: +#%{_datadir}/SuSEfirewall2/services/TEMPLATE mkdir -p %{buildroot}%{_fwdefdir} install -m 644 %{SOURCE7} %{buildroot}%{_fwdefdir}/sshd %endif @@ -279,7 +337,7 @@ install -D -m 0755 %{SOURCE9} %{buildroot}%{_sbindir}/sshd-gen-keys-start # re-define the __os_install_post macro: the macro strips # the binaries and thereby invalidates any hashes created earlier. # -# this shows up earlier because otherwise the %%expand of +# this shows up earlier because otherwise the %expand of # the macro is too late. %{expand:%%global __os_install_post {%__os_install_post @@ -295,7 +353,7 @@ done %pre getent group sshd >/dev/null || %{_sbindir}/groupadd -r sshd -getent passwd sshd >/dev/null || %{_sbindir}/useradd -r -g sshd -d %{_localstatedir}/lib/sshd -s /bin/false -c "SSH daemon" sshd +getent passwd sshd >/dev/null || %{_sbindir}/useradd -r -g sshd -d /var/lib/sshd -s /bin/false -c "SSH daemon" sshd %if %{uses_systemd} %service_add_pre sshd.service %endif @@ -320,7 +378,7 @@ getent passwd sshd >/dev/null || %{_sbindir}/useradd -r -g sshd -d %{_localstate %service_del_postun sshd.service %else %restart_on_update sshd -%insserv_cleanup +%{insserv_cleanup} %endif %files @@ -328,32 +386,36 @@ getent passwd sshd >/dev/null || %{_sbindir}/useradd -r -g sshd -d %{_localstate %exclude %{_bindir}/*.chk %exclude %{_sbindir}/*.chk %exclude %{_libexecdir}/ssh/sftp-server.chk -%dir %attr(755,root,root) %{_localstatedir}/lib/sshd -%doc README.SUSE README.kerberos ChangeLog OVERVIEW README TODO LICENCE CREDITS +%dir %attr(755,root,root) /var/lib/sshd +%doc README.SuSE README.kerberos ChangeLog OVERVIEW README TODO LICENCE CREDITS %attr(0755,root,root) %dir %{_sysconfdir}/ssh %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/moduli %verify(not mode) %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ssh_config %verify(not mode) %attr(0640,root,root) %config(noreplace) %{_sysconfdir}/ssh/sshd_config %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/pam.d/sshd %if %{uses_systemd} -%attr(0644,root,root) %{_unitdir}/sshd.service +%doc sshd.init +%attr(0644,root,root) %config %{_unitdir}/sshd.service %else %attr(0755,root,root) %config %{_initddir}/sshd +%doc sshd.service %endif %attr(0755,root,root) %{_bindir}/* %attr(0755,root,root) %{_sbindir}/* %attr(0755,root,root) %dir %{_libexecdir}/ssh %exclude %{_libexecdir}/ssh/ssh-ldap* %attr(0755,root,root) %{_libexecdir}/ssh/* -%attr(0444,root,root) %{_mandir}/man1/* -%attr(0444,root,root) %{_mandir}/man5/* -%attr(0444,root,root) %{_mandir}/man8/* +%attr(0444,root,root) %doc %{_mandir}/man1/* +%attr(0444,root,root) %doc %{_mandir}/man5/* +%attr(0444,root,root) %doc %{_mandir}/man8/* %dir %{_sysconfdir}/slp.reg.d %config %{_sysconfdir}/slp.reg.d/ssh.reg -%{_localstatedir}/adm/fillup-templates/sysconfig.ssh +/var/adm/fillup-templates/sysconfig.ssh %if %{has_fw_dir} +%if %{needs_all_dirs} %dir %{_fwdir} %dir %{_fwdefdir} +%endif %config %{_fwdefdir}/sshd %endif