diff options
Diffstat (limited to 'backport-openssh-7.6p1-audit.patch')
-rw-r--r-- | backport-openssh-7.6p1-audit.patch | 2342 |
1 files changed, 2342 insertions, 0 deletions
diff --git a/backport-openssh-7.6p1-audit.patch b/backport-openssh-7.6p1-audit.patch new file mode 100644 index 0000000..7f68f36 --- /dev/null +++ b/backport-openssh-7.6p1-audit.patch @@ -0,0 +1,2342 @@ +diff -up openssh-8.6p1/audit-bsm.c.audit openssh-8.6p1/audit-bsm.c +--- openssh-8.6p1/audit-bsm.c.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/audit-bsm.c 2021-04-19 16:47:35.753062106 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -373,13 +373,26 @@ audit_connection_from(const char *host, + #endif + } + ++int ++audit_run_command(struct ssh *ssh, const char *command) ++{ ++ /* not implemented */ ++ return 0; ++} ++ + void +-audit_run_command(const char *command) ++audit_end_command(struct ssh *ssh, int handle, const char *command) + { + /* not implemented */ + } + + void ++audit_count_session_open(void) ++{ ++ /* not necessary */ ++} ++ ++void + audit_session_open(struct logininfo *li) + { + /* not implemented */ +@@ -391,6 +404,12 @@ audit_session_close(struct logininfo *li + /* not implemented */ + } + ++int ++audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++{ ++ /* not implemented */ ++} ++ + void + audit_event(struct ssh *ssh, ssh_audit_event_t event) + { +@@ -452,4 +471,28 @@ audit_event(struct ssh *ssh, ssh_audit_e + debug("%s: unhandled event %d", __func__, event); + } + } ++ ++void ++audit_unsupported_body(struct ssh *ssh, int what) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_session_key_free_body(struct ssh * ssh, int ctos, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} + #endif /* BSM */ +diff -up openssh-8.6p1/audit.c.audit openssh-8.6p1/audit.c +--- openssh-8.6p1/audit.c.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/audit.c 2021-04-19 16:47:35.753062106 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -34,6 +34,12 @@ + #include "log.h" + #include "hostfile.h" + #include "auth.h" ++#include "ssh-gss.h" ++#include "monitor_wrap.h" ++#include "xmalloc.h" ++#include "misc.h" ++#include "servconf.h" ++#include "ssherr.h" + + /* + * Care must be taken when using this since it WILL NOT be initialized when +@@ -41,6 +47,7 @@ + * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. + */ + extern Authctxt *the_authctxt; ++extern ServerOptions options; + + /* Maybe add the audit class to struct Authmethod? */ + ssh_audit_event_t +@@ -69,13 +76,10 @@ audit_classify_auth(const char *method) + const char * + audit_username(void) + { +- static const char unknownuser[] = "(unknown user)"; +- static const char invaliduser[] = "(invalid user)"; ++ static const char unknownuser[] = "(unknown)"; + +- if (the_authctxt == NULL || the_authctxt->user == NULL) ++ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) + return (unknownuser); +- if (!the_authctxt->valid) +- return (invaliduser); + return (the_authctxt->user); + } + +@@ -109,6 +113,35 @@ audit_event_lookup(ssh_audit_event_t ev) + return(event_lookup[i].name); + } + ++void ++audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) ++{ ++ char *fp; ++ ++ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) ++ *rv = -SSH_ERR_INTERNAL_ERROR; ++ free(fp); ++} ++ ++void ++audit_unsupported(struct ssh *ssh, int what) ++{ ++ PRIVSEP(audit_unsupported_body(ssh, what)); ++} ++ ++void ++audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs) ++{ ++ PRIVSEP(audit_kex_body(ssh, ctos, enc, mac, comp, pfs, getpid(), getuid())); ++} ++ ++void ++audit_session_key_free(struct ssh *ssh, int ctos) ++{ ++ PRIVSEP(audit_session_key_free_body(ssh, ctos, getpid(), getuid())); ++} ++ + # ifndef CUSTOM_SSH_AUDIT_EVENTS + /* + * Null implementations of audit functions. +@@ -138,6 +171,17 @@ audit_event(struct ssh *ssh, ssh_audit_e + } + + /* ++ * Called when a child process has called, or will soon call, ++ * audit_session_open. ++ */ ++void ++audit_count_session_open(void) ++{ ++ debug("audit count session open euid %d user %s", geteuid(), ++ audit_username()); ++} ++ ++/* + * Called when a user session is started. Argument is the tty allocated to + * the session, or NULL if no tty was allocated. + * +@@ -172,13 +216,82 @@ audit_session_close(struct logininfo *li + /* + * This will be called when a user runs a non-interactive command. Note that + * it may be called multiple times for a single connection since SSH2 allows +- * multiple sessions within a single connection. ++ * multiple sessions within a single connection. Returns a "handle" for ++ * audit_end_command. + */ +-void +-audit_run_command(const char *command) ++int ++audit_run_command(struct ssh *ssh, 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(struct ssh *ssh, 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(struct ssh *ssh, int host_user, char *fp, int rv) ++{ ++ debug("audit %s key usage euid %d user %s fingerprint %s, result %d", ++ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), ++ fp, rv); ++} ++ ++/* ++ * This will be called when the protocol negotiation fails. ++ */ ++void ++audit_unsupported_body(struct ssh *ssh, int what) ++{ ++ debug("audit unsupported protocol euid %d type %d", geteuid(), what); ++} ++ ++/* ++ * This will be called on succesfull protocol negotiation. ++ */ ++void ++audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, ++ uid_t uid) ++{ ++ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, ++ (unsigned)uid); ++} ++ ++/* ++ * This will be called on succesfull session key discard ++ */ ++void ++audit_session_key_free_body(struct ssh *, int ctos, pid_t pid, uid_t uid) ++{ ++ debug("audit session key discard euid %u direction %d from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); ++} ++ ++/* ++ * This will be called on destroy private part of the server key ++ */ ++void ++audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) ++{ ++ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", ++ geteuid(), fp, (long)pid, (unsigned)uid); + } + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff -up openssh-8.6p1/audit.h.audit openssh-8.6p1/audit.h +--- openssh-8.6p1/audit.h.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/audit.h 2021-04-19 16:47:35.753062106 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -26,6 +26,7 @@ + # define _SSH_AUDIT_H + + #include "loginrec.h" ++#include "sshkey.h" + + struct ssh; + +@@ -45,13 +46,32 @@ enum ssh_audit_event_type { + SSH_CONNECTION_ABANDON, /* closed without completing auth */ + SSH_AUDIT_UNKNOWN + }; ++ ++enum ssh_audit_kex { ++ SSH_AUDIT_UNSUPPORTED_CIPHER, ++ SSH_AUDIT_UNSUPPORTED_MAC, ++ SSH_AUDIT_UNSUPPORTED_COMPRESSION ++}; + typedef enum ssh_audit_event_type ssh_audit_event_t; + ++int listening_for_clients(void); ++ + void audit_connection_from(const char *, int); + void audit_event(struct ssh *, ssh_audit_event_t); ++void audit_count_session_open(void); + void audit_session_open(struct logininfo *); + void audit_session_close(struct logininfo *); +-void audit_run_command(const char *); ++int audit_run_command(struct ssh *, const char *); ++void audit_end_command(struct ssh *, int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); ++int audit_keyusage(struct ssh *, int, char *, int); ++void audit_key(struct ssh *, int, int *, const struct sshkey *); ++void audit_unsupported(struct ssh *, int); ++void audit_kex(struct ssh *, int, char *, char *, char *, char *); ++void audit_unsupported_body(struct ssh *, int); ++void audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); ++void audit_session_key_free(struct ssh *, int ctos); ++void audit_session_key_free_body(struct ssh *, int ctos, pid_t, uid_t); ++void audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); + + #endif /* _SSH_AUDIT_H */ +diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c +--- openssh-8.6p1/audit-linux.c.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/audit-linux.c 2021-04-19 16:47:35.753062106 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -33,27 +33,40 @@ + + #include "log.h" + #include "audit.h" ++#include "sshkey.h" ++#include "hostfile.h" ++#include "auth.h" ++#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ ++#include "servconf.h" + #include "canohost.h" + #include "packet.h" +- ++#include "cipher.h" ++#include "channels.h" ++#include "session.h" ++ ++#define AUDIT_LOG_SIZE 256 ++ ++extern ServerOptions options; ++extern Authctxt *the_authctxt; ++extern u_int utmp_len; + const char *audit_username(void); + +-int +-linux_audit_record_event(int uid, const char *username, const char *hostname, +- const char *ip, const char *ttyn, int success) ++static void ++linux_audit_user_logxxx(int uid, const char *username, ++ const char *ip, const char *ttyn, int success, int event) + { + int audit_fd, rc, saved_errno; + + if ((audit_fd = audit_open()) < 0) { + if (errno == EINVAL || errno == EPROTONOSUPPORT || + errno == EAFNOSUPPORT) +- return 1; /* No audit support in kernel */ ++ return; /* No audit support in kernel */ + else +- return 0; /* Must prevent login */ ++ goto fatal_report; /* Must prevent login */ + } +- rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, ++ rc = audit_log_acct_message(audit_fd, event, + NULL, "login", username ? username : "(unknown)", +- username == NULL ? uid : -1, hostname, ip, ttyn, success); ++ username == NULL ? uid : -1, NULL, ip, ttyn, success); + saved_errno = errno; + close(audit_fd); + +@@ -65,9 +78,96 @@ linux_audit_record_event(int uid, const + rc = 0; + errno = saved_errno; + +- return rc >= 0; ++ if (rc < 0) { ++fatal_report: ++ fatal("linux_audit_write_entry failed: %s", strerror(errno)); ++ } ++} ++ ++static void ++linux_audit_user_auth(int uid, const char *username, ++ const char *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, 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; ++ errno = saved_errno; ++ if (rc < 0) { ++fatal_report: ++ fatal("linux_audit_write_entry failed: %s", strerror(errno)); ++ } ++} ++ ++int ++audit_keyusage(struct ssh *ssh, int host_user, 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 grantors=auth-key", host_user ? "pubkey" : "hostbased"); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp); ++ rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, ++ ssh_remote_ipaddr(ssh), NULL, rv); ++out: ++ saved_errno = errno; ++ audit_close(audit_fd); ++ errno = saved_errno; ++ /* do not report error if the error is EPERM and sshd is run as non root user */ ++ return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0)); + } + ++static int user_login_count = 0; ++ + /* Below is the sshd audit API code */ + + void +@@ -76,49 +176,210 @@ audit_connection_from(const char *host, + /* not implemented */ + } + ++int ++audit_run_command(struct ssh *ssh, const char *command) ++{ ++ if (!user_login_count++) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ ssh_remote_ipaddr(ssh), ++ "ssh", 1, AUDIT_USER_LOGIN); ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ ssh_remote_ipaddr(ssh), ++ "ssh", 1, AUDIT_USER_START); ++ return 0; ++} ++ + void +-audit_run_command(const char *command) ++audit_end_command(struct ssh *ssh, int handle, const char *command) + { +- /* not implemented */ ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ ssh_remote_ipaddr(ssh), ++ "ssh", 1, AUDIT_USER_END); ++ if (user_login_count && !--user_login_count) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ ssh_remote_ipaddr(ssh), ++ "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, ++ li->line, 1, AUDIT_USER_LOGIN); ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ li->line, 1, AUDIT_USER_START); + } + + void + audit_session_close(struct logininfo *li) + { +- /* not implemented */ ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ li->line, 1, AUDIT_USER_END); ++ if (user_login_count && !--user_login_count) ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ li->line, 1, AUDIT_USER_LOGOUT); + } + + void + audit_event(struct ssh *ssh, 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(), ++ ssh_remote_ipaddr(ssh), "ssh", 0, event); ++ linux_audit_user_logxxx(-1, audit_username(), ++ ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); + break; +- case SSH_AUTH_FAIL_NONE: + case SSH_AUTH_FAIL_PASSWD: ++ if (options.use_pam) ++ break; ++ case SSH_LOGIN_EXCEED_MAXTRIES: + 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(), ++ ssh_remote_ipaddr(ssh), "ssh", 0, event); ++ break; ++ ++ case SSH_CONNECTION_CLOSE: ++ if (user_login_count) { ++ while (user_login_count--) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ ssh_remote_ipaddr(ssh), ++ "ssh", 1, AUDIT_USER_END); ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ ssh_remote_ipaddr(ssh), ++ "ssh", 1, AUDIT_USER_LOGOUT); ++ } ++ break; ++ ++ case SSH_CONNECTION_ABANDON: + case SSH_INVALID_USER: +- linux_audit_record_event(-1, audit_username(), NULL, +- ssh_remote_ipaddr(ssh), "sshd", 0); ++ linux_audit_user_logxxx(-1, audit_username(), ++ ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); + break; + default: + debug("%s: unhandled event %d", __func__, event); + break; + } + } ++ ++void ++audit_unsupported_body(struct ssh *ssh, int what) ++{ ++#ifdef AUDIT_CRYPTO_SESSION ++ char buf[AUDIT_LOG_SIZE]; ++ const static char *name[] = { "cipher", "mac", "comp" }; ++ char *s; ++ int audit_fd; ++ ++ snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ", ++ name[what], ssh_remote_port(ssh), (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))), ++ ssh_local_port(ssh)); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) ++ /* no problem, the next instruction will be fatal() */ ++ return; ++ audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, ++ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 0); ++ audit_close(audit_fd); ++#endif ++} ++ ++const static char *direction[] = { "from-server", "from-client", "both" }; ++ ++void ++audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, ++ char *pfs, pid_t pid, uid_t uid) ++{ ++#ifdef AUDIT_CRYPTO_SESSION ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ const struct sshcipher *cipher = cipher_by_name(enc); ++ char *s; ++ ++ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", ++ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs, ++ (intmax_t)pid, (intmax_t)uid, ++ ssh_remote_port(ssh), (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))), ssh_local_port(ssh)); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return; /* No audit support in kernel */ ++ else ++ fatal("cannot open audit"); /* Must prevent login */ ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, ++ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ fatal("cannot write into audit"); /* Must prevent login */ ++#endif ++} ++ ++void ++audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ char *s; ++ ++ snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", ++ direction[ctos], (intmax_t)pid, (intmax_t)uid, ++ ssh_remote_port(ssh), ++ (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))), ++ ssh_local_port(ssh)); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno != EINVAL && errno != EPROTONOSUPPORT && ++ errno != EAFNOSUPPORT) ++ error("cannot open audit"); ++ return; ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, ++ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ error("cannot write into audit"); ++} ++ ++void ++audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ ++ snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ", ++ fp, (intmax_t)pid, (intmax_t)uid); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno != EINVAL && errno != EPROTONOSUPPORT && ++ errno != EAFNOSUPPORT) ++ error("cannot open audit"); ++ return; ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, ++ buf, NULL, ++ listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh), ++ NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ error("cannot write into audit"); ++} + #endif /* USE_LINUX_AUDIT */ +diff -up openssh-8.6p1/auditstub.c.audit openssh-8.6p1/auditstub.c +--- openssh-8.6p1/auditstub.c.audit 2021-04-19 16:47:35.754062114 +0200 ++++ openssh-8.6p1/auditstub.c 2021-04-19 16:47:35.754062114 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -0,0 +1,52 @@ ++/* $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 <jchadima@redhat.com> ++ */ ++ ++#include <sys/types.h> ++ ++struct ssh; ++ ++void ++audit_unsupported(struct ssh *ssh, int n) ++{ ++} ++ ++void ++audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs) ++{ ++} ++ ++void ++audit_session_key_free(struct ssh *ssh, int ctos) ++{ ++} ++ ++void ++audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid) ++{ ++} +diff -up openssh-8.6p1/auth2.c.audit openssh-8.6p1/auth2.c +--- openssh-8.6p1/auth2.c.audit 2021-04-19 16:47:35.682061561 +0200 ++++ openssh-8.6p1/auth2.c 2021-04-19 16:47:35.754062114 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -298,9 +298,6 @@ input_userauth_request(int type, u_int32 + } else { + /* Invalid user, fake password information */ + authctxt->pw = fakepw(); +-#ifdef SSH_AUDIT_EVENTS +- PRIVSEP(audit_event(ssh, SSH_INVALID_USER)); +-#endif + } + #ifdef USE_PAM + if (options.use_pam) +diff -up openssh-8.6p1/auth2-hostbased.c.audit openssh-8.6p1/auth2-hostbased.c +--- openssh-8.6p1/auth2-hostbased.c.audit 2021-04-19 16:47:35.656061361 +0200 ++++ openssh-8.6p1/auth2-hostbased.c 2021-04-19 16:47:35.754062114 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -158,7 +158,7 @@ userauth_hostbased(struct ssh *ssh) + authenticated = 0; + if (PRIVSEP(hostbased_key_allowed(ssh, authctxt->pw, cuser, + chost, key)) && +- PRIVSEP(sshkey_verify(key, sig, slen, ++ PRIVSEP(hostbased_key_verify(ssh, key, sig, slen, + sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat, NULL)) == 0) + authenticated = 1; + +@@ -175,6 +175,20 @@ done: + return authenticated; + } + ++int ++hostbased_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, ++ size_t slen, const u_char *data, size_t datalen, const char *pkalg, u_int compat, ++ struct sshkey_sig_details **detailsp) ++{ ++ int rv; ++ ++ rv = sshkey_verify(key, sig, slen, data, datalen, pkalg, compat, detailsp); ++#ifdef SSH_AUDIT_EVENTS ++ audit_key(ssh, 0, &rv, key); ++#endif ++ return rv; ++} ++ + /* return 1 if given hostkey is allowed */ + int + hostbased_key_allowed(struct ssh *ssh, struct passwd *pw, +diff -up openssh-8.6p1/auth2-pubkey.c.audit openssh-8.6p1/auth2-pubkey.c +--- openssh-8.6p1/auth2-pubkey.c.audit 2021-04-19 16:47:35.726061899 +0200 ++++ openssh-8.6p1/auth2-pubkey.c 2021-04-19 16:47:35.754062114 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -213,7 +213,7 @@ userauth_pubkey(struct ssh *ssh) + /* test for correct signature */ + authenticated = 0; + if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && +- PRIVSEP(sshkey_verify(key, sig, slen, ++ PRIVSEP(user_key_verify(ssh, key, sig, slen, + sshbuf_ptr(b), sshbuf_len(b), + (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, + ssh->compat, &sig_details)) == 0) { +@@ -305,6 +305,20 @@ done: + return authenticated; + } + ++int ++user_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, ++ size_t slen, const u_char *data, size_t datalen, const char *pkalg, u_int compat, ++ struct sshkey_sig_details **detailsp) ++{ ++ int rv; ++ ++ rv = sshkey_verify(key, sig, slen, data, datalen, pkalg, compat, detailsp); ++#ifdef SSH_AUDIT_EVENTS ++ audit_key(ssh, 1, &rv, key); ++#endif ++ return rv; ++} ++ + static int + match_principals_option(const char *principal_list, struct sshkey_cert *cert) + { +diff -up openssh-8.6p1/auth.c.audit openssh-8.6p1/auth.c +--- openssh-8.6p1/auth.c.audit 2021-04-19 16:47:35.681061553 +0200 ++++ openssh-8.6p1/auth.c 2021-04-19 16:47:35.754062114 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -597,9 +597,6 @@ getpwnamallow(struct ssh *ssh, const cha + record_failed_login(ssh, user, + auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); + #endif +-#ifdef SSH_AUDIT_EVENTS +- audit_event(ssh, SSH_INVALID_USER); +-#endif /* SSH_AUDIT_EVENTS */ + return (NULL); + } + if (!allowed_user(ssh, pw)) +diff -up openssh-8.6p1/auth.h.audit openssh-8.6p1/auth.h +--- openssh-8.6p1/auth.h.audit 2021-04-19 16:47:35.697061676 +0200 ++++ openssh-8.6p1/auth.h 2021-04-19 16:47:35.754062114 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -193,6 +193,8 @@ struct passwd * getpwnamallow(struct ssh + + char *expand_authorized_keys(const char *, struct passwd *pw); + char *authorized_principals_file(struct passwd *); ++int user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); + + FILE *auth_openkeyfile(const char *, struct passwd *, int); + FILE *auth_openprincipals(const char *, struct passwd *, int); +@@ -212,6 +214,8 @@ struct sshkey *get_hostkey_private_by_ty + int get_hostkey_index(struct sshkey *, int, struct ssh *); + int sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *, + u_char **, size_t *, const u_char *, size_t, const char *); ++int hostbased_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); + + /* Key / cert options linkage to auth layer */ + const struct sshauthopt *auth_options(struct ssh *); +diff -up openssh-8.6p1/cipher.c.audit openssh-8.6p1/cipher.c +--- openssh-8.6p1/cipher.c.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/cipher.c 2021-04-19 16:47:35.755062122 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -64,25 +64,6 @@ struct sshcipher_ctx { + const struct sshcipher *cipher; + }; + +-struct sshcipher { +- char *name; +- u_int block_size; +- u_int key_len; +- u_int iv_len; /* defaults to block_size */ +- u_int auth_len; +- u_int flags; +-#define CFLAG_CBC (1<<0) +-#define CFLAG_CHACHAPOLY (1<<1) +-#define CFLAG_AESCTR (1<<2) +-#define CFLAG_NONE (1<<3) +-#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */ +-#ifdef WITH_OPENSSL +- const EVP_CIPHER *(*evptype)(void); +-#else +- void *ignored; +-#endif +-}; +- + static const struct sshcipher ciphers[] = { + #ifdef WITH_OPENSSL + #ifndef OPENSSL_NO_DES +@@ -422,7 +403,7 @@ cipher_get_length(struct sshcipher_ctx * + void + cipher_free(struct sshcipher_ctx *cc) + { +- if (cc == NULL) ++ if (cc == NULL || cc->cipher == NULL) + return; + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { + chachapoly_free(cc->cp_ctx); +diff -up openssh-8.6p1/cipher.h.audit openssh-8.6p1/cipher.h +--- openssh-8.6p1/cipher.h.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/cipher.h 2021-04-19 16:47:35.755062122 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -47,7 +47,25 @@ + #define CIPHER_ENCRYPT 1 + #define CIPHER_DECRYPT 0 + +-struct sshcipher; ++struct sshcipher { ++ char *name; ++ u_int block_size; ++ u_int key_len; ++ u_int iv_len; /* defaults to block_size */ ++ u_int auth_len; ++ u_int flags; ++#define CFLAG_CBC (1<<0) ++#define CFLAG_CHACHAPOLY (1<<1) ++#define CFLAG_AESCTR (1<<2) ++#define CFLAG_NONE (1<<3) ++#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */ ++#ifdef WITH_OPENSSL ++ const EVP_CIPHER *(*evptype)(void); ++#else ++ void *ignored; ++#endif ++}; ++ + struct sshcipher_ctx; + + const struct sshcipher *cipher_by_name(const char *); +diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c +--- openssh-8.6p1/kex.c.audit 2021-04-19 16:47:35.743062030 +0200 ++++ openssh-8.6p1/kex.c 2021-04-19 16:47:35.755062122 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -65,6 +65,7 @@ + #include "ssherr.h" + #include "sshbuf.h" + #include "digest.h" ++#include "audit.h" + + #ifdef GSSAPI + #include "ssh-gss.h" +@@ -816,12 +817,16 @@ kex_start_rekex(struct ssh *ssh) + } + + static int +-choose_enc(struct sshenc *enc, char *client, char *server) ++choose_enc(struct ssh *ssh, struct sshenc *enc, char *client, char *server) + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_CIPHER); ++#endif + return SSH_ERR_NO_CIPHER_ALG_MATCH; ++ } + if ((enc->cipher = cipher_by_name(name)) == NULL) { + error_f("unsupported cipher %s", name); + free(name); +@@ -842,8 +847,12 @@ choose_mac(struct ssh *ssh, struct sshma + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_MAC); ++#endif + return SSH_ERR_NO_MAC_ALG_MATCH; ++ } + if (mac_setup(mac, name) < 0) { + error_f("unsupported MAC %s", name); + free(name); +@@ -856,12 +865,16 @@ choose_mac(struct ssh *ssh, struct sshma + } + + static int +-choose_comp(struct sshcomp *comp, char *client, char *server) ++choose_comp(struct ssh *ssh, struct sshcomp *comp, char *client, char *server) + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_COMPRESSION); ++#endif + return SSH_ERR_NO_COMPRESS_ALG_MATCH; ++ } + #ifdef WITH_ZLIB + if (strcmp(name, "zlib@openssh.com") == 0) { + comp->type = COMP_DELAYED; +@@ -1002,7 +1015,7 @@ kex_choose_conf(struct ssh *ssh) + nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; + nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; + ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; +- if ((r = choose_enc(&newkeys->enc, cprop[nenc], ++ if ((r = choose_enc(ssh, &newkeys->enc, cprop[nenc], + sprop[nenc])) != 0) { + kex->failed_choice = peer[nenc]; + peer[nenc] = NULL; +@@ -1017,7 +1030,7 @@ kex_choose_conf(struct ssh *ssh) + peer[nmac] = NULL; + goto out; + } +- if ((r = choose_comp(&newkeys->comp, cprop[ncomp], ++ if ((r = choose_comp(ssh, &newkeys->comp, cprop[ncomp], + sprop[ncomp])) != 0) { + kex->failed_choice = peer[ncomp]; + peer[ncomp] = NULL; +@@ -1040,6 +1053,10 @@ kex_choose_conf(struct ssh *ssh) + dh_need = MAXIMUM(dh_need, newkeys->enc.block_size); + dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len); + dh_need = MAXIMUM(dh_need, newkeys->mac.key_len); ++ debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need); ++#ifdef SSH_AUDIT_EVENTS ++ audit_kex(ssh, mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name); ++#endif + } + /* XXX need runden? */ + kex->we_need = need; +@@ -1297,6 +1314,36 @@ dump_digest(const char *msg, const u_cha + } + #endif + ++static void ++enc_destroy(struct sshenc *enc) ++{ ++ if (enc == NULL) ++ return; ++ ++ if (enc->key) { ++ memset(enc->key, 0, enc->key_len); ++ free(enc->key); ++ } ++ ++ if (enc->iv) { ++ memset(enc->iv, 0, enc->iv_len); ++ free(enc->iv); ++ } ++ ++ memset(enc, 0, sizeof(*enc)); ++} ++ ++void ++newkeys_destroy(struct newkeys *newkeys) ++{ ++ if (newkeys == NULL) ++ return; ++ ++ enc_destroy(&newkeys->enc); ++ mac_destroy(&newkeys->mac); ++ memset(&newkeys->comp, 0, sizeof(newkeys->comp)); ++} ++ + /* + * Send a plaintext error message to the peer, suffixed by \r\n. + * Only used during banner exchange, and there only for the server. +diff -up openssh-8.6p1/kex.h.audit openssh-8.6p1/kex.h +--- openssh-8.6p1/kex.h.audit 2021-04-19 16:47:35.683061568 +0200 ++++ openssh-8.6p1/kex.h 2021-04-19 16:47:35.756062129 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -226,6 +226,8 @@ int kexgss_client(struct ssh *); + int kexgss_server(struct ssh *); + #endif + ++void newkeys_destroy(struct newkeys *newkeys); ++ + int kex_dh_keypair(struct kex *); + int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, + struct sshbuf **); +diff -up openssh-8.6p1/mac.c.audit openssh-8.6p1/mac.c +--- openssh-8.6p1/mac.c.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/mac.c 2021-04-19 16:47:35.756062129 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -239,6 +239,20 @@ mac_clear(struct sshmac *mac) + mac->umac_ctx = NULL; + } + ++void ++mac_destroy(struct sshmac *mac) ++{ ++ if (mac == NULL) ++ return; ++ ++ if (mac->key) { ++ memset(mac->key, 0, mac->key_len); ++ free(mac->key); ++ } ++ ++ memset(mac, 0, sizeof(*mac)); ++} ++ + /* XXX copied from ciphers_valid */ + #define MAC_SEP "," + int +diff -up openssh-8.6p1/mac.h.audit openssh-8.6p1/mac.h +--- openssh-8.6p1/mac.h.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/mac.h 2021-04-19 16:47:35.756062129 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int3 + int mac_check(struct sshmac *, u_int32_t, const u_char *, size_t, + const u_char *, size_t); + void mac_clear(struct sshmac *); ++void mac_destroy(struct sshmac *); + + #endif /* SSHMAC_H */ +diff -up openssh-8.6p1/Makefile.in.audit openssh-8.6p1/Makefile.in +--- openssh-8.6p1/Makefile.in.audit 2021-04-19 16:47:35.731061937 +0200 ++++ openssh-8.6p1/Makefile.in 2021-04-19 16:47:35.756062129 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -112,7 +112,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kexsntrup761x25519.o sntrup761.o kexgen.o \ + kexgssc.o \ + sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ +- sshbuf-io.o ++ sshbuf-io.o auditstub.o + + SKOBJS= ssh-sk-client.o + +diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c +--- openssh-8.6p1/monitor.c.audit 2021-04-19 16:47:35.707061753 +0200 ++++ openssh-8.6p1/monitor.c 2021-04-19 16:47:35.756062129 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -93,6 +93,7 @@ + #include "compat.h" + #include "ssh2.h" + #include "authfd.h" ++#include "audit.h" + #include "match.h" + #include "ssherr.h" + #include "sk-api.h" +@@ -107,6 +108,8 @@ extern u_int utmp_len; + extern struct sshbuf *loginmsg; + extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ + ++extern void destroy_sensitive_data(struct ssh *, int); ++ + /* State exported from the child */ + static struct sshbuf *child_state; + +@@ -157,6 +160,11 @@ int mm_answer_gss_updatecreds(struct ssh + #ifdef SSH_AUDIT_EVENTS + int mm_answer_audit_event(struct ssh *, int, struct sshbuf *); + int mm_answer_audit_command(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_end_command(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_unsupported_body(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_kex_body(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_session_key_free_body(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_server_key_free(struct ssh *, int, struct sshbuf *); + #endif + + static Authctxt *authctxt; +@@ -215,6 +223,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} + }; +@@ -1444,8 +1461,10 @@ mm_answer_keyverify(struct ssh *ssh, int + int r, ret, req_presence = 0, req_verify = 0, valid_data = 0; + int encoded_ret; + struct sshkey_sig_details *sig_details = NULL; ++ int type = 0; + +- if ((r = sshbuf_get_string_direct(m, &blob, &bloblen)) != 0 || ++ if ((r = sshbuf_get_u32(m, &type)) != 0 || ++ (r = sshbuf_get_string_direct(m, &blob, &bloblen)) != 0 || + (r = sshbuf_get_string_direct(m, &signature, &signaturelen)) != 0 || + (r = sshbuf_get_string_direct(m, &data, &datalen)) != 0 || + (r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0) +@@ -1454,6 +1473,8 @@ mm_answer_keyverify(struct ssh *ssh, int + if (hostbased_cuser == NULL || hostbased_chost == NULL || + !monitor_allowed_key(blob, bloblen)) + fatal_f("bad key, not previously allowed"); ++ if (type != key_blobtype) ++ fatal_f("bad key type"); + + /* Empty signature algorithm means NULL. */ + if (*sigalg == '\0') { +@@ -1469,14 +1490,19 @@ mm_answer_keyverify(struct ssh *ssh, int + case MM_USERKEY: + valid_data = monitor_valid_userblob(ssh, data, datalen); + auth_method = "publickey"; ++ ret = user_key_verify(ssh, key, signature, signaturelen, data, ++ datalen, sigalg, ssh->compat, &sig_details); + break; + case MM_HOSTKEY: + valid_data = monitor_valid_hostbasedblob(data, datalen, + hostbased_cuser, hostbased_chost); + auth_method = "hostbased"; ++ ret = hostbased_key_verify(ssh, key, signature, signaturelen, data, ++ datalen, sigalg, ssh->compat, &sig_details); + break; + default: + valid_data = 0; ++ ret = 0; + break; + } + if (!valid_data) +@@ -1488,8 +1514,6 @@ mm_answer_keyverify(struct ssh *ssh, int + SSH_FP_DEFAULT)) == NULL) + fatal_f("sshkey_fingerprint failed"); + +- ret = sshkey_verify(key, signature, signaturelen, data, datalen, +- sigalg, ssh->compat, &sig_details); + debug3_f("%s %s signature %s%s%s", auth_method, sshkey_type(key), + (ret == 0) ? "verified" : "unverified", + (ret != 0) ? ": " : "", (ret != 0) ? ssh_err(ret) : ""); +@@ -1576,13 +1600,19 @@ mm_record_login(struct ssh *ssh, Session + } + + static void +-mm_session_close(Session *s) ++mm_session_close(struct ssh *ssh, Session *s) + { + debug3_f("session %d pid %ld", s->self, (long)s->pid); + if (s->ttyfd != -1) { + debug3_f("tty %s ptyfd %d", s->tty, s->ptyfd); + session_pty_cleanup2(s); + } ++#ifdef SSH_AUDIT_EVENTS ++ if (s->command != NULL) { ++ debug3_f("command %d", s->command_handle); ++ session_end_command2(ssh, s); ++ } ++#endif + session_unused(s->self); + } + +@@ -1649,7 +1679,7 @@ mm_answer_pty(struct ssh *ssh, int sock, + + error: + if (s != NULL) +- mm_session_close(s); ++ mm_session_close(ssh, s); + if ((r = sshbuf_put_u32(m, 0)) != 0) + fatal_fr(r, "assemble 0"); + mm_request_send(sock, MONITOR_ANS_PTY, m); +@@ -1668,7 +1698,7 @@ mm_answer_pty_cleanup(struct ssh *ssh, i + if ((r = sshbuf_get_cstring(m, &tty, NULL)) != 0) + fatal_fr(r, "parse tty"); + if ((s = session_by_tty(tty)) != NULL) +- mm_session_close(s); ++ mm_session_close(ssh, s); + sshbuf_reset(m); + free(tty); + return (0); +@@ -1690,6 +1720,8 @@ mm_answer_term(struct ssh *ssh, int sock + sshpam_cleanup(); + #endif + ++ destroy_sensitive_data(ssh, 0); ++ + while (waitpid(pmonitor->m_pid, &status, 0) == -1) + if (errno != EINTR) + exit(1); +@@ -1736,12 +1768,47 @@ mm_answer_audit_command(struct ssh *ssh, + { + char *cmd; + int r; ++ Session *s; + + debug3("%s entering", __func__); + if ((r = sshbuf_get_cstring(m, &cmd, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ + /* sanity check command, if so how? */ +- audit_run_command(cmd); ++ s = session_new(); ++ if (s == NULL) ++ fatal_f("error allocating a session"); ++ s->command = cmd; ++#ifdef SSH_AUDIT_EVENTS ++ s->command_handle = audit_run_command(ssh, cmd); ++#endif ++ ++ sshbuf_reset(m); ++ sshbuf_put_u32(m, s->self); ++ ++ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); ++ ++ return (0); ++} ++ ++int ++mm_answer_audit_end_command(struct ssh *ssh, int socket, struct sshbuf *m) ++{ ++ int handle, r; ++ size_t len; ++ u_char *cmd = NULL; ++ Session *s; ++ ++ debug3_f("entering"); ++ if ((r = sshbuf_get_u32(m, &handle)) != 0 || ++ (r = sshbuf_get_string(m, &cmd, &len)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ s = session_by_id(handle); ++ if (s == NULL || s->ttyfd != -1 || s->command == NULL || ++ strcmp(s->command, cmd) != 0) ++ fatal_f("invalid handle"); ++ mm_session_close(ssh, s); + free(cmd); + return (0); + } +@@ -1813,6 +1880,7 @@ monitor_apply_keystate(struct ssh *ssh, + void + mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) + { ++ struct sshbuf *m; + debug3_f("Waiting for new keys"); + + if ((child_state = sshbuf_new()) == NULL) +@@ -1820,6 +1888,19 @@ mm_get_keystate(struct ssh *ssh, struct + mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, + child_state); + debug3_f("GOT new keys"); ++ ++#ifdef SSH_AUDIT_EVENTS ++ m = sshbuf_new(); ++ mm_request_receive_expect(pmonitor->m_sendfd, ++ MONITOR_REQ_AUDIT_SESSION_KEY_FREE, m); ++ mm_answer_audit_session_key_free_body(ssh, pmonitor->m_sendfd, m); ++ sshbuf_free(m); ++#endif ++ ++ /* Drain any buffered messages from the child */ ++ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) ++ ; ++ + } + + +@@ -2111,3 +2192,102 @@ mm_answer_gss_updatecreds(struct ssh *ss + + #endif /* GSSAPI */ + ++#ifdef SSH_AUDIT_EVENTS ++int ++mm_answer_audit_unsupported_body(struct ssh *ssh, int sock, struct sshbuf *m) ++{ ++ int what, r; ++ ++ if ((r = sshbuf_get_u32(m, &what)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ audit_unsupported_body(ssh, what); ++ ++ sshbuf_reset(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_kex_body(struct ssh *ssh, int sock, struct sshbuf *m) ++{ ++ int ctos, r; ++ char *cipher, *mac, *compress, *pfs; ++ u_int64_t tmp; ++ pid_t pid; ++ uid_t uid; ++ ++ if ((r = sshbuf_get_u32(m, &ctos)) != 0 || ++ (r = sshbuf_get_cstring(m, &cipher, NULL)) != 0 || ++ (r = sshbuf_get_cstring(m, &mac, NULL)) != 0 || ++ (r = sshbuf_get_cstring(m, &compress, NULL)) != 0 || ++ (r = sshbuf_get_cstring(m, &pfs, NULL)) != 0 || ++ (r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal_fr(r, "buffer error"); ++ pid = (pid_t) tmp; ++ if ((r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal_fr(r, "buffer error"); ++ uid = (pid_t) tmp; ++ ++ audit_kex_body(ssh, ctos, cipher, mac, compress, pfs, pid, uid); ++ ++ free(cipher); ++ free(mac); ++ free(compress); ++ free(pfs); ++ sshbuf_reset(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_session_key_free_body(struct ssh *ssh, int sock, struct sshbuf *m) ++{ ++ int ctos, r; ++ u_int64_t tmp; ++ pid_t pid; ++ uid_t uid; ++ ++ if ((r = sshbuf_get_u32(m, &ctos)) != 0 || ++ (r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal_fr(r, "buffer error"); ++ pid = (pid_t) tmp; ++ if ((r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal_fr(r, "buffer error"); ++ uid = (uid_t) tmp; ++ ++ audit_session_key_free_body(ssh, ctos, pid, uid); ++ ++ sshbuf_reset(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_server_key_free(struct ssh *ssh, int sock, struct sshbuf *m) ++{ ++ size_t len, r; ++ char *fp; ++ u_int64_t tmp; ++ pid_t pid; ++ uid_t uid; ++ ++ if ((r = sshbuf_get_cstring(m, &fp, &len)) != 0 || ++ (r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal_fr(r, "buffer error"); ++ pid = (pid_t) tmp; ++ if ((r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal_fr(r, "buffer error"); ++ uid = (uid_t) tmp; ++ ++ audit_destroy_sensitive_data(ssh, fp, pid, uid); ++ ++ free(fp); ++ sshbuf_reset(m); ++ ++ return 0; ++} ++#endif /* SSH_AUDIT_EVENTS */ +diff -up openssh-8.6p1/monitor.h.audit openssh-8.6p1/monitor.h +--- openssh-8.6p1/monitor.h.audit 2021-04-19 16:47:35.707061753 +0200 ++++ openssh-8.6p1/monitor.h 2021-04-19 16:47:35.757062137 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -65,7 +65,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, + + MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, + MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, +diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c +--- openssh-8.6p1/monitor_wrap.c.audit 2021-04-19 16:47:35.685061584 +0200 ++++ openssh-8.6p1/monitor_wrap.c 2021-04-19 16:47:35.757062137 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -520,7 +520,7 @@ mm_key_allowed(enum mm_keytype type, con + */ + + int +-mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, ++mm_sshkey_verify(enum mm_keytype type, const struct sshkey *key, const u_char *sig, size_t siglen, + const u_char *data, size_t datalen, const char *sigalg, u_int compat, + struct sshkey_sig_details **sig_detailsp) + { +@@ -536,7 +536,8 @@ mm_sshkey_verify(const struct sshkey *ke + *sig_detailsp = NULL; + if ((m = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); +- if ((r = sshkey_puts(key, m)) != 0 || ++ if ((r = sshbuf_put_u32(m, type)) != 0 || ++ (r = sshkey_puts(key, m)) != 0 || + (r = sshbuf_put_string(m, sig, siglen)) != 0 || + (r = sshbuf_put_string(m, data, datalen)) != 0 || + (r = sshbuf_put_cstring(m, sigalg == NULL ? "" : sigalg)) != 0) +@@ -569,6 +570,22 @@ mm_sshkey_verify(const struct sshkey *ke + return 0; + } + ++int ++mm_hostbased_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, size_t siglen, ++ const u_char *data, size_t datalen, const char *pkalg, u_int compat, ++ struct sshkey_sig_details **detailsp) ++{ ++ return mm_sshkey_verify(MM_HOSTKEY, key, sig, siglen, data, datalen, pkalg, compat, detailsp); ++} ++ ++int ++mm_user_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, size_t siglen, ++ const u_char *data, size_t datalen, const char *pkalg, u_int compat, ++ struct sshkey_sig_details **detailsp) ++{ ++ return mm_sshkey_verify(MM_USERKEY, key, sig, siglen, data, datalen, pkalg, compat, detailsp); ++} ++ + void + mm_send_keystate(struct ssh *ssh, struct monitor *monitor) + { +@@ -921,11 +938,12 @@ mm_audit_event(struct ssh *ssh, ssh_audi + sshbuf_free(m); + } + +-void +-mm_audit_run_command(const char *command) ++int ++mm_audit_run_command(struct ssh *ssh, const char *command) + { + struct sshbuf *m; + int r; ++ int handle; + + debug3("%s entering command %s", __func__, command); + +@@ -935,6 +953,30 @@ mm_audit_run_command(const char *command + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, m); ++ ++ if ((r = sshbuf_get_u32(m, &handle)) != 0) ++ fatal_fr(r, "buffer error"); ++ sshbuf_free(m); ++ ++ return (handle); ++} ++ ++void ++mm_audit_end_command(struct ssh *ssh, int handle, const char *command) ++{ ++ int r; ++ struct sshbuf *m; ++ ++ debug3_f("entering command %s", command); ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ if ((r = sshbuf_put_u32(m, handle)) != 0 || ++ (r = sshbuf_put_cstring(m, command)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, m); + sshbuf_free(m); + } + #endif /* SSH_AUDIT_EVENTS */ +@@ -1095,3 +1137,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc + } + + #endif /* GSSAPI */ ++#ifdef SSH_AUDIT_EVENTS ++void ++mm_audit_unsupported_body(struct ssh *ssh, int what) ++{ ++ int r; ++ struct sshbuf *m; ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ if ((r = sshbuf_put_u32(m, what)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, ++ m); ++ ++ sshbuf_free(m); ++} ++ ++void ++mm_audit_kex_body(struct ssh *ssh, int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid, ++ uid_t uid) ++{ ++ int r; ++ struct sshbuf *m; ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ if ((r = sshbuf_put_u32(m, ctos)) != 0 || ++ (r = sshbuf_put_cstring(m, cipher)) != 0 || ++ (r = sshbuf_put_cstring(m, (mac ? mac : "<implicit>"))) != 0 || ++ (r = sshbuf_put_cstring(m, compress)) != 0 || ++ (r = sshbuf_put_cstring(m, fps)) != 0 || ++ (r = sshbuf_put_u64(m, pid)) != 0 || ++ (r = sshbuf_put_u64(m, uid)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, ++ m); ++ ++ sshbuf_free(m); ++} ++ ++void ++mm_audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid) ++{ ++ int r; ++ struct sshbuf *m; ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ if ((r = sshbuf_put_u32(m, ctos)) != 0 || ++ (r = sshbuf_put_u64(m, pid)) != 0 || ++ (r = sshbuf_put_u64(m, uid)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, ++ m); ++ sshbuf_free(m); ++} ++ ++void ++mm_audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) ++{ ++ int r; ++ struct sshbuf *m; ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ if ((r = sshbuf_put_cstring(m, fp)) != 0 || ++ (r = sshbuf_put_u64(m, pid)) != 0 || ++ (r = sshbuf_put_u64(m, uid)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m); ++ sshbuf_free(m); ++} ++#endif /* SSH_AUDIT_EVENTS */ +diff -up openssh-8.6p1/monitor_wrap.h.audit openssh-8.6p1/monitor_wrap.h +--- openssh-8.6p1/monitor_wrap.h.audit 2021-04-19 16:47:35.685061584 +0200 ++++ openssh-8.6p1/monitor_wrap.h 2021-04-19 16:47:35.757062137 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -61,7 +61,9 @@ int mm_user_key_allowed(struct ssh *, st + struct sshauthopt **); + int mm_hostbased_key_allowed(struct ssh *, struct passwd *, const char *, + const char *, struct sshkey *); +-int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, ++int mm_hostbased_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); ++int mm_user_key_verify(struct ssh*, const struct sshkey *, const u_char *, size_t, + const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); + + #ifdef GSSAPI +@@ -86,7 +88,12 @@ void mm_sshpam_free_ctx(void *); + #ifdef SSH_AUDIT_EVENTS + #include "audit.h" + void mm_audit_event(struct ssh *, ssh_audit_event_t); +-void mm_audit_run_command(const char *); ++int mm_audit_run_command(struct ssh *ssh, const char *); ++void mm_audit_end_command(struct ssh *ssh, int, const char *); ++void mm_audit_unsupported_body(struct ssh *, int); ++void mm_audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); ++void mm_audit_session_key_free_body(struct ssh *, int, pid_t, uid_t); ++void mm_audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); + #endif + + struct Session; +diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c +--- openssh-8.6p1/packet.c.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/packet.c 2021-04-19 16:48:46.885608837 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -81,6 +81,7 @@ + #endif + + #include "xmalloc.h" ++#include "audit.h" + #include "compat.h" + #include "ssh2.h" + #include "cipher.h" +@@ -506,6 +507,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. +@@ -583,22 +591,19 @@ ssh_packet_close_internal(struct ssh *ss + { + struct session_state *state = ssh->state; + u_int mode; ++ u_int had_keys = packet_state_has_keys(state); + + if (!state->initialized) + return; + state->initialized = 0; +- if (do_close) { +- if (state->connection_in == state->connection_out) { +- close(state->connection_out); +- } else { +- close(state->connection_in); +- close(state->connection_out); +- } +- } + sshbuf_free(state->input); ++ state->input = NULL; + sshbuf_free(state->output); ++ state->output = NULL; + sshbuf_free(state->outgoing_packet); ++ state->outgoing_packet = NULL; + sshbuf_free(state->incoming_packet); ++ state->incoming_packet = NULL; + for (mode = 0; mode < MODE_MAX; mode++) { + kex_free_newkeys(state->newkeys[mode]); /* current keys */ + state->newkeys[mode] = NULL; +@@ -634,8 +639,18 @@ ssh_packet_close_internal(struct ssh *ss + #endif /* WITH_ZLIB */ + cipher_free(state->send_context); + cipher_free(state->receive_context); ++ if (had_keys && state->server_side) { ++ /* Assuming this is called only from privsep child */ ++ audit_session_key_free(ssh, MODE_MAX); ++ } + state->send_context = state->receive_context = NULL; + if (do_close) { ++ if (state->connection_in == state->connection_out) { ++ close(state->connection_out); ++ } else { ++ close(state->connection_in); ++ close(state->connection_out); ++ } + free(ssh->local_ipaddr); + ssh->local_ipaddr = NULL; + free(ssh->remote_ipaddr); +@@ -892,6 +907,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod + (unsigned long long)state->p_send.bytes, + (unsigned long long)state->p_send.blocks); + kex_free_newkeys(state->newkeys[mode]); ++ audit_session_key_free(ssh, mode); + state->newkeys[mode] = NULL; + } + /* note that both bytes and the seqnr are not reset */ +@@ -2173,6 +2189,72 @@ ssh_packet_get_output(struct ssh *ssh) + return (void *)ssh->state->output; + } + ++static void ++newkeys_destroy_and_free(struct newkeys *newkeys) ++{ ++ if (newkeys == NULL) ++ return; ++ ++ free(newkeys->enc.name); ++ ++ if (newkeys->mac.enabled) { ++ mac_clear(&newkeys->mac); ++ free(newkeys->mac.name); ++ } ++ ++ free(newkeys->comp.name); ++ ++ newkeys_destroy(newkeys); ++ free(newkeys); ++} ++ ++static void ++packet_destroy_state(struct session_state *state) ++{ ++ if (state == NULL) ++ return; ++ ++ cipher_free(state->receive_context); ++ cipher_free(state->send_context); ++ state->send_context = state->receive_context = NULL; ++ ++ sshbuf_free(state->input); ++ state->input = NULL; ++ sshbuf_free(state->output); ++ state->output = NULL; ++ sshbuf_free(state->outgoing_packet); ++ state->outgoing_packet = NULL; ++ sshbuf_free(state->incoming_packet); ++ state->incoming_packet = NULL; ++ if (state->compression_buffer) { ++ sshbuf_free(state->compression_buffer); ++ state->compression_buffer = NULL; ++ } ++ newkeys_destroy_and_free(state->newkeys[MODE_IN]); ++ state->newkeys[MODE_IN] = NULL; ++ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); ++ state->newkeys[MODE_OUT] = NULL; ++ mac_destroy(state->packet_discard_mac); ++// TAILQ_HEAD(, packet) outgoing; ++// memset(state, 0, sizeof(state)); ++} ++ ++void ++packet_destroy_all(struct ssh *ssh, int audit_it, int privsep) ++{ ++ if (audit_it) ++ audit_it = packet_state_has_keys(ssh->state); ++ packet_destroy_state(ssh->state); ++ if (audit_it) { ++#ifdef SSH_AUDIT_EVENTS ++ if (privsep) ++ audit_session_key_free(ssh, MODE_MAX); ++ else ++ audit_session_key_free_body(ssh, MODE_MAX, getpid(), getuid()); ++#endif ++ } ++} ++ + /* Reset after_authentication and reset compression in post-auth privsep */ + static int + ssh_packet_set_postauth(struct ssh *ssh) +diff -up openssh-8.6p1/packet.h.audit openssh-8.6p1/packet.h +--- openssh-8.6p1/packet.h.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/packet.h 2021-04-19 16:47:35.758062145 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -218,4 +218,5 @@ const u_char *sshpkt_ptr(struct ssh *, s + # undef EC_POINT + #endif + ++void packet_destroy_all(struct ssh *, int, int); + #endif /* PACKET_H */ +diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c +--- openssh-8.6p1/session.c.audit 2021-04-19 16:47:35.722061868 +0200 ++++ openssh-8.6p1/session.c 2021-04-19 16:47:35.758062145 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -136,7 +136,7 @@ extern char *__progname; + extern int debug_flag; + extern u_int utmp_len; + extern int startup_pipe; +-extern void destroy_sensitive_data(void); ++extern void destroy_sensitive_data(struct ssh *, int); + extern struct sshbuf *loginmsg; + extern struct sshauthopt *auth_opts; + extern char *tun_fwd_ifnames; /* serverloop.c */ +@@ -644,6 +644,14 @@ do_exec_pty(struct ssh *ssh, Session *s, + /* Parent. Close the slave side of the pseudo tty. */ + close(ttyfd); + ++#if !defined(HAVE_OSF_SIA) && defined(SSH_AUDIT_EVENTS) ++ /* do_login in the child did not affect state in this process, ++ compensate. From an architectural standpoint, this is extremely ++ ugly. */ ++ if (command != NULL) ++ audit_count_session_open(); ++#endif ++ + /* Enter interactive session. */ + s->ptymaster = ptymaster; + ssh_packet_set_interactive(ssh, 1, +@@ -736,15 +744,19 @@ do_exec(struct ssh *ssh, Session *s, con + s->self); + + #ifdef SSH_AUDIT_EVENTS ++ if (s->command != NULL || s->command_handle != -1) ++ fatal("do_exec: command already set"); + if (command != NULL) +- PRIVSEP(audit_run_command(command)); ++ s->command = xstrdup(command); + else if (s->ttyfd == -1) { + char *shell = s->pw->pw_shell; + + if (shell[0] == '\0') /* empty shell means /bin/sh */ + shell =_PATH_BSHELL; +- PRIVSEP(audit_run_command(shell)); ++ s->command = xstrdup(shell); + } ++ if (s->command != NULL && s->ptyfd == -1) ++ s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); + #endif + if (s->ttyfd != -1) + ret = do_exec_pty(ssh, s, command); +@@ -1550,8 +1562,11 @@ do_child(struct ssh *ssh, Session *s, co + sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); + + /* remove hostkey from the child's memory */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(ssh, 1); + ssh_packet_clear_keys(ssh); ++ /* Don't audit this - both us and the parent would be talking to the ++ monitor over a single socket, with no synchronization. */ ++ packet_destroy_all(ssh, 0, 1); + + /* Force a password change */ + if (s->authctxt->force_pwchange) { +@@ -1763,6 +1778,9 @@ session_unused(int id) + sessions[id].ttyfd = -1; + sessions[id].ptymaster = -1; + sessions[id].x11_chanids = NULL; ++#ifdef SSH_AUDIT_EVENTS ++ sessions[id].command_handle = -1; ++#endif + sessions[id].next_unused = sessions_first_unused; + sessions_first_unused = id; + } +@@ -1843,6 +1861,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_f("unknown id %d", id); ++ session_dump(); ++ return NULL; ++} ++ ++Session * + session_by_tty(char *tty) + { + int i; +@@ -2450,6 +2481,32 @@ session_exit_message(struct ssh *ssh, Se + chan_write_failed(ssh, c); + } + ++#ifdef SSH_AUDIT_EVENTS ++void ++session_end_command2(struct ssh *ssh, Session *s) ++{ ++ if (s->command != NULL) { ++ if (s->command_handle != -1) ++ audit_end_command(ssh, s->command_handle, s->command); ++ free(s->command); ++ s->command = NULL; ++ s->command_handle = -1; ++ } ++} ++ ++static void ++session_end_command(struct ssh *ssh, Session *s) ++{ ++ if (s->command != NULL) { ++ if (s->command_handle != -1) ++ PRIVSEP(audit_end_command(ssh, s->command_handle, s->command)); ++ free(s->command); ++ s->command = NULL; ++ s->command_handle = -1; ++ } ++} ++#endif ++ + void + session_close(struct ssh *ssh, Session *s) + { +@@ -2463,6 +2520,10 @@ session_close(struct ssh *ssh, Session * + + if (s->ttyfd != -1) + session_pty_cleanup(s); ++#ifdef SSH_AUDIT_EVENTS ++ if (s->command) ++ session_end_command(ssh, s); ++#endif + free(s->term); + free(s->display); + free(s->x11_chanids); +@@ -2537,14 +2598,14 @@ session_close_by_channel(struct ssh *ssh + } + + void +-session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *)) ++session_destroy_all(struct ssh *ssh, void (*closefunc)(struct ssh *ssh, Session *)) + { + int i; + for (i = 0; i < sessions_nalloc; i++) { + Session *s = &sessions[i]; + if (s->used) { + if (closefunc != NULL) +- closefunc(s); ++ closefunc(ssh, s); + else + session_close(ssh, s); + } +@@ -2671,6 +2732,15 @@ do_authenticated2(struct ssh *ssh, Authc + server_loop2(ssh, authctxt); + } + ++static void ++do_cleanup_one_session(struct ssh *ssh, Session *s) ++{ ++ session_pty_cleanup2(s); ++#ifdef SSH_AUDIT_EVENTS ++ session_end_command2(ssh, s); ++#endif ++} ++ + void + do_cleanup(struct ssh *ssh, Authctxt *authctxt) + { +@@ -2734,7 +2804,7 @@ do_cleanup(struct ssh *ssh, Authctxt *au + * or if running in monitor. + */ + if (!use_privsep || mm_is_monitor()) +- session_destroy_all(ssh, session_pty_cleanup2); ++ session_destroy_all(ssh, do_cleanup_one_session); + } + + /* Return a name for the remote host that fits inside utmp_size */ +diff -up openssh-8.6p1/session.h.audit openssh-8.6p1/session.h +--- openssh-8.6p1/session.h.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/session.h 2021-04-19 16:47:35.758062145 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -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(struct ssh *, Authctxt *); +@@ -71,10 +77,12 @@ void session_unused(int); + int session_input_channel_req(struct ssh *, Channel *, const char *); + void session_close_by_pid(struct ssh *ssh, pid_t, int); + void session_close_by_channel(struct ssh *, int, void *); +-void session_destroy_all(struct ssh *, void (*)(Session *)); ++void session_destroy_all(struct ssh *, void (*)(struct ssh*, Session *)); + void session_pty_cleanup2(Session *); ++void session_end_command2(struct ssh *ssh, Session *); + + Session *session_new(void); ++Session *session_by_id(int); + Session *session_by_tty(char *); + void session_close(struct ssh *, Session *); + void do_setusercontext(struct passwd *); +diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c +--- openssh-8.6p1/sshd.c.audit 2021-04-19 16:47:35.727061907 +0200 ++++ openssh-8.6p1/sshd.c 2021-04-19 16:47:35.759062152 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -122,6 +122,7 @@ + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" ++#include "audit.h" + #include "ssh-sandbox.h" + #include "auth-options.h" + #include "version.h" +@@ -260,8 +261,8 @@ struct sshbuf *loginmsg; + struct passwd *privsep_pw = NULL; + + /* Prototypes for various functions defined later in this file. */ +-void destroy_sensitive_data(void); +-void demote_sensitive_data(void); ++void destroy_sensitive_data(struct ssh *, int); ++void demote_sensitive_data(struct ssh *); + static void do_ssh2_kex(struct ssh *); + + static char *listener_proctitle; +@@ -279,6 +280,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) + { +@@ -377,18 +387,45 @@ grace_alarm_handler(int sig) + } + } + +-/* 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(struct ssh *ssh, int privsep) + { + u_int i; ++#ifdef SSH_AUDIT_EVENTS ++ pid_t pid; ++ uid_t uid; + ++ pid = getpid(); ++ uid = getuid(); ++#endif + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { ++ char *fp; ++ ++ if (sshkey_is_private(sensitive_data.host_keys[i])) ++ fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); ++ else ++ fp = NULL; + sshkey_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = NULL; ++ if (fp != NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ if (privsep) ++ PRIVSEP(audit_destroy_sensitive_data(ssh, fp, ++ pid, uid)); ++ else ++ audit_destroy_sensitive_data(ssh, fp, ++ pid, uid); ++#endif ++ free(fp); ++ } + } +- if (sensitive_data.host_certificates[i]) { ++ if (sensitive_data.host_certificates ++ && sensitive_data.host_certificates[i]) { + sshkey_free(sensitive_data.host_certificates[i]); + sensitive_data.host_certificates[i] = NULL; + } +@@ -397,20 +434,38 @@ destroy_sensitive_data(void) + + /* Demote private to public keys for network child */ + void +-demote_sensitive_data(void) ++demote_sensitive_data(struct ssh *ssh) + { + struct sshkey *tmp; + u_int i; + int r; ++#ifdef SSH_AUDIT_EVENTS ++ pid_t pid; ++ uid_t uid; + ++ pid = getpid(); ++ uid = getuid(); ++#endif + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { ++ char *fp; ++ ++ if (sshkey_is_private(sensitive_data.host_keys[i])) ++ fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); ++ else ++ fp = NULL; + if ((r = sshkey_from_private( + sensitive_data.host_keys[i], &tmp)) != 0) + fatal_r(r, "could not demote host %s key", + sshkey_type(sensitive_data.host_keys[i])); + sshkey_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = tmp; ++ if (fp != NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_destroy_sensitive_data(ssh, fp, pid, uid); ++#endif ++ free(fp); ++ } + } + /* Certs do not need demotion */ + } +@@ -438,7 +493,7 @@ reseed_prngs(void) + } + + static void +-privsep_preauth_child(void) ++privsep_preauth_child(struct ssh *ssh) + { + gid_t gidset[1]; + +@@ -453,7 +508,7 @@ privsep_preauth_child(void) + reseed_prngs(); + + /* Demote the private keys to public keys. */ +- demote_sensitive_data(); ++ demote_sensitive_data(ssh); + + #ifdef WITH_SELINUX + sshd_selinux_change_privsep_preauth_context(); +@@ -492,7 +547,7 @@ privsep_preauth(struct ssh *ssh) + + 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) { +@@ -537,7 +592,7 @@ privsep_preauth(struct ssh *ssh) + /* Arrange for logging to be sent to the monitor */ + set_log_handler(mm_log_handler, pmonitor); + +- privsep_preauth_child(); ++ privsep_preauth_child(ssh); + setproctitle("%s", "[net]"); + if (box != NULL) + ssh_sandbox_child(box); +@@ -589,7 +644,7 @@ privsep_postauth(struct ssh *ssh, Authct + set_log_handler(mm_log_handler, pmonitor); + + /* Demote the private keys to public keys. */ +- demote_sensitive_data(); ++ demote_sensitive_data(ssh); + + reseed_prngs(); + +@@ -1143,7 +1198,7 @@ server_listen(void) + * from this function are in a forked subprocess. + */ + static void +-server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) ++server_accept_loop(struct ssh *ssh, int *sock_in, int *sock_out, int *newsock, int *config_s) + { + fd_set *fdset; + int i, j, ret, maxfd; +@@ -1204,6 +1259,7 @@ server_accept_loop(int *sock_in, int *so + if (received_sigterm) { + logit("Received signal %d; terminating.", + (int) received_sigterm); ++ destroy_sensitive_data(ssh, 0); + close_listen_socks(); + if (options.pid_file != NULL) + unlink(options.pid_file); +@@ -2098,7 +2154,7 @@ main(int ac, char **av) + #endif + + /* Accept a connection and return in a forked child */ +- server_accept_loop(&sock_in, &sock_out, ++ server_accept_loop(ssh, &sock_in, &sock_out, + &newsock, config_s); + } + +@@ -2333,6 +2389,9 @@ main(int ac, char **av) + do_authenticated(ssh, authctxt); + + /* The connection has been terminated. */ ++ packet_destroy_all(ssh, 1, 1); ++ destroy_sensitive_data(ssh, 1); ++ + ssh_packet_get_bytes(ssh, &ibytes, &obytes); + verbose("Transferred: sent %llu, received %llu bytes", + (unsigned long long)obytes, (unsigned long long)ibytes); +@@ -2513,6 +2572,15 @@ do_ssh2_kex(struct ssh *ssh) + 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_active_state != NULL && the_authctxt != NULL) { + do_cleanup(the_active_state, the_authctxt); + if (use_privsep && privsep_is_preauth && +@@ -2525,9 +2593,16 @@ cleanup_exit(int i) + } + } + } ++ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; ++ if (sensitive_data.host_keys != NULL && the_active_state != NULL) ++ destroy_sensitive_data(the_active_state, is_privsep_child); ++ if (the_active_state != NULL) ++ packet_destroy_all(the_active_state, 1, is_privsep_child); + #ifdef SSH_AUDIT_EVENTS + /* done after do_cleanup so it can cancel the PAM auth 'thread' */ +- if (the_active_state != NULL && (!use_privsep || mm_is_monitor())) ++ if (the_active_state != NULL && ++ (the_authctxt == NULL || !the_authctxt->authenticated) && ++ (!use_privsep || mm_is_monitor())) + audit_event(the_active_state, SSH_CONNECTION_ABANDON); + #endif + _exit(i); +diff -up openssh-8.6p1/sshkey.c.audit openssh-8.6p1/sshkey.c +--- openssh-8.6p1/sshkey.c.audit 2021-04-19 16:47:35.741062014 +0200 ++++ openssh-8.6p1/sshkey.c 2021-04-19 16:47:35.759062152 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -371,6 +371,38 @@ sshkey_type_is_valid_ca(int type) + } + + int ++sshkey_is_private(const struct sshkey *k) ++{ ++ switch (k->type) { ++#ifdef WITH_OPENSSL ++ case KEY_RSA_CERT: ++ case KEY_RSA: { ++ const BIGNUM *d; ++ RSA_get0_key(k->rsa, NULL, NULL, &d); ++ return d != NULL; ++ } ++ case KEY_DSA_CERT: ++ case KEY_DSA: { ++ const BIGNUM *priv_key; ++ DSA_get0_key(k->dsa, NULL, &priv_key); ++ return priv_key != NULL; ++ } ++#ifdef OPENSSL_HAS_ECC ++ case KEY_ECDSA_CERT: ++ case KEY_ECDSA: ++ return EC_KEY_get0_private_key(k->ecdsa) != NULL; ++#endif /* OPENSSL_HAS_ECC */ ++#endif /* WITH_OPENSSL */ ++ case KEY_ED25519_CERT: ++ case KEY_ED25519: ++ return (k->ed25519_pk != NULL); ++ default: ++ /* fatal("key_is_private: bad key type %d", k->type); */ ++ return 0; ++ } ++} ++ ++int + sshkey_is_cert(const struct sshkey *k) + { + if (k == NULL) +diff -up openssh-8.6p1/sshkey.h.audit openssh-8.6p1/sshkey.h +--- openssh-8.6p1/sshkey.h.audit 2021-04-19 16:47:35.741062014 +0200 ++++ openssh-8.6p1/sshkey.h 2021-04-19 16:47:35.759062152 +0200 +Reference:https://src.fedoraproject.org/rpms/openssh/blob/rawhide/f/backport-openssh-7.6p1-audit.patch +@@ -189,6 +189,7 @@ int sshkey_shield_private(struct sshke + int sshkey_unshield_private(struct sshkey *); + + int sshkey_type_from_name(const char *); ++int sshkey_is_private(const struct sshkey *); + int sshkey_is_cert(const struct sshkey *); + int sshkey_is_sk(const struct sshkey *); + int sshkey_type_is_cert(int); |