proposal_t *proposal;
/**
- * traffic selectors for initiators side
+ * traffic selectors for initiator side
*/
linked_list_t *tsi;
/**
- * traffic selectors for responders side
+ * traffic selectors for responder side
*/
linked_list_t *tsr;
+ /**
+ * labels for initiator side
+ */
+ linked_list_t *labels_i;
+
+ /**
+ * labels for responder side
+ */
+ linked_list_t *labels_r;
+
/**
* source of triggering packet
*/
task->use_reqid(task, this->child.reqid);
task->use_marks(task, this->child.mark_in, this->child.mark_out);
task->use_if_ids(task, this->child.if_id_in, this->child.if_id_out);
+ task->use_label(task, this->child.label);
DBG1(DBG_IKE, "creating CHILD_SA failed, trying again in %d seconds",
retry);
}
/* add TSi/TSr payloads */
- ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi, NULL);
+ ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi,
+ this->child.label);
message->add_payload(message, (payload_t*)ts_payload);
- ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr, NULL);
+ ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr,
+ this->child.label);
message->add_payload(message, (payload_t*)ts_payload);
/* add a notify if we are not in tunnel mode */
case PLV2_TS_INITIATOR:
ts_payload = (ts_payload_t*)payload;
this->tsi = ts_payload->get_traffic_selectors(ts_payload);
+ this->labels_i = ts_payload->get_sec_labels(ts_payload);
break;
case PLV2_TS_RESPONDER:
ts_payload = (ts_payload_t*)payload;
this->tsr = ts_payload->get_traffic_selectors(ts_payload);
+ this->labels_r = ts_payload->get_sec_labels(ts_payload);
break;
case PLV2_NOTIFY:
handle_notify(this, (notify_payload_t*)payload);
enumerator->destroy(enumerator);
}
+/**
+ * Check if we have only the generic label available when using SELinux and not
+ * a specific one from an acquire.
+ */
+static bool generic_label_only(private_child_create_t *this)
+{
+ return this->config->get_label(this->config) && !this->child.label &&
+ this->config->get_label_mode(this->config) == SEC_LABEL_MODE_SELINUX;
+}
+
/**
* Check if we should defer the creation of this CHILD_SA until after the
* IKE_SA has been established childless.
static status_t defer_child_sa(private_child_create_t *this)
{
ike_cfg_t *ike_cfg;
+ childless_t policy;
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
+ policy = ike_cfg->childless(ike_cfg);
if (this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_CHILDLESS))
{
- if (ike_cfg->childless(ike_cfg) == CHILDLESS_FORCE)
+ /* with SELinux, we prefer not to create a CHILD_SA when we only have
+ * the generic label available. if the peer does not support it,
+ * creating the SA will most likely fail */
+ if (policy == CHILDLESS_FORCE ||
+ generic_label_only(this))
{
return NEED_MORE;
}
}
- else if (ike_cfg->childless(ike_cfg) == CHILDLESS_FORCE)
+ else if (policy == CHILDLESS_FORCE)
{
DBG1(DBG_IKE, "peer does not support childless IKE_SA initiation");
return DESTROY_ME;
/**
* Check if there is a duplicate CHILD_SA already established and we can abort
- * initiating this one
+ * initiating this one.
*/
static bool check_for_duplicate(private_child_create_t *this)
{
return found;
}
+/**
+ * Check if this is an attempt to create an SA with generic label and should
+ * be aborted.
+ */
+static bool check_for_generic_label(private_child_create_t *this)
+{
+ if (generic_label_only(this))
+ {
+ sec_label_t *label;
+
+ label = this->config->get_label(this->config);
+ DBG1(DBG_IKE, "not establishing CHILD_SA %s{%d} with generic "
+ "label '%s'", this->child_sa->get_name(this->child_sa),
+ this->child_sa->get_unique_id(this->child_sa),
+ label->get_string(label));
+ return TRUE;
+ }
+ return FALSE;
+}
+
METHOD(task_t, build_i, status_t,
private_child_create_t *this, message_t *message)
{
this->tsr->insert_first(this->tsr,
this->packet_tsr->clone(this->packet_tsr));
}
+
+ if (!generic_label_only(this) && !this->child.label)
+ { /* in the simple label mode we propose the configured label as we
+ * won't have labels from acquires */
+ this->child.label = this->config->get_label(this->config);
+ if (this->child.label)
+ {
+ this->child.label = this->child.label->clone(this->child.label);
+ }
+ }
+ if (this->child.label)
+ {
+ DBG2(DBG_CFG, "proposing security label '%s'",
+ this->child.label->get_string(this->child.label));
+ }
+
this->proposals = this->config->get_proposals(this->config,
this->dh_group == MODP_NONE);
this->mode = this->config->get_mode(this->config);
* by controller and trap manager */
if (!this->rekey &&
message->get_exchange_type(message) == CREATE_CHILD_SA &&
- check_for_duplicate(this))
+ (check_for_generic_label(this) || check_for_duplicate(this)))
{
message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
return SUCCESS;
listr = get_dynamic_hosts(this->ike_sa, TRUE);
listi = get_dynamic_hosts(this->ike_sa, FALSE);
child_cfg = peer_cfg->select_child_cfg(peer_cfg,
- tsr ?: this->tsr, tsi ?: this->tsi,
- listr, listi, NULL, NULL);
+ tsr ?: this->tsr, tsi ?: this->tsi,
+ listr, listi, this->labels_r, this->labels_i);
if ((tsi || tsr) && child_cfg &&
child_cfg->get_mode(child_cfg) != MODE_TRANSPORT)
{
{
/* no match for the substituted NAT selectors, try it without */
child_cfg = peer_cfg->select_child_cfg(peer_cfg,
- this->tsr, this->tsi,
- listr, listi, NULL, NULL);
+ this->tsr, this->tsi,
+ listr, listi, this->labels_r, this->labels_i);
}
listr->destroy(listr);
listi->destroy(listi);
return NOT_SUPPORTED;
}
+/**
+ * Select a security label.
+ *
+ * We already know that the proposed labels match the selected config, just make
+ * sure that the proposed/returned labels are the same.
+ */
+static bool select_label(private_child_create_t *this)
+{
+ sec_label_t *li, *lr;
+
+ if (!this->config->select_label(this->config, this->labels_i, FALSE, &li, NULL) ||
+ !this->config->select_label(this->config, this->labels_r, FALSE, &lr, NULL))
+ { /* sanity check */
+ return FALSE;
+ }
+
+ if (li)
+ {
+ if (!li->equals(li, lr))
+ {
+ DBG1(DBG_CHD, "security labels in TSi and TSr don't match");
+ return FALSE;
+ }
+ else if (!this->child.label)
+ {
+ this->child.label = li->clone(li);
+ }
+ else if (!this->child.label->equals(this->child.label, li))
+ {
+ DBG1(DBG_CHD, "returned security label '%s' doesn't match proposed "
+ "'%s'", li->get_string(li),
+ this->child.label->get_string(this->child.label));
+ return FALSE;
+ }
+ }
+ if (this->child.label)
+ {
+ DBG1(DBG_CFG, "selected security label: %s",
+ this->child.label->get_string(this->child.label));
+ }
+ return TRUE;
+}
+
METHOD(task_t, build_r, status_t,
private_child_create_t *this, message_t *message)
{
}
enumerator->destroy(enumerator);
+ if (!select_label(this))
+ {
+ message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
+ handle_child_sa_failure(this, message);
+ return SUCCESS;
+ }
+
this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa, TRUE);
this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa, FALSE);
this->child.encap = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
return delete_failed_sa(this);
}
+ if (!select_label(this))
+ {
+ handle_child_sa_failure(this, message);
+ return delete_failed_sa(this);
+ }
+
if (select_and_install(this, no_dh, ike_auth) == SUCCESS)
{
if (!this->rekey)
this->child.if_id_out = out;
}
+METHOD(child_create_t, use_label, void,
+ private_child_create_t *this, sec_label_t *label)
+{
+ DESTROY_IF(this->child.label);
+ this->child.label = label ? label->clone(label) : NULL;
+}
+
METHOD(child_create_t, use_dh_group, void,
private_child_create_t *this, diffie_hellman_group_t dh_group)
{
{
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
}
+ if (this->labels_i)
+ {
+ this->labels_i->destroy_offset(this->labels_i, offsetof(sec_label_t, destroy));
+ }
+ if (this->labels_r)
+ {
+ this->labels_r->destroy_offset(this->labels_r, offsetof(sec_label_t, destroy));
+ }
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
DESTROY_IF(this->nonceg);
{
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
}
+ if (this->labels_i)
+ {
+ this->labels_i->destroy_offset(this->labels_i, offsetof(sec_label_t, destroy));
+ }
+ if (this->labels_r)
+ {
+ this->labels_r->destroy_offset(this->labels_r, offsetof(sec_label_t, destroy));
+ }
if (!this->established)
{
DESTROY_IF(this->child_sa);
}
DESTROY_IF(this->config);
DESTROY_IF(this->nonceg);
+ DESTROY_IF(this->child.label);
free(this);
}
.use_reqid = _use_reqid,
.use_marks = _use_marks,
.use_if_ids = _use_if_ids,
+ .use_label = _use_label,
.use_dh_group = _use_dh_group,
.task = {
.get_type = _get_type,