diff -Naur libreswan-3.29-orig/programs/pluto/ikev1.c libreswan-3.29/programs/pluto/ikev1.c
--- libreswan-3.29-orig/programs/pluto/ikev1.c 2019-06-26 22:03:27.801184503 -0400
+++ libreswan-3.29/programs/pluto/ikev1.c 2019-06-27 13:26:11.443969779 -0400
@@ -2675,6 +2675,12 @@
passert(st != NULL);
pexpect(!state_is_busy(st));
+ if (result > STF_OK) {
+ if (st != NULL) {
+ linux_audit_conn(md->st, IS_IKE_SA_ESTABLISHED(md->st) ? LAK_CHILD_FAIL : LAK_PARENT_FAIL);
+ }
+ }
+
switch (result) {
case STF_OK:
{
diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_quick.c libreswan-3.29/programs/pluto/ikev1_quick.c
--- libreswan-3.29-orig/programs/pluto/ikev1_quick.c 2019-06-26 22:03:27.803184531 -0400
+++ libreswan-3.29/programs/pluto/ikev1_quick.c 2019-06-27 13:23:53.787080070 -0400
@@ -1663,6 +1663,9 @@
if (!install_inbound_ipsec_sa(st))
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+ /* we only audit once for IPsec SA's, we picked the inbound SA */
+ linux_audit_conn(st, LAK_CHILD_START);
+
/* encrypt message, except for fixed part of header */
if (!ikev1_encrypt_message(&rbody, st)) {
diff -Naur libreswan-3.29-orig/programs/pluto/ikev2.c libreswan-3.29/programs/pluto/ikev2.c
--- libreswan-3.29-orig/programs/pluto/ikev2.c 2019-06-10 10:22:04.000000000 -0400
+++ libreswan-3.29/programs/pluto/ikev2.c 2019-06-27 13:25:16.529215928 -0400
@@ -3204,6 +3204,13 @@
lswlog_v2_stf_status(buf, result);
}
+ /* audit log failures - success is audit logged in ikev2_ike_sa_established() */
+ if (result > STF_OK) {
+ if (st != NULL) {
+ linux_audit_conn(st, IS_IKE_SA_ESTABLISHED(st) ? LAK_CHILD_FAIL : LAK_PARENT_FAIL);
+ }
+ }
+
switch (result) {
case STF_SUSPEND:
diff -Naur libreswan-3.29-orig/programs/pluto/ikev2_child.c libreswan-3.29/programs/pluto/ikev2_child.c
--- libreswan-3.29-orig/programs/pluto/ikev2_child.c 2019-06-10 10:22:04.000000000 -0400
+++ libreswan-3.29/programs/pluto/ikev2_child.c 2019-06-27 13:23:53.788080084 -0400
@@ -102,6 +102,10 @@
return STF_OK;
}
+/*
+ * The caller could have done the linux_audit_conn() call, except one case
+ * here deletes the state before returning an STF error
+ */
stf_status ikev2_child_sa_respond(struct msg_digest *md,
pb_stream *outpbs,
enum isakmp_xchg_types isa_xchg)
diff -Naur libreswan-3.29-orig/programs/pluto/ikev2_parent.c libreswan-3.29/programs/pluto/ikev2_parent.c
--- libreswan-3.29-orig/programs/pluto/ikev2_parent.c 2019-06-10 10:22:04.000000000 -0400
+++ libreswan-3.29/programs/pluto/ikev2_parent.c 2019-06-27 13:23:53.789080097 -0400
@@ -239,6 +239,7 @@
c->newest_isakmp_sa = ike->sa.st_serialno;
v2_schedule_replace_event(&ike->sa);
ike->sa.st_viable_parent = TRUE;
+ linux_audit_conn(&ike->sa, LAK_PARENT_START);
pstat_sa_established(&ike->sa);
}
@@ -1581,6 +1582,24 @@
libreswan_log("IKE_AUTH response contained an unknown error notification (%d)", n);
} else {
libreswan_log("IKE_AUTH response contained the error notification %s", name);
+ /*
+ * There won't be a child state transition, so log if error is child related.
+ * see RFC 7296 Section 1.2
+ */
+ switch(n) {
+ case v2N_NO_PROPOSAL_CHOSEN:
+ case v2N_SINGLE_PAIR_REQUIRED:
+ case v2N_NO_ADDITIONAL_SAS:
+ case v2N_INTERNAL_ADDRESS_FAILURE:
+ case v2N_FAILED_CP_REQUIRED:
+ case v2N_TS_UNACCEPTABLE:
+ case v2N_INVALID_SELECTORS:
+ /* fallthrough */
+ linux_audit_conn(st, LAK_CHILD_FAIL);
+ break;
+ default:
+ break;
+ }
}
}
}
@@ -3063,10 +3082,6 @@
ikev2_ike_sa_established(pexpect_ike_sa(st), md->svm,
STATE_PARENT_R2);
-#ifdef USE_LINUX_AUDIT
- linux_audit_conn(st, LAK_PARENT_START);
-#endif
-
if (LHAS(st->hidden_variables.st_nat_traversal, NATED_HOST)) {
/* ensure we run keepalives if needed */
if (c->nat_keepalive)
@@ -3801,10 +3816,6 @@
ikev2_ike_sa_established(pexpect_ike_sa(pst), md->svm,
STATE_PARENT_I3);
-#ifdef USE_LINUX_AUDIT
- linux_audit_conn(st, LAK_PARENT_START);
-#endif
-
if (LHAS(st->hidden_variables.st_nat_traversal, NATED_HOST)) {
/* ensure we run keepalives if needed */
if (c->nat_keepalive)
diff -Naur libreswan-3.29-orig/programs/pluto/kernel.c libreswan-3.29/programs/pluto/kernel.c
--- libreswan-3.29-orig/programs/pluto/kernel.c 2019-06-10 10:22:04.000000000 -0400
+++ libreswan-3.29/programs/pluto/kernel.c 2019-06-27 13:23:53.790080111 -0400
@@ -3334,7 +3334,8 @@
}
#ifdef USE_LINUX_AUDIT
- linux_audit_conn(st, LAK_CHILD_START);
+ if (inbound_also)
+ linux_audit_conn(st, LAK_CHILD_START);
#endif
statetime_stop(&start, "%s()", __func__);
@@ -3378,8 +3379,13 @@
{
#ifdef USE_LINUX_AUDIT
/* XXX in IKEv2 we get a spurious call with a parent st :( */
- if (IS_CHILD_SA(st))
- linux_audit_conn(st, LAK_CHILD_DESTROY);
+ if (IS_CHILD_SA(st)) {
+ /* child destruction already logged for STATE_CHILDSA_DEL state */
+ if (st->st_esp.present || st->st_ah.present) {
+ /* ESP or AH means this was an established IPsec SA */
+ linux_audit_conn(st, LAK_CHILD_DESTROY);
+ }
+ }
#endif
switch (kern_interface) {
case USE_KLIPS:
diff -Naur libreswan-3.29-orig/programs/pluto/linux_audit.c libreswan-3.29/programs/pluto/linux_audit.c
--- libreswan-3.29-orig/programs/pluto/linux_audit.c 2019-06-10 10:22:04.000000000 -0400
+++ libreswan-3.29/programs/pluto/linux_audit.c 2019-06-27 13:24:21.474460154 -0400
@@ -176,12 +176,16 @@
zero(&cipher_str); /* OK: no pointer fields */
zero(&spi_str); /* OK: no pointer fields */
+ ip_address_buf raddr_buf;
+ const char *raddr = ipstr(&c->spd.that.host_addr, &raddr_buf);
+
switch (op) {
case LAK_PARENT_START:
case LAK_PARENT_DESTROY:
+ case LAK_PARENT_FAIL:
initiator = (st->st_original_role == ORIGINAL_INITIATOR) || IS_PHASE1_INIT(st->st_state);
snprintf(head, sizeof(head), "op=%s direction=%s %s connstate=%lu ike-version=%s auth=%s",
- op == LAK_PARENT_START ? "start" : "destroy",
+ op == LAK_PARENT_DESTROY ? "destroy" : "start", /* fail to start logged under op=start */
initiator ? "initiator" : "responder",
conn_encode,
st->st_serialno,
@@ -191,7 +195,8 @@
st->st_oakley.auth, &esb));
snprintf(prfname, sizeof(prfname), "%s",
- st->st_oakley.ta_prf->prf_ike_audit_name);
+ st->st_oakley.ta_prf == NULL ? "none" :
+ st->st_oakley.ta_prf->prf_ike_audit_name);
if (st->st_oakley.ta_integ == &ike_alg_integ_none) {
if (st->st_ike_version == IKEv1) {
@@ -220,18 +225,21 @@
}
snprintf(cipher_str, sizeof(cipher_str),
- "cipher=%s ksize=%d integ=%s prf=%s pfs=%s",
- st->st_oakley.ta_encrypt->encrypt_ike_audit_name,
+ "cipher=%s ksize=%d integ=%s prf=%s pfs=%s raddr=%s",
+ st->st_oakley.ta_encrypt == NULL ? "none" :
+ st->st_oakley.ta_encrypt->encrypt_ike_audit_name,
st->st_oakley.enckeylen,
integname, prfname,
- st->st_oakley.ta_dh->common.name);
+ st->st_oakley.ta_dh == NULL ? "none" :
+ st->st_oakley.ta_dh->common.name, raddr);
break;
case LAK_CHILD_START:
case LAK_CHILD_DESTROY:
+ case LAK_CHILD_FAIL:
{
snprintf(head, sizeof(head), "op=%s %s connstate=%lu, satype=%s samode=%s",
- op == LAK_CHILD_START ? "start" : "destroy",
+ op == LAK_CHILD_DESTROY ? "destroy" : "start", /* fail to start logged under op=start */
conn_encode,
st->st_serialno,
st->st_esp.present ? "ipsec-esp" : (st->st_ah.present ? "ipsec-ah" : "ipsec-policy"),
@@ -274,7 +282,7 @@
/* note: each arg appears twice because it is printed two ways */
snprintf(spi_str, sizeof(spi_str),
- "in-spi=%" PRIu32 "(0x%08" PRIu32 ") out-spi=%" PRIu32 "(0x%08" PRIu32 ") in-ipcomp=%" PRIu32 "(0x%08" PRIu32 ") out-ipcomp=%" PRIu32 "(0x%08" PRIu32 ")",
+ "in-spi=%" PRIu32 "(0x%08" PRIu32 ") out-spi=%" PRIu32 "(0x%08" PRIu32 ") in-ipcomp=%" PRIu32 "(0x%08" PRIu32 ") out-ipcomp=%" PRIu32 "(0x%08" PRIu32 ") raddr=%s",
ntohl(pi->attrs.spi),
ntohl(pi->attrs.spi),
ntohl(pi->our_spi),
@@ -282,7 +290,8 @@
ntohl(st->st_ipcomp.attrs.spi), /* zero if missing */
ntohl(st->st_ipcomp.attrs.spi), /* zero if missing */
ntohl(st->st_ipcomp.our_spi), /* zero if missing */
- ntohl(st->st_ipcomp.our_spi)); /* zero if missing */
+ ntohl(st->st_ipcomp.our_spi), /* zero if missing */
+ raddr);
break;
}
default:
@@ -290,21 +299,18 @@
}
free(conn_encode); /* allocated by audit_encode_nv_string() */
- ip_address_buf laddr_buf;
- const char *laddr = ipstr(&c->spd.this.host_addr, &laddr_buf);
-
- ip_address_buf raddr_buf;
- const char *raddr = ipstr(&c->spd.that.host_addr, &raddr_buf);
-
- snprintf(audit_str, sizeof(audit_str), "%s %s %s laddr=%s",
+ snprintf(audit_str, sizeof(audit_str), "%s %s %s",
head,
cipher_str,
- spi_str,
- laddr);
+ spi_str);
+
+ ip_address_buf laddr_buf;
+ const char *laddr = ipstr(&c->spd.this.host_addr, &laddr_buf);
- linux_audit((op == LAK_CHILD_START || op == LAK_CHILD_DESTROY) ?
+ linux_audit((op == LAK_CHILD_START || op == LAK_CHILD_DESTROY || op == LAK_CHILD_FAIL) ?
AUDIT_CRYPTO_IPSEC_SA : AUDIT_CRYPTO_IKE_SA,
- audit_str, raddr, AUDIT_RESULT_OK);
+ audit_str, laddr,
+ (op == LAK_PARENT_FAIL || op == LAK_CHILD_FAIL) ? AUDIT_RESULT_FAIL : AUDIT_RESULT_OK);
}
#if __GNUC__ >= 7
#pragma GCC diagnostic pop
diff -Naur libreswan-3.29-orig/programs/pluto/log.h libreswan-3.29/programs/pluto/log.h
--- libreswan-3.29-orig/programs/pluto/log.h 2019-06-10 10:22:04.000000000 -0400
+++ libreswan-3.29/programs/pluto/log.h 2019-06-27 13:23:53.791080125 -0400
@@ -174,7 +174,9 @@
LAK_PARENT_START,
LAK_CHILD_START,
LAK_PARENT_DESTROY,
- LAK_CHILD_DESTROY
+ LAK_CHILD_DESTROY,
+ LAK_PARENT_FAIL,
+ LAK_CHILD_FAIL
};
extern void linux_audit_init(void);
extern void linux_audit(const int type, const char *message,
diff -Naur libreswan-3.29-orig/programs/pluto/retry.c libreswan-3.29/programs/pluto/retry.c
--- libreswan-3.29-orig/programs/pluto/retry.c 2019-06-10 10:22:04.000000000 -0400
+++ libreswan-3.29/programs/pluto/retry.c 2019-06-27 13:25:27.536367032 -0400
@@ -123,6 +123,10 @@
set_cur_state(st); /* ipsecdoi_replace would reset cur_state, set it again */
pstat_sa_failed(st, REASON_TOO_MANY_RETRANSMITS);
+
+ /* placed here because IKEv1 doesn't do a proper state change to STF_FAIL/STF_FATAL */
+ linux_audit_conn(st, IS_IKE_SA(st) ? LAK_PARENT_FAIL : LAK_CHILD_FAIL);
+
delete_state(st);
/* note: no md->st to clear */
}
diff -Naur libreswan-3.29-orig/programs/pluto/state.c libreswan-3.29/programs/pluto/state.c
--- libreswan-3.29-orig/programs/pluto/state.c 2019-06-10 10:22:04.000000000 -0400
+++ libreswan-3.29/programs/pluto/state.c 2019-06-27 13:23:53.792080138 -0400
@@ -875,6 +875,16 @@
#ifdef USE_LINUX_AUDIT
/*
+ * IKEv2 IKE failures are logged in the state transition conpletion.
+ * IKEv1 IKE failures do not go through a transition, so we catch
+ * these in delete_state()
+ */
+ if (IS_IKE_SA(st) && st->st_ike_version == IKEv1 &&
+ !IS_IKE_SA_ESTABLISHED(st)) {
+ linux_audit_conn(st, LAK_PARENT_FAIL);
+ }
+
+ /*
* only log parent state deletes, we log children in
* ipsec_delete_sa()
*/