Bugzilla – Attachment 2795 Details for
Bug 1402
Support auditing through Linux Audit subsystem
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
audit patch rebased for 7.2 HEAD
audit.patch (text/plain), 67.98 KB, created by
Jakub Jelen
on 2016-03-05 02:39:46 AEDT
(
hide
)
Description:
audit patch rebased for 7.2 HEAD
Filename:
MIME Type:
Creator:
Jakub Jelen
Created:
2016-03-05 02:39:46 AEDT
Size:
67.98 KB
patch
obsolete
>From 61c2a76462d882c97b4cd8987bf38a22ea320a64 Mon Sep 17 00:00:00 2001 >From: Jakub Jelen <jjelen@redhat.com> >Date: Fri, 4 Mar 2016 16:17:14 +0100 >Subject: [PATCH] Audit from Fedora > >--- > Makefile.in | 2 +- > audit-bsm.c | 57 ++++++++- > audit-linux.c | 320 ++++++++++++++++++++++++++++++++++++++++++++--- > audit.c | 141 +++++++++++++++++++-- > audit.h | 23 +++- > auditstub.c | 50 ++++++++ > auth-rsa.c | 21 +++- > auth.c | 3 - > auth.h | 2 + > auth2-hostbased.c | 14 ++- > auth2-pubkey.c | 14 ++- > auth2.c | 3 - > cipher.c | 20 --- > cipher.h | 21 +++- > kex.c | 53 +++++++- > kex.h | 2 + > key.h | 1 + > mac.c | 14 +++ > mac.h | 1 + > monitor.c | 183 ++++++++++++++++++++++++++- > monitor.h | 8 +- > monitor_wrap.c | 149 +++++++++++++++++++++- > monitor_wrap.h | 12 +- > packet.c | 100 +++++++++++++-- > packet.h | 1 + > sandbox-seccomp-filter.c | 6 + > session.c | 116 ++++++++++++++++- > session.h | 8 ++ > sshd.c | 99 +++++++++++++-- > sshkey.c | 27 ++++ > sshkey.h | 1 + > 31 files changed, 1376 insertions(+), 96 deletions(-) > create mode 100644 auditstub.c > >diff --git a/Makefile.in b/Makefile.in >index 84c3c6c..36dc828 100644 >--- a/Makefile.in >+++ b/Makefile.in >@@ -92,7 +92,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ > kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ > kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ > kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \ >- platform-pledge.o >+ platform-pledge.o auditstub.o > > SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ > sshconnect.o sshconnect1.o sshconnect2.o mux.o >diff --git a/audit-bsm.c b/audit-bsm.c >index 6135591..c7a1b47 100644 >--- a/audit-bsm.c >+++ b/audit-bsm.c >@@ -375,10 +375,23 @@ audit_connection_from(const char *host, int port) > #endif > } > >-void >+int > audit_run_command(const char *command) > { > /* not implemented */ >+ return 0; >+} >+ >+void >+audit_end_command(int handle, const char *command) >+{ >+ /* not implemented */ >+} >+ >+void >+audit_count_session_open(void) >+{ >+ /* not necessary */ > } > > void >@@ -393,6 +406,12 @@ audit_session_close(struct logininfo *li) > /* not implemented */ > } > >+int >+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) >+{ >+ /* not implemented */ >+} >+ > void > audit_event(ssh_audit_event_t event) > { >@@ -454,4 +473,40 @@ audit_event(ssh_audit_event_t event) > debug("%s: unhandled event %d", __func__, event); > } > } >+ >+void >+audit_unsupported_body(int what) >+{ >+ /* not implemented */ >+} >+ >+void >+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid) >+{ >+ /* not implemented */ >+} >+ >+void >+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) >+{ >+ /* not implemented */ >+} >+ >+void >+audit_destroy_sensitive_data(const char *fp) >+{ >+ /* not implemented */ >+} >+ >+void >+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) >+{ >+ /* not implemented */ >+} >+ >+void >+audit_generate_ephemeral_server_key(const char *fp) >+{ >+ /* not implemented */ >+} > #endif /* BSM */ >diff --git a/audit-linux.c b/audit-linux.c >index b3ee2f4..f93bf40 100644 >--- a/audit-linux.c >+++ b/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 char *username, > if (audit_fd < 0) { > if (errno == EINVAL || errno == EPROTONOSUPPORT || > errno == EAFNOSUPPORT) >- return 1; /* No audit support in kernel */ >+ return; /* No audit support in kernel */ > else >- return 0; /* Must prevent login */ >+ goto fatal_report; /* Must prevent login */ > } >- rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, >+ rc = audit_log_acct_message(audit_fd, event, > NULL, "login", username ? username : "(unknown)", > username == NULL ? uid : -1, hostname, ip, ttyn, success); > saved_errno = errno; >@@ -65,35 +77,154 @@ linux_audit_record_event(int uid, const char *username, > if ((rc == -EPERM) && (geteuid() != 0)) > rc = 0; > errno = saved_errno; >- return (rc >= 0); >+ if (rc < 0) { >+fatal_report: >+ fatal("linux_audit_write_entry failed: %s", strerror(errno)); >+ } >+} >+ >+static void >+linux_audit_user_auth(int uid, const char *username, >+ const char *hostname, const char *ip, const char *ttyn, int success, int event) >+{ >+ int audit_fd, rc, saved_errno; >+ static const char *event_name[] = { >+ "maxtries exceeded", >+ "root denied", >+ "success", >+ "none", >+ "password", >+ "challenge-response", >+ "pubkey", >+ "hostbased", >+ "gssapi", >+ "invalid user", >+ "nologin", >+ "connection closed", >+ "connection abandoned", >+ "unknown" >+ }; >+ >+ audit_fd = audit_open(); >+ if (audit_fd < 0) { >+ if (errno == EINVAL || errno == EPROTONOSUPPORT || >+ errno == EAFNOSUPPORT) >+ return; /* No audit support in kernel */ >+ else >+ goto fatal_report; /* Must prevent login */ >+ } >+ >+ if ((event < 0) || (event > SSH_AUDIT_UNKNOWN)) >+ event = SSH_AUDIT_UNKNOWN; >+ >+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, >+ NULL, event_name[event], username ? username : "(unknown)", >+ username == NULL ? uid : -1, hostname, ip, ttyn, success); >+ saved_errno = errno; >+ close(audit_fd); >+ /* >+ * Do not report error if the error is EPERM and sshd is run as non >+ * root user. >+ */ >+ if ((rc == -EPERM) && (geteuid() != 0)) >+ rc = 0; >+ errno = saved_errno; >+ if (rc < 0) { >+fatal_report: >+ fatal("linux_audit_write_entry failed: %s", strerror(errno)); >+ } >+} >+ >+int >+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) >+{ >+ char buf[AUDIT_LOG_SIZE]; >+ int audit_fd, rc, saved_errno; >+ >+ audit_fd = audit_open(); >+ if (audit_fd < 0) { >+ if (errno == EINVAL || errno == EPROTONOSUPPORT || >+ errno == EAFNOSUPPORT) >+ return 1; /* No audit support in kernel */ >+ else >+ return 0; /* Must prevent login */ >+ } >+ snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port()); >+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, >+ buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); >+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) >+ goto out; >+ /* 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 */ >diff --git a/audit.c b/audit.c >index ced57fa..fc2e3de 100644 >--- a/audit.c >+++ b/audit.c >@@ -28,6 +28,7 @@ > > #include <stdarg.h> > #include <string.h> >+#include <unistd.h> > > #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 */ >diff --git a/audit.h b/audit.h >index 92ede5b..84b5d0a 100644 >--- a/audit.h >+++ b/audit.h >@@ -28,6 +28,7 @@ > # define _SSH_AUDIT_H > > #include "loginrec.h" >+#include "key.h" > > enum ssh_audit_event_type { > SSH_LOGIN_EXCEED_MAXTRIES, >@@ -45,13 +46,33 @@ enum ssh_audit_event_type { > SSH_CONNECTION_ABANDON, /* closed without completing auth */ > SSH_AUDIT_UNKNOWN > }; >+ >+enum ssh_audit_kex { >+ SSH_AUDIT_UNSUPPORTED_CIPHER, >+ SSH_AUDIT_UNSUPPORTED_MAC, >+ SSH_AUDIT_UNSUPPORTED_COMPRESSION >+}; > typedef enum ssh_audit_event_type ssh_audit_event_t; > >+int listening_for_clients(void); >+ > void audit_connection_from(const char *, int); > void audit_event(ssh_audit_event_t); >+void audit_count_session_open(void); > void audit_session_open(struct logininfo *); > void audit_session_close(struct logininfo *); >-void audit_run_command(const char *); >+int audit_run_command(const char *); >+void audit_end_command(int, const char *); > ssh_audit_event_t audit_classify_auth(const char *); >+int audit_keyusage(int, const char *, unsigned, char *, int); >+void audit_key(int, int *, const Key *); >+void audit_unsupported(int); >+void audit_kex(int, char *, char *, char *, char *); >+void audit_unsupported_body(int); >+void audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); >+void audit_session_key_free(int ctos); >+void audit_session_key_free_body(int ctos, pid_t, uid_t); >+void audit_destroy_sensitive_data(const char *, pid_t, uid_t); >+void audit_generate_ephemeral_server_key(const char *); > > #endif /* _SSH_AUDIT_H */ >diff --git a/auditstub.c b/auditstub.c >new file mode 100644 >index 0000000..116f460 >--- /dev/null >+++ b/auditstub.c >@@ -0,0 +1,50 @@ >+/* $Id: auditstub.c,v 1.1 jfch Exp $ */ >+ >+/* >+ * Copyright 2010 Red Hat, Inc. All rights reserved. >+ * Use is subject to license terms. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR >+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. >+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, >+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ * >+ * Red Hat author: Jan F. Chadima <jchadima@redhat.com> >+ */ >+ >+#include <sys/types.h> >+ >+void >+audit_unsupported(int n) >+{ >+} >+ >+void >+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) >+{ >+} >+ >+void >+audit_session_key_free(int ctos) >+{ >+} >+ >+void >+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) >+{ >+} >diff --git a/auth-rsa.c b/auth-rsa.c >index cbd971b..dd44d0a 100644 >--- a/auth-rsa.c >+++ b/auth-rsa.c >@@ -95,7 +95,10 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) > { > u_char buf[32], mdbuf[16]; > struct ssh_digest_ctx *md; >- int len; >+ int len, rv; >+#ifdef SSH_AUDIT_EVENTS >+ char *fp; >+#endif > > /* don't allow short keys */ > if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { >@@ -119,12 +122,18 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) > ssh_digest_free(md); > > /* Verify that the response is the original challenge. */ >- if (timingsafe_bcmp(response, mdbuf, 16) != 0) { >- /* Wrong answer. */ >- return (0); >+ rv = timingsafe_bcmp(response, mdbuf, 16) == 0; >+ >+#ifdef SSH_AUDIT_EVENTS >+ fp = 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; > } > > /* >diff --git a/auth.c b/auth.c >index 214c2c7..4d1fbbe 100644 >--- a/auth.c >+++ b/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)) >diff --git a/auth.h b/auth.h >index 2160154..818ddad 100644 >--- a/auth.h >+++ b/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, struct ssh *); > int ssh1_session_key(BIGNUM *); > int sshd_hostkey_sign(Key *, Key *, u_char **, size_t *, > const u_char *, size_t, const char *, u_int); >+int hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); > > /* debug messages during authentication */ > void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); >diff --git a/auth2-hostbased.c b/auth2-hostbased.c >index e2327cf..bf487a8 100644 >--- a/auth2-hostbased.c >+++ b/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, >diff --git a/auth2-pubkey.c b/auth2-pubkey.c >index 41b34ae..00565f3 100644 >--- a/auth2-pubkey.c >+++ b/auth2-pubkey.c >@@ -176,7 +176,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 */ >@@ -256,6 +256,18 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) > free(extra); > } > >+int >+user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) >+{ >+ int rv; >+ >+ rv = key_verify(key, sig, slen, data, datalen); >+#ifdef SSH_AUDIT_EVENTS >+ audit_key(1, &rv, key); >+#endif >+ return rv; >+} >+ > /* > * Splits 's' into an argument vector. Handles quoted string and basic > * escape characters (\\, \", \'). Caller must free the argument vector >diff --git a/auth2.c b/auth2.c >index 7177962..877737d 100644 >--- a/auth2.c >+++ b/auth2.c >@@ -239,9 +239,6 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) > } else { > logit("input_userauth_request: invalid user %s", user); > authctxt->pw = fakepw(); >-#ifdef SSH_AUDIT_EVENTS >- PRIVSEP(audit_event(SSH_INVALID_USER)); >-#endif > } > #ifdef USE_PAM > if (options.use_pam) >diff --git a/cipher.c b/cipher.c >index 13847e5..346b4cb 100644 >--- a/cipher.c >+++ b/cipher.c >@@ -57,26 +57,6 @@ extern const EVP_CIPHER *evp_ssh1_3des(void); > extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); > #endif > >-struct sshcipher { >- char *name; >- int number; /* for ssh1 only */ >- u_int block_size; >- u_int key_len; >- u_int iv_len; /* defaults to block_size */ >- u_int auth_len; >- u_int discard_len; >- u_int flags; >-#define CFLAG_CBC (1<<0) >-#define CFLAG_CHACHAPOLY (1<<1) >-#define CFLAG_AESCTR (1<<2) >-#define CFLAG_NONE (1<<3) >-#ifdef WITH_OPENSSL >- const EVP_CIPHER *(*evptype)(void); >-#else >- void *ignored; >-#endif >-}; >- > static const struct sshcipher ciphers[] = { > #ifdef WITH_SSH1 > { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, >diff --git a/cipher.h b/cipher.h >index 06d4be4..a786dfa 100644 >--- a/cipher.h >+++ b/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; >diff --git a/kex.c b/kex.c >index d371f47..981e4f8 100644 >--- a/kex.c >+++ b/kex.c >@@ -53,6 +53,7 @@ > #include "ssherr.h" > #include "sshbuf.h" > #include "digest.h" >+#include "audit.h" > > #if OPENSSL_VERSION_NUMBER >= 0x00907000L > # if defined(HAVE_EVP_SHA256) >@@ -630,8 +631,12 @@ choose_enc(struct sshenc *enc, char *client, char *server) > { > char *name = match_list(client, server, NULL); > >- if (name == NULL) >+ if (name == NULL) { >+#ifdef SSH_AUDIT_EVENTS >+ audit_unsupported(SSH_AUDIT_UNSUPPORTED_CIPHER); >+#endif > return SSH_ERR_NO_CIPHER_ALG_MATCH; >+ } > if ((enc->cipher = cipher_by_name(name)) == NULL) > return SSH_ERR_INTERNAL_ERROR; > enc->name = name; >@@ -649,8 +654,12 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) > { > char *name = match_list(client, server, NULL); > >- if (name == NULL) >+ if (name == NULL) { >+#ifdef SSH_AUDIT_EVENTS >+ audit_unsupported(SSH_AUDIT_UNSUPPORTED_MAC); >+#endif > return SSH_ERR_NO_MAC_ALG_MATCH; >+ } > if (mac_setup(mac, name) < 0) > return SSH_ERR_INTERNAL_ERROR; > /* truncate the key */ >@@ -667,8 +676,12 @@ choose_comp(struct sshcomp *comp, char *client, char *server) > { > char *name = match_list(client, server, NULL); > >- if (name == NULL) >+ if (name == NULL) { >+#ifdef SSH_AUDIT_EVENTS >+ audit_unsupported(SSH_AUDIT_UNSUPPORTED_COMPRESSION); >+#endif > return SSH_ERR_NO_COMPRESS_ALG_MATCH; >+ } > if (strcmp(name, "zlib@openssh.com") == 0) { > comp->type = COMP_DELAYED; > } else if (strcmp(name, "zlib") == 0) { >@@ -839,6 +852,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; >@@ -1013,3 +1030,33 @@ dump_digest(char *msg, u_char *digest, int len) > sshbuf_dump_data(digest, len, stderr); > } > #endif >+ >+static void >+enc_destroy(struct sshenc *enc) >+{ >+ if (enc == NULL) >+ return; >+ >+ if (enc->key) { >+ memset(enc->key, 0, enc->key_len); >+ free(enc->key); >+ } >+ >+ if (enc->iv) { >+ memset(enc->iv, 0, enc->iv_len); >+ free(enc->iv); >+ } >+ >+ memset(enc, 0, sizeof(*enc)); >+} >+ >+void >+newkeys_destroy(struct newkeys *newkeys) >+{ >+ if (newkeys == NULL) >+ return; >+ >+ enc_destroy(&newkeys->enc); >+ mac_destroy(&newkeys->mac); >+ memset(&newkeys->comp, 0, sizeof(newkeys->comp)); >+} >diff --git a/kex.h b/kex.h >index 1c58966..d3afffe 100644 >--- a/kex.h >+++ b/kex.h >@@ -190,6 +190,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 *); >diff --git a/key.h b/key.h >index 34c992b..02d9fa7 100644 >--- a/key.h >+++ b/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 >diff --git a/mac.c b/mac.c >index f63fbff..adfe66c 100644 >--- a/mac.c >+++ b/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 >diff --git a/mac.h b/mac.h >index e5f6b84..c4b92f0 100644 >--- a/mac.h >+++ b/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 */ >diff --git a/monitor.c b/monitor.c >index ac7dd30..c01456b 100644 >--- a/monitor.c >+++ b/monitor.c >@@ -101,6 +101,7 @@ > #include "compat.h" > #include "ssh2.h" > #include "authfd.h" >+#include "audit.h" > #include "match.h" > #include "ssherr.h" > >@@ -116,6 +117,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; > >@@ -161,6 +164,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 *); >@@ -217,6 +225,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}, >@@ -248,6 +260,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} > }; >@@ -280,6 +297,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} >@@ -293,6 +314,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} >@@ -1411,9 +1437,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); >@@ -1421,6 +1449,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) >@@ -1441,7 +1471,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"); > >@@ -1502,6 +1542,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); > } > >@@ -1784,6 +1830,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); >@@ -1826,11 +1874,43 @@ mm_answer_audit_command(int socket, Buffer *m) > { > u_int len; > char *cmd; >+ Session *s; > > debug3("%s entering", __func__); > cmd = buffer_get_string(m, &len); >+ > /* sanity check command, if so how? */ >- audit_run_command(cmd); >+ s = session_new(); >+ if (s == NULL) >+ fatal("%s: error allocating a session", __func__); >+ s->command = cmd; >+ s->command_handle = audit_run_command(cmd); >+ >+ buffer_clear(m); >+ buffer_put_int(m, s->self); >+ >+ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); >+ >+ return (0); >+} >+ >+int >+mm_answer_audit_end_command(int socket, Buffer *m) >+{ >+ int handle; >+ u_int len; >+ char *cmd; >+ Session *s; >+ >+ debug3("%s entering", __func__); >+ handle = buffer_get_int(m); >+ cmd = buffer_get_string(m, &len); >+ >+ s = session_by_id(handle); >+ if (s == NULL || s->ttyfd != -1 || s->command == NULL || >+ strcmp(s->command, cmd) != 0) >+ fatal("%s: invalid handle", __func__); >+ mm_session_close(s); > free(cmd); > return (0); > } >@@ -1880,6 +1960,7 @@ monitor_apply_keystate(struct monitor *pmonitor) > void > mm_get_keystate(struct monitor *pmonitor) > { >+ Buffer m; > debug3("%s: Waiting for new keys", __func__); > > if ((child_state = sshbuf_new()) == NULL) >@@ -1887,6 +1968,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) >+ ; >+ > } > > >@@ -2056,3 +2152,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 */ >diff --git a/monitor.h b/monitor.h >index 93b8b66..89a41c1 100644 >--- a/monitor.h >+++ b/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 > > }; > >diff --git a/monitor_wrap.c b/monitor_wrap.c >index c5db6df..c8762e4 100644 >--- a/monitor_wrap.c >+++ b/monitor_wrap.c >@@ -443,7 +443,7 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key, > */ > > int >-mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) >+mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) > { > Buffer m; > u_char *blob; >@@ -457,6 +457,7 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) > return (0); > > buffer_init(&m); >+ buffer_put_int(&m, type); > buffer_put_string(&m, blob, len); > buffer_put_string(&m, sig, siglen); > buffer_put_string(&m, data, datalen); >@@ -474,6 +475,18 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) > return (verified); > } > >+int >+mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) >+{ >+ return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen); >+} >+ >+int >+mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) >+{ >+ return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen); >+} >+ > 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,114 @@ 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 : "<implicit>")); >+ buffer_put_cstring(&m, compress); >+ buffer_put_cstring(&m, fps); >+ buffer_put_int64(&m, pid); >+ buffer_put_int64(&m, uid); >+ >+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m); >+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, >+ &m); >+ >+ buffer_free(&m); >+} >+ >+void >+mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) >+{ >+ Buffer m; >+ >+ buffer_init(&m); >+ buffer_put_int(&m, ctos); >+ buffer_put_int64(&m, pid); >+ buffer_put_int64(&m, uid); >+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); >+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, >+ &m); >+ buffer_free(&m); >+} >+ >+void >+mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) >+{ >+ Buffer m; >+ >+ buffer_init(&m); >+ buffer_put_cstring(&m, fp); >+ buffer_put_int64(&m, pid); >+ buffer_put_int64(&m, uid); >+ >+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m); >+ buffer_free(&m); >+} >+ >+int mm_forward_audit_messages(int fdin) >+{ >+ u_char buf[4]; >+ u_int blen, msg_len; >+ Buffer m; >+ int ret = 0; >+ >+ debug3("%s: entering", __func__); >+ buffer_init(&m); >+ do { >+ blen = atomicio(read, fdin, buf, sizeof(buf)); >+ if (blen == 0) /* closed pipe */ >+ break; >+ if (blen != sizeof(buf)) { >+ error("%s: Failed to read the buffer from child", __func__); >+ ret = -1; >+ break; >+ } >+ >+ msg_len = get_u32(buf); >+ if (msg_len > 256 * 1024) >+ fatal("%s: read: bad msg_len %d", __func__, msg_len); >+ buffer_clear(&m); >+ buffer_append_space(&m, msg_len); >+ if (atomicio(read, fdin, buffer_ptr(&m), msg_len) != msg_len) { >+ error("%s: Failed to read the the buffer conent from the child", __func__); >+ ret = -1; >+ break; >+ } >+ if (atomicio(vwrite, pmonitor->m_recvfd, buf, blen) != blen || >+ atomicio(vwrite, pmonitor->m_recvfd, buffer_ptr(&m), msg_len) != msg_len) { >+ error("%s: Failed to write the messag to the monitor", __func__); >+ ret = -1; >+ break; >+ } >+ } while (1); >+ buffer_free(&m); >+ return ret; >+} >+void mm_set_monitor_pipe(int fd) >+{ >+ pmonitor->m_recvfd = fd; >+} >+#endif /* SSH_AUDIT_EVENTS */ >diff --git a/monitor_wrap.h b/monitor_wrap.h >index eb820ae..9e78374 100644 >--- a/monitor_wrap.h >+++ b/monitor_wrap.h >@@ -49,7 +49,8 @@ int mm_key_allowed(enum mm_keytype, char *, char *, Key *, int); > int mm_user_key_allowed(struct passwd *, Key *, int); > int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); > int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); >-int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); >+int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int); >+int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int); > int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); > int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); > BIGNUM *mm_auth_rsa_generate_challenge(Key *); >@@ -74,7 +75,14 @@ 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); >+int mm_forward_audit_messages(int); >+void mm_set_monitor_pipe(int); > #endif > > struct Session; >diff --git a/packet.c b/packet.c >index f406c07..3957053 100644 >--- a/packet.c >+++ b/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" >@@ -454,6 +455,13 @@ ssh_packet_get_connection_out(struct ssh *ssh) > return ssh->state->connection_out; > } > >+static int >+packet_state_has_keys (const struct session_state *state) >+{ >+ return state != NULL && >+ (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL); >+} >+ > /* > * Returns the IP-address of the remote host as a string. The returned > * string must not be freed. >@@ -498,13 +506,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); >@@ -536,12 +537,22 @@ 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(MODE_OUT); >+ } > free(ssh->remote_ipaddr); > ssh->remote_ipaddr = NULL; >+ if (state->connection_in == state->connection_out) { >+ shutdown(state->connection_out, SHUT_RDWR); >+ close(state->connection_out); >+ } else { >+ close(state->connection_in); >+ close(state->connection_out); >+ } > free(ssh->state); > ssh->state = NULL; > } >@@ -966,6 +977,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode) > (unsigned long long)state->p_read.blocks, > (unsigned long long)state->p_send.bytes, > (unsigned long long)state->p_send.blocks); >+ audit_session_key_free(mode); > if ((r = cipher_cleanup(cc)) != 0) > return r; > enc = &state->newkeys[mode]->enc; >@@ -2406,6 +2418,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_cleanup(&state->receive_context); >+ cipher_cleanup(&state->send_context); >+ >+ buffer_free(state->input); >+ state->input = NULL; >+ buffer_free(state->output); >+ state->output = NULL; >+ buffer_free(state->outgoing_packet); >+ state->outgoing_packet = NULL; >+ buffer_free(state->incoming_packet); >+ state->incoming_packet = NULL; >+ if( state->compression_buffer ) { >+ buffer_free(state->compression_buffer); >+ state->compression_buffer = NULL; >+ } >+ newkeys_destroy_and_free(state->newkeys[MODE_IN]); >+ state->newkeys[MODE_IN] = NULL; >+ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); >+ state->newkeys[MODE_OUT] = NULL; >+ mac_destroy(state->packet_discard_mac); >+// TAILQ_HEAD(, packet) outgoing; >+// memset(state, 0, sizeof(state)); >+} >+ >+void >+packet_destroy_all(int audit_it, int privsep) >+{ >+ if (audit_it) >+ audit_it = (active_state != NULL && packet_state_has_keys(active_state->state)); >+ if (active_state != NULL) >+ packet_destroy_state(active_state->state); >+ if (audit_it) { >+#ifdef SSH_AUDIT_EVENTS >+ if (privsep) >+ audit_session_key_free(MODE_OUT); >+ else >+ audit_session_key_free_body(MODE_OUT, getpid(), getuid()); >+#endif >+ } >+} >+ > /* Reset after_authentication and reset compression in post-auth privsep */ > static int > ssh_packet_set_postauth(struct ssh *ssh) >diff --git a/packet.h b/packet.h >index 28516a5..29a25ae 100644 >--- a/packet.h >+++ b/packet.h >@@ -200,4 +200,5 @@ extern struct ssh *active_state; > # undef EC_POINT > #endif > >+void packet_destroy_all(int, int); > #endif /* PACKET_H */ >diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c >index d132e26..b4990bb 100644 >--- a/sandbox-seccomp-filter.c >+++ b/sandbox-seccomp-filter.c >@@ -153,6 +153,12 @@ static const struct sock_filter preauth_insns[] = { > #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 >diff --git a/session.c b/session.c >index 7a02500..fc1379f 100644 >--- a/session.c >+++ b/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. */ >@@ -159,6 +159,10 @@ static Session *sessions = NULL; > login_cap_t *lc; > #endif > >+#ifdef SSH_AUDIT_EVENTS >+int paudit[2]; >+#endif >+ > static int is_child = 0; > static int in_chroot = 0; > >@@ -730,6 +734,14 @@ do_exec_pty(Session *s, const char *command) > /* Parent. Close the slave side of the pseudo tty. */ > close(ttyfd); > >+#if !defined(HAVE_OSF_SIA) && defined(SSH_AUDIT_EVENTS) >+ /* do_login in the child did not affect state in this process, >+ compensate. From an architectural standpoint, this is extremely >+ ugly. */ >+ if (!(options.use_login && command == NULL)) >+ audit_count_session_open(); >+#endif >+ > /* Enter interactive session. */ > s->ptymaster = ptymaster; > packet_set_interactive(1, >@@ -825,15 +837,21 @@ do_exec(Session *s, const char *command) > s->self); > > #ifdef SSH_AUDIT_EVENTS >+ if (s->command != NULL || s->command_handle != -1) >+ fatal("do_exec: command already set"); > if (command != NULL) >- PRIVSEP(audit_run_command(command)); >+ s->command = xstrdup(command); > else if (s->ttyfd == -1) { > char *shell = s->pw->pw_shell; > > if (shell[0] == '\0') /* empty shell means /bin/sh */ > shell =_PATH_BSHELL; >- PRIVSEP(audit_run_command(shell)); >+ s->command = xstrdup(shell); > } >+ if (s->command != NULL && s->ptyfd == -1) >+ s->command_handle = PRIVSEP(audit_run_command(s->command)); >+ if (pipe(paudit) < 0) >+ fatal("pipe: %s", strerror(errno)); > #endif > if (s->ttyfd != -1) > ret = do_exec_pty(s, command); >@@ -849,6 +867,20 @@ do_exec(Session *s, const char *command) > */ > buffer_clear(&loginmsg); > >+#ifdef SSH_AUDIT_EVENTS >+ close(paudit[1]); >+ if (use_privsep && ret == 0) { >+ /* >+ * Read the audit messages from forked child and send them >+ * back to monitor. We don't want to communicate directly, >+ * because the messages might get mixed up. >+ * Continue after the pipe gets closed (all messages sent). >+ */ >+ ret = mm_forward_audit_messages(paudit[0]); >+ } >+ close(paudit[0]); >+#endif /* SSH_AUDIT_EVENTS */ >+ > return ret; > } > >@@ -1669,8 +1701,27 @@ do_child(Session *s, const char *command) > struct passwd *pw = s->pw; > int r = 0; > >+#ifdef SSH_AUDIT_EVENTS >+ int pparent = paudit[1]; >+ close(paudit[0]); >+ /* Hack the monitor pipe to avoid race condition with parent */ >+ if (use_privsep) >+ mm_set_monitor_pipe(pparent); >+#endif >+ > /* remove hostkey from the child's memory */ >- destroy_sensitive_data(); >+ destroy_sensitive_data(use_privsep); >+ /* >+ * We can audit this, because wer hacked the pipe to direct the >+ * messages over postauth child. But this message requires answer >+ * which we can't do using one-way pipe. >+ */ >+ packet_destroy_all(0, 1); >+ >+#ifdef SSH_AUDIT_EVENTS >+ /* Notify parent that we are done */ >+ close(pparent); >+#endif > > /* Force a password change */ > if (s->authctxt->force_pwchange) { >@@ -1897,6 +1948,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; > } >@@ -1979,6 +2033,19 @@ session_open(Authctxt *authctxt, int chanid) > } > > Session * >+session_by_id(int id) >+{ >+ if (id >= 0 && id < sessions_nalloc) { >+ Session *s = &sessions[id]; >+ if (s->used) >+ return s; >+ } >+ debug("%s: unknown id %d", __func__, id); >+ session_dump(); >+ return NULL; >+} >+ >+Session * > session_by_tty(char *tty) > { > int i; >@@ -2495,6 +2562,32 @@ session_exit_message(Session *s, int status) > chan_write_failed(c); > } > >+#ifdef SSH_AUDIT_EVENTS >+void >+session_end_command2(Session *s) >+{ >+ if (s->command != NULL) { >+ if (s->command_handle != -1) >+ audit_end_command(s->command_handle, s->command); >+ free(s->command); >+ s->command = NULL; >+ s->command_handle = -1; >+ } >+} >+ >+static void >+session_end_command(Session *s) >+{ >+ if (s->command != NULL) { >+ if (s->command_handle != -1) >+ PRIVSEP(audit_end_command(s->command_handle, s->command)); >+ free(s->command); >+ s->command = NULL; >+ s->command_handle = -1; >+ } >+} >+#endif >+ > void > session_close(Session *s) > { >@@ -2508,6 +2601,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); >@@ -2722,6 +2819,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) > { >@@ -2770,5 +2876,5 @@ do_cleanup(Authctxt *authctxt) > * or if running in monitor. > */ > if (!use_privsep || mm_is_monitor()) >- session_destroy_all(session_pty_cleanup2); >+ session_destroy_all(do_cleanup_one_session); > } >diff --git a/session.h b/session.h >index 6a2f35e..e9b312e 100644 >--- a/session.h >+++ b/session.h >@@ -61,6 +61,12 @@ struct Session { > char *name; > char *val; > } *env; >+ >+ /* exec */ >+#ifdef SSH_AUDIT_EVENTS >+ int command_handle; >+ char *command; >+#endif > }; > > void do_authenticated(Authctxt *); >@@ -73,8 +79,10 @@ void session_close_by_pid(pid_t, int); > void session_close_by_channel(int, void *); > void session_destroy_all(void (*)(Session *)); > void session_pty_cleanup2(Session *); >+void session_end_command2(Session *); > > Session *session_new(void); >+Session *session_by_id(int); > Session *session_by_tty(char *); > void session_close(Session *); > void do_setusercontext(struct passwd *); >diff --git a/sshd.c b/sshd.c >index 430569c..8cbbca1 100644 >--- a/sshd.c >+++ b/sshd.c >@@ -121,6 +121,7 @@ > #include "ssh-gss.h" > #endif > #include "monitor_wrap.h" >+#include "audit.h" > #include "ssh-sandbox.h" > #include "version.h" > #include "ssherr.h" >@@ -253,7 +254,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 >@@ -274,6 +275,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) > { >@@ -553,22 +563,49 @@ sshd_exchange_identification(int sock_in, int sock_out) > } > } > >-/* Destroy the host and server keys. They will no longer be needed. */ >+/* >+ * Destroy the host and server keys. They will no longer be needed. Careful, >+ * this can be called from cleanup_exit() - i.e. from just about anywhere. >+ */ > void >-destroy_sensitive_data(void) >+destroy_sensitive_data(int privsep) > { > int i; >+#ifdef SSH_AUDIT_EVENTS >+ pid_t pid; >+ uid_t uid; > >+ pid = getpid(); >+ uid = getuid(); >+#endif > if (sensitive_data.server_key) { > key_free(sensitive_data.server_key); > sensitive_data.server_key = NULL; > } > for (i = 0; i < options.num_host_key_files; i++) { > if (sensitive_data.host_keys[i]) { >+ char *fp; >+ >+ if (key_is_private(sensitive_data.host_keys[i])) >+ fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); >+ else >+ fp = NULL; > key_free(sensitive_data.host_keys[i]); > sensitive_data.host_keys[i] = NULL; >+ if (fp != NULL) { >+#ifdef SSH_AUDIT_EVENTS >+ if (privsep) >+ PRIVSEP(audit_destroy_sensitive_data(fp, >+ pid, uid)); >+ else >+ audit_destroy_sensitive_data(fp, >+ pid, uid); >+#endif >+ free(fp); >+ } > } >- if (sensitive_data.host_certificates[i]) { >+ if (sensitive_data.host_certificates >+ && sensitive_data.host_certificates[i]) { > key_free(sensitive_data.host_certificates[i]); > sensitive_data.host_certificates[i] = NULL; > } >@@ -583,7 +620,13 @@ demote_sensitive_data(void) > { > Key *tmp; > int i; >+#ifdef SSH_AUDIT_EVENTS >+ pid_t pid; >+ uid_t uid; > >+ pid = getpid(); >+ uid = getuid(); >+#endif > if (sensitive_data.server_key) { > tmp = key_demote(sensitive_data.server_key); > key_free(sensitive_data.server_key); >@@ -592,11 +635,23 @@ demote_sensitive_data(void) > > for (i = 0; i < options.num_host_key_files; i++) { > if (sensitive_data.host_keys[i]) { >+ char *fp; >+ >+ if (key_is_private(sensitive_data.host_keys[i])) >+ fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); >+ else >+ fp = NULL; > tmp = key_demote(sensitive_data.host_keys[i]); > key_free(sensitive_data.host_keys[i]); > sensitive_data.host_keys[i] = tmp; > if (tmp->type == KEY_RSA1) > sensitive_data.ssh1_host_key = tmp; >+ if (fp != NULL) { >+#ifdef SSH_AUDIT_EVENTS >+ audit_destroy_sensitive_data(fp, pid, uid); >+#endif >+ free(fp); >+ } > } > /* Certs do not need demotion */ > } >@@ -746,6 +801,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 +1334,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) > if (received_sigterm) { > logit("Received signal %d; terminating.", > (int) received_sigterm); >+ destroy_sensitive_data(0); > close_listen_socks(); > if (options.pid_file != NULL) > unlink(options.pid_file); >@@ -2212,6 +2274,7 @@ main(int ac, char **av) > */ > if (use_privsep) { > mm_send_keystate(pmonitor); >+ packet_destroy_all(1, 1); > exit(0); > } > >@@ -2254,7 +2317,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, >@@ -2268,6 +2331,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); >@@ -2428,6 +2494,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(MODE_OUT, cipher_name(cipher_type), "crc", "none", "none"); >+#endif >+ > debug("Encryption type: %.200s", cipher_name(cipher_type)); > > /* Get the encrypted integer. */ >@@ -2487,7 +2557,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); >@@ -2612,6 +2682,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 && >@@ -2623,9 +2703,14 @@ cleanup_exit(int i) > pmonitor->m_pid, strerror(errno)); > } > } >+ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; >+ if (sensitive_data.host_keys != NULL) >+ destroy_sensitive_data(is_privsep_child); >+ packet_destroy_all(1, is_privsep_child); > #ifdef SSH_AUDIT_EVENTS > /* done after do_cleanup so it can cancel the PAM auth 'thread' */ >- if (!use_privsep || mm_is_monitor()) >+ if ((the_authctxt == NULL || !the_authctxt->authenticated) && >+ (!use_privsep || mm_is_monitor())) > audit_event(SSH_CONNECTION_ABANDON); > #endif > _exit(i); >diff --git a/sshkey.c b/sshkey.c >index 87b093e..d212de6 100644 >--- a/sshkey.c >+++ b/sshkey.c >@@ -302,6 +302,33 @@ sshkey_type_is_valid_ca(int type) > } > > int >+sshkey_is_private(const struct sshkey *k) >+{ >+ switch (k->type) { >+#ifdef WITH_OPENSSL >+ case KEY_RSA_CERT: >+ case KEY_RSA1: >+ case KEY_RSA: >+ return k->rsa->d != NULL; >+ case KEY_DSA_CERT: >+ case KEY_DSA: >+ return k->dsa->priv_key != NULL; >+#ifdef OPENSSL_HAS_ECC >+ case KEY_ECDSA_CERT: >+ case KEY_ECDSA: >+ return EC_KEY_get0_private_key(k->ecdsa) != NULL; >+#endif /* OPENSSL_HAS_ECC */ >+#endif /* WITH_OPENSSL */ >+ case KEY_ED25519_CERT: >+ case KEY_ED25519: >+ return (k->ed25519_pk != NULL); >+ default: >+ /* fatal("key_is_private: bad key type %d", k->type); */ >+ return 0; >+ } >+} >+ >+int > sshkey_is_cert(const struct sshkey *k) > { > if (k == NULL) >diff --git a/sshkey.h b/sshkey.h >index a20a14f..a15e349 100644 >--- a/sshkey.h >+++ b/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); >-- >2.5.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1402
:
1396
|
1930
|
1931
|
1934
|
1939
|
1940
|
1942
|
1943
|
1945
|
1950
|
1951
|
1952
|
1954
|
1974
|
1975
|
1976
|
1981
|
2010
|
2011
|
2012
|
2013
|
2014
|
2015
|
2085
|
2086
|
2087
|
2088
|
2089
|
2090
| 2795