# extended auditing of user actions # based on: # https://bugzilla.mindrot.org/show_bug.cgi?id=1402 # https://bugzilla.mindrot.org/attachment.cgi?id=2011 # by jchadima@redhat.com diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c --- a/openssh-6.6p1/audit-bsm.c +++ b/openssh-6.6p1/audit-bsm.c @@ -370,20 +370,33 @@ audit_connection_from(const char *host, /* this is used on IPv4-only machines */ tid->port = (dev_t)port; tid->machine = inet_addr(host); snprintf(buf, sizeof(buf), "%08x", tid->machine); debug3("BSM audit: machine ID %s", buf); #endif } -void +int audit_run_command(const char *command) { /* not implemented */ + return 0; +} + +void +audit_end_command(int handle, const char *command) +{ + /* not implemented */ +} + +void +audit_count_session_open(void) +{ + /* not necessary */ } void audit_session_open(struct logininfo *li) { /* not implemented */ } diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c --- a/openssh-6.6p1/audit-linux.c +++ b/openssh-6.6p1/audit-linux.c @@ -30,97 +30,210 @@ #include "includes.h" #if defined(USE_LINUX_AUDIT) #include #include #include #include "log.h" #include "audit.h" +#include "key.h" +#include "hostfile.h" +#include "auth.h" +#include "servconf.h" #include "canohost.h" +extern ServerOptions options; +extern Authctxt *the_authctxt; +extern u_int utmp_len; const char* audit_username(void); -int -linux_audit_record_event(int uid, const char *username, - const char *hostname, const char *ip, const char *ttyn, int success) +static void +linux_audit_user_logxxx(int uid, const char *username, + const char *hostname, const char *ip, const char *ttyn, int success, int event) { int audit_fd, rc, saved_errno; audit_fd = audit_open(); if (audit_fd < 0) { if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) - return 1; /* No audit support in kernel */ + return; /* No audit support in kernel */ else - return 0; /* Must prevent login */ + goto fatal_report; /* Must prevent login */ } - rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, + rc = audit_log_acct_message(audit_fd, event, NULL, "login", username ? username : "(unknown)", username == NULL ? uid : -1, hostname, ip, ttyn, success); saved_errno = errno; close(audit_fd); /* * Do not report error if the error is EPERM and sshd is run as non * root user. */ if ((rc == -EPERM) && (geteuid() != 0)) rc = 0; errno = saved_errno; - return (rc >= 0); + if (rc < 0) { +fatal_report: + fatal("linux_audit_write_entry failed: %s", strerror(errno)); + } } +static void +linux_audit_user_auth(int uid, const char *username, + const char *hostname, const char *ip, const char *ttyn, int success, int event) +{ + int audit_fd, rc, saved_errno; + static const char *event_name[] = { + "maxtries exceeded", + "root denied", + "success", + "none", + "password", + "challenge-response", + "pubkey", + "hostbased", + "gssapi", + "invalid user", + "nologin", + "connection closed", + "connection abandoned", + "unknown" + }; + + audit_fd = audit_open(); + if (audit_fd < 0) { + if (errno == EINVAL || errno == EPROTONOSUPPORT || + errno == EAFNOSUPPORT) + return; /* No audit support in kernel */ + else + goto fatal_report; /* Must prevent login */ + } + + if ((event < 0) || (event > SSH_AUDIT_UNKNOWN)) + event = SSH_AUDIT_UNKNOWN; + + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, + NULL, event_name[event], username ? username : "(unknown)", + username == NULL ? uid : -1, hostname, ip, ttyn, success); + saved_errno = errno; + close(audit_fd); + /* + * Do not report error if the error is EPERM and sshd is run as non + * root user. + */ + if ((rc == -EPERM) && (geteuid() != 0)) + rc = 0; + errno = saved_errno; + if (rc < 0) { +fatal_report: + fatal("linux_audit_write_entry failed: %s", strerror(errno)); + } +} + +static int user_login_count = 0; + /* Below is the sshd audit API code */ void audit_connection_from(const char *host, int port) { + /* not implemented */ } - /* not implemented */ + +int +audit_run_command(const char *command) +{ + if (!user_login_count++) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_LOGIN); + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_START); + return 0; +} void -audit_run_command(const char *command) +audit_end_command(int handle, const char *command) { - /* not implemented */ + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_END); + if (user_login_count && !--user_login_count) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_LOGOUT); +} + +void +audit_count_session_open(void) +{ + user_login_count++; } void audit_session_open(struct logininfo *li) { - if (linux_audit_record_event(li->uid, NULL, li->hostname, - NULL, li->line, 1) == 0) - fatal("linux_audit_write_entry failed: %s", strerror(errno)); + if (!user_login_count++) + linux_audit_user_logxxx(li->uid, NULL, li->hostname, + NULL, li->line, 1, AUDIT_USER_LOGIN); + linux_audit_user_logxxx(li->uid, NULL, li->hostname, + NULL, li->line, 1, AUDIT_USER_START); } void audit_session_close(struct logininfo *li) { - /* not implemented */ + linux_audit_user_logxxx(li->uid, NULL, li->hostname, + NULL, li->line, 1, AUDIT_USER_END); + if (user_login_count && !--user_login_count) + linux_audit_user_logxxx(li->uid, NULL, li->hostname, + NULL, li->line, 1, AUDIT_USER_LOGOUT); } void audit_event(ssh_audit_event_t event) { switch(event) { case SSH_AUTH_SUCCESS: - case SSH_CONNECTION_CLOSE: - case SSH_NOLOGIN: - case SSH_LOGIN_EXCEED_MAXTRIES: - case SSH_LOGIN_ROOT_DENIED: + linux_audit_user_auth(-1, audit_username(), NULL, + get_remote_ipaddr(), "ssh", 1, event); break; + case SSH_NOLOGIN: + case SSH_LOGIN_ROOT_DENIED: + linux_audit_user_auth(-1, audit_username(), NULL, + get_remote_ipaddr(), "ssh", 0, event); + linux_audit_user_logxxx(-1, audit_username(), NULL, + get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); + break; + + case SSH_LOGIN_EXCEED_MAXTRIES: case SSH_AUTH_FAIL_NONE: case SSH_AUTH_FAIL_PASSWD: case SSH_AUTH_FAIL_KBDINT: case SSH_AUTH_FAIL_PUBKEY: case SSH_AUTH_FAIL_HOSTBASED: case SSH_AUTH_FAIL_GSSAPI: + linux_audit_user_auth(-1, audit_username(), NULL, + get_remote_ipaddr(), "ssh", 0, event); + break; + + case SSH_CONNECTION_CLOSE: + if (user_login_count) { + while (user_login_count--) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_END); + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_LOGOUT); + } + break; + + case SSH_CONNECTION_ABANDON: case SSH_INVALID_USER: - linux_audit_record_event(-1, audit_username(), NULL, - get_remote_ipaddr(), "sshd", 0); + linux_audit_user_logxxx(-1, audit_username(), NULL, + get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); break; default: debug("%s: unhandled event %d", __func__, event); } } #endif /* USE_LINUX_AUDIT */ diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c --- a/openssh-6.6p1/audit.c +++ b/openssh-6.6p1/audit.c @@ -135,16 +135,27 @@ audit_connection_from(const char *host, void audit_event(ssh_audit_event_t event) { debug("audit event euid %d user %s event %d (%s)", geteuid(), audit_username(), event, audit_event_lookup(event)); } /* + * Called when a child process has called, or will soon call, + * audit_session_open. + */ +void +audit_count_session_open(void) +{ + debug("audit count session open euid %d user %s", geteuid(), + audit_username()); +} + +/* * Called when a user session is started. Argument is the tty allocated to * the session, or NULL if no tty was allocated. * * Note that this may be called multiple times if multiple sessions are used * within a single connection. */ void audit_session_open(struct logininfo *li) @@ -169,18 +180,34 @@ audit_session_close(struct logininfo *li debug("audit session close euid %d user %s tty name %s", geteuid(), audit_username(), t); } /* * This will be called when a user runs a non-interactive command. Note that * it may be called multiple times for a single connection since SSH2 allows - * multiple sessions within a single connection. + * multiple sessions within a single connection. Returns a "handle" for + * audit_end_command. */ -void +int audit_run_command(const char *command) { debug("audit run command euid %d user %s command '%.200s'", geteuid(), audit_username(), command); + return 0; } + +/* + * This will be called when the non-interactive command finishes. Note that + * it may be called multiple times for a single connection since SSH2 allows + * multiple sessions within a single connection. "handle" should come from + * the corresponding audit_run_command. + */ +void +audit_end_command(int handle, const char *command) +{ + debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), + audit_username(), command); +} + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ #endif /* SSH_AUDIT_EVENTS */ diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h --- a/openssh-6.6p1/audit.h +++ b/openssh-6.6p1/audit.h @@ -44,14 +44,16 @@ enum ssh_audit_event_type { SSH_CONNECTION_CLOSE, /* closed after attempting auth or session */ SSH_CONNECTION_ABANDON, /* closed without completing auth */ SSH_AUDIT_UNKNOWN }; typedef enum ssh_audit_event_type ssh_audit_event_t; void audit_connection_from(const char *, int); void audit_event(ssh_audit_event_t); +void audit_count_session_open(void); void audit_session_open(struct logininfo *); void audit_session_close(struct logininfo *); -void audit_run_command(const char *); +int audit_run_command(const char *); +void audit_end_command(int, const char *); ssh_audit_event_t audit_classify_auth(const char *); #endif /* _SSH_AUDIT_H */ diff --git a/openssh-6.6p1/monitor.c b/openssh-6.6p1/monitor.c --- a/openssh-6.6p1/monitor.c +++ b/openssh-6.6p1/monitor.c @@ -175,16 +175,17 @@ int mm_answer_gss_setup_ctx(int, Buffer int mm_answer_gss_accept_ctx(int, Buffer *); int mm_answer_gss_userok(int, Buffer *); int mm_answer_gss_checkmic(int, Buffer *); #endif #ifdef SSH_AUDIT_EVENTS int mm_answer_audit_event(int, Buffer *); int mm_answer_audit_command(int, Buffer *); +int mm_answer_audit_end_command(int, Buffer *); #endif static int monitor_read_log(struct monitor *); static Authctxt *authctxt; static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ /* local state for key verify */ @@ -255,16 +256,17 @@ struct mon_table mon_dispatch_postauth20 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, {MONITOR_REQ_SIGN, 0, mm_answer_sign}, {MONITOR_REQ_PTY, 0, mm_answer_pty}, {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, {MONITOR_REQ_TERM, 0, mm_answer_term}, #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, + {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, #endif {0, 0, NULL} }; struct mon_table mon_dispatch_proto15[] = { {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, @@ -297,16 +299,17 @@ struct mon_table mon_dispatch_proto15[] struct mon_table mon_dispatch_postauth15[] = { {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty}, {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup}, {MONITOR_REQ_TERM, 0, mm_answer_term}, #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, + {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, #endif {0, 0, NULL} }; struct mon_table *mon_dispatch; /* Specifies if a certain message is allowed at the moment */ @@ -1420,16 +1423,22 @@ mm_record_login(Session *s, struct passw static void mm_session_close(Session *s) { debug3("%s: session %d pid %ld", __func__, s->self, (long)s->pid); if (s->ttyfd != -1) { debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); session_pty_cleanup2(s); } +#ifdef SSH_AUDIT_EVENTS + if (s->command != NULL) { + debug3("%s: command %d", __func__, s->command_handle); + session_end_command2(s); + } +#endif session_unused(s->self); } int mm_answer_pty(int sock, Buffer *m) { extern struct monitor *pmonitor; Session *s; @@ -1742,21 +1751,53 @@ mm_answer_audit_event(int socket, Buffer return (0); } int mm_answer_audit_command(int socket, Buffer *m) { u_int len; char *cmd; + Session *s; debug3("%s entering", __func__); cmd = buffer_get_string(m, &len); /* sanity check command, if so how? */ - audit_run_command(cmd); + s = session_new(); + if (s == NULL) + fatal("%s: error allocating a session", __func__); + s->command = cmd; + s->command_handle = audit_run_command(cmd); + + buffer_clear(m); + buffer_put_int(m, s->self); + + mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); + + return (0); +} + +int +mm_answer_audit_end_command(int socket, Buffer *m) +{ + int handle; + u_int len; + char *cmd; + Session *s; + + debug3("%s entering", __func__); + handle = buffer_get_int(m); + cmd = buffer_get_string(m, &len); + + s = session_by_id(handle); + if (s == NULL || s->ttyfd != -1 || s->command == NULL || + strcmp(s->command, cmd) != 0) + fatal("%s: invalid handle", __func__); + mm_session_close(s); + free(cmd); return (0); } #endif /* SSH_AUDIT_EVENTS */ void monitor_apply_keystate(struct monitor *pmonitor) { diff --git a/openssh-6.6p1/monitor.h b/openssh-6.6p1/monitor.h --- a/openssh-6.6p1/monitor.h +++ b/openssh-6.6p1/monitor.h @@ -59,16 +59,17 @@ enum monitor_reqtype { MONITOR_REQ_PAM_START = 100, MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, MONITOR_REQ_PAM_INIT_CTX = 104, MONITOR_ANS_PAM_INIT_CTX = 105, MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, + MONITOR_ANS_AUDIT_COMMAND = 114, MONITOR_REQ_AUDIT_END_COMMAND = 115, }; struct mm_master; struct monitor { int m_recvfd; int m_sendfd; int m_log_recvfd; diff --git a/openssh-6.6p1/monitor_wrap.c b/openssh-6.6p1/monitor_wrap.c --- a/openssh-6.6p1/monitor_wrap.c +++ b/openssh-6.6p1/monitor_wrap.c @@ -1184,27 +1184,48 @@ mm_audit_event(ssh_audit_event_t event) buffer_init(&m); buffer_put_int(&m, event); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_EVENT, &m); buffer_free(&m); } -void +int mm_audit_run_command(const char *command) { Buffer m; + int handle; debug3("%s entering command %s", __func__, command); buffer_init(&m); buffer_put_cstring(&m, command); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m); + + handle = buffer_get_int(&m); + buffer_free(&m); + + return (handle); +} + +void +mm_audit_end_command(int handle, const char *command) +{ + Buffer m; + + debug3("%s entering command %s", __func__, command); + + buffer_init(&m); + buffer_put_int(&m, handle); + buffer_put_cstring(&m, command); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m); buffer_free(&m); } #endif /* SSH_AUDIT_EVENTS */ #ifdef GSSAPI OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid) { diff --git a/openssh-6.6p1/monitor_wrap.h b/openssh-6.6p1/monitor_wrap.h --- a/openssh-6.6p1/monitor_wrap.h +++ b/openssh-6.6p1/monitor_wrap.h @@ -69,17 +69,18 @@ void *mm_sshpam_init_ctx(struct Authctxt int mm_sshpam_query(void *, char **, char **, u_int *, char ***, u_int **); int mm_sshpam_respond(void *, u_int, char **); void mm_sshpam_free_ctx(void *); #endif #ifdef SSH_AUDIT_EVENTS #include "audit.h" void mm_audit_event(ssh_audit_event_t); -void mm_audit_run_command(const char *); +int mm_audit_run_command(const char *); +void mm_audit_end_command(int, const char *); #endif struct Session; void mm_terminate(void); int mm_pty_allocate(int *, int *, char *, size_t); void mm_session_pty_cleanup2(struct Session *); /* SSHv1 interfaces */ diff --git a/openssh-6.6p1/session.c b/openssh-6.6p1/session.c --- a/openssh-6.6p1/session.c +++ b/openssh-6.6p1/session.c @@ -740,16 +740,24 @@ do_exec_pty(Session *s, const char *comm cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); #endif s->pid = pid; /* Parent. Close the slave side of the pseudo tty. */ close(ttyfd); +#ifndef HAVE_OSF_SIA + /* do_login in the child did not affect state in this process, + compensate. From an architectural standpoint, this is extremely + ugly. */ + if (!(options.use_login && command == NULL)) + audit_count_session_open(); +#endif + /* Enter interactive session. */ s->ptymaster = ptymaster; packet_set_interactive(1, options.ip_qos_interactive, options.ip_qos_bulk); if (compat20) { session_set_fds(s, ptyfd, fdout, -1, 1, 1); } else { server_loop(pid, ptyfd, fdout, -1); @@ -834,25 +842,29 @@ do_exec(Session *s, const char *command) session_type, tty == NULL ? "" : " on ", tty == NULL ? "" : tty, s->pw->pw_name, get_remote_ipaddr(), get_remote_port()); #ifdef SSH_AUDIT_EVENTS + if (s->command != NULL || s->command_handle != -1) + fatal("do_exec: command already set"); if (command != NULL) - PRIVSEP(audit_run_command(command)); + s->command = xstrdup(command); else if (s->ttyfd == -1) { char *shell = s->pw->pw_shell; if (shell[0] == '\0') /* empty shell means /bin/sh */ shell =_PATH_BSHELL; - PRIVSEP(audit_run_command(shell)); + s->command = xstrdup(shell); } + if (s->command != NULL) + s->command_handle = PRIVSEP(audit_run_command(s->command)); #endif if (s->ttyfd != -1) ret = do_exec_pty(s, command); else ret = do_exec_no_pty(s, command); original_command = NULL; @@ -1908,16 +1920,17 @@ session_unused(int id) memset(&sessions[id], 0, sizeof(*sessions)); sessions[id].self = id; sessions[id].used = 0; sessions[id].chanid = -1; sessions[id].ptyfd = -1; sessions[id].ttyfd = -1; sessions[id].ptymaster = -1; sessions[id].x11_chanids = NULL; + sessions[id].command_handle = -1; sessions[id].next_unused = sessions_first_unused; sessions_first_unused = id; } Session * session_new(void) { Session *s, *tmp; @@ -1990,16 +2003,29 @@ session_open(Authctxt *authctxt, int cha if (s->pw == NULL || !authctxt->valid) fatal("no user for session %d", s->self); debug("session_open: session %d: link with channel %d", s->self, chanid); s->chanid = chanid; return 1; } Session * +session_by_id(int id) +{ + if (id >= 0 && id < sessions_nalloc) { + Session *s = &sessions[id]; + if (s->used) + return s; + } + debug("session_by_id: unknown id %d", id); + session_dump(); + return NULL; +} + +Session * session_by_tty(char *tty) { int i; for (i = 0; i < sessions_nalloc; i++) { Session *s = &sessions[i]; if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { debug("session_by_tty: session %d tty %s", i, tty); return s; @@ -2506,16 +2532,40 @@ session_exit_message(Session *s, int sta * interested in data we write. * Note that we must not call 'chan_read_failed', since there could * be some more data waiting in the pipe. */ if (c->ostate != CHAN_OUTPUT_CLOSED) chan_write_failed(c); } +#ifdef SSH_AUDIT_EVENTS +void +session_end_command2(Session *s) +{ + if (s->command != NULL) { + audit_end_command(s->command_handle, s->command); + free(s->command); + s->command = NULL; + s->command_handle = -1; + } +} + +static void +session_end_command(Session *s) +{ + if (s->command != NULL) { + PRIVSEP(audit_end_command(s->command_handle, s->command)); + free(s->command); + s->command = NULL; + s->command_handle = -1; + } +} +#endif + void session_close(Session *s) { u_int i; int do_xauth; debug("session_close: session %d pid %ld", s->self, (long)s->pid); @@ -2546,16 +2596,20 @@ session_close(Session *s) int status; waitpid(pid, &status, 0); } } if (s->ttyfd != -1) session_pty_cleanup(s); +#ifdef SSH_AUDIT_EVENTS + if (s->command) + session_end_command(s); +#endif free(s->term); free(s->display); free(s->x11_chanids); free(s->auth_display); free(s->auth_data); free(s->auth_proto); free(s->subsys); if (s->env != NULL) { @@ -2760,16 +2814,25 @@ session_setup_x11fwd(Session *s) } static void do_authenticated2(Authctxt *authctxt) { server_loop2(authctxt); } +static void +do_cleanup_one_session(Session *s) +{ + session_pty_cleanup2(s); +#ifdef SSH_AUDIT_EVENTS + session_end_command2(s); +#endif +} + void do_cleanup(Authctxt *authctxt) { static int called = 0; debug("do_cleanup"); /* no cleanup if we're in the child for login shell */ @@ -2808,10 +2871,10 @@ do_cleanup(Authctxt *authctxt) /* remove agent socket */ auth_sock_cleanup_proc(authctxt->pw); /* * Cleanup ptys/utmp only if privsep is disabled, * or if running in monitor. */ if (!use_privsep || mm_is_monitor()) - session_destroy_all(session_pty_cleanup2); + session_destroy_all(do_cleanup_one_session); } diff --git a/openssh-6.6p1/session.h b/openssh-6.6p1/session.h --- a/openssh-6.6p1/session.h +++ b/openssh-6.6p1/session.h @@ -56,29 +56,37 @@ struct Session { int *x11_chanids; int is_subsystem; char *subsys; u_int num_env; struct { char *name; char *val; } *env; + + /* exec */ +#ifdef SSH_AUDIT_EVENTS + int command_handle; + char *command; +#endif }; void do_authenticated(Authctxt *); void do_cleanup(Authctxt *); int session_open(Authctxt *, int); void session_unused(int); int session_input_channel_req(Channel *, const char *); void session_close_by_pid(pid_t, int); void session_close_by_channel(int, void *); void session_destroy_all(void (*)(Session *)); void session_pty_cleanup2(Session *); +void session_end_command2(Session *); Session *session_new(void); +Session *session_by_id(int); Session *session_by_tty(char *); void session_close(Session *); void do_setusercontext(struct passwd *); void child_set_env(char ***envp, u_int *envsizep, const char *name, const char *value); #endif diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c --- a/openssh-6.6p1/sshd.c +++ b/openssh-6.6p1/sshd.c @@ -2532,13 +2532,14 @@ cleanup_exit(int i) if (kill(pmonitor->m_pid, SIGKILL) != 0 && errno != ESRCH) error("%s: kill(%d): %s", __func__, pmonitor->m_pid, strerror(errno)); } } #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ - if (!use_privsep || mm_is_monitor()) + if ((the_authctxt == NULL || !the_authctxt->authenticated) && + (!use_privsep || mm_is_monitor())) audit_event(SSH_CONNECTION_ABANDON); #endif _exit(i); }