9fb40d132b
- curve25519 key exchange fix (-curve25519-6.6.1p1.patch) - patch re-ordering (-audit3-key_auth_usage-fips.patch, -audit4-kex_results-fips.patch) OBS-URL: https://build.opensuse.org/request/show/231427 OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=80
868 lines
23 KiB
Diff
868 lines
23 KiB
Diff
# 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 <libaudit.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#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);
|
|
}
|