/** Optional interface ID */
uint32_t if_id;
+ /** Optional security label */
+ sec_label_t *label;
+
/** Associated route installed for this policy */
route_entry_t *route;
policy->direction, this);
policy->used_by->destroy(policy->used_by);
}
+ DESTROY_IF(policy->label);
free(policy);
}
static u_int policy_hash(policy_entry_t *key)
{
chunk_t chunk = chunk_from_thing(key->sel);
- return chunk_hash_inc(chunk, chunk_hash_inc(chunk_from_thing(key->mark),
+ u_int hash;
+
+ hash = chunk_hash_inc(chunk, chunk_hash_inc(chunk_from_thing(key->mark),
chunk_hash(chunk_from_thing(key->if_id))));
+ if (key->label)
+ {
+ hash = key->label->hash(key->label, hash);
+ }
+ return hash;
}
/**
return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) &&
key->mark == other_key->mark &&
key->if_id == other_key->if_id &&
- key->direction == other_key->direction;
+ key->direction == other_key->direction &&
+ sec_labels_equal(key->label, other_key->label);
}
/**
return TRUE;
}
+/**
+ * Format the security label for debug messages
+ */
+static void format_label(char *buf, int buflen, sec_label_t *label)
+{
+ if (label)
+ {
+ snprintf(buf, buflen, " (ctx %s)", label->get_string(label));
+ }
+}
+
+/**
+ * Add a security label to message if required
+ */
+static bool add_label(struct nlmsghdr *hdr, int buflen, sec_label_t *label)
+{
+ if (label)
+ {
+#ifdef USE_SELINUX
+ struct xfrm_user_sec_ctx *ctx;
+ chunk_t enc = label->get_encoding(label);
+ int len = sizeof(*ctx) + enc.len;
+
+ ctx = netlink_reserve(hdr, buflen, XFRMA_SEC_CTX, len);
+ if (!ctx)
+ {
+ return FALSE;
+ }
+ /* this attribute for some reason duplicates the generic header */
+ ctx->exttype = XFRMA_SEC_CTX;
+ ctx->len = len;
+
+ ctx->ctx_doi = XFRM_SC_DOI_LSM;
+ ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
+ ctx->ctx_len = enc.len;
+ memcpy((void*)(ctx + 1), enc.ptr, enc.len);
+#endif
+ }
+ return TRUE;
+}
+
/**
* Add a uint32 attribute to message
*/
goto failed;
}
+ if (!add_label(hdr, sizeof(request), data->label))
+ {
+ goto failed;
+ }
+
if (ipcomp == IPCOMP_NONE && (data->mark.value | data->mark.mask))
{
if (!add_uint32(hdr, sizeof(request), XFRMA_SET_MARK,
}
tmpl->reqid = ipsec->cfg.reqid;
tmpl->id.proto = protos[i].proto;
- if (policy->direction == POLICY_OUT)
+ /* in order to match SAs with all matching labels, we can't have the
+ * SPI in the template */
+ if (policy->direction == POLICY_OUT && !policy->label)
{
tmpl->id.spi = protos[i].spi;
}
policy_change_done(this, policy);
return FAILED;
}
+ if (!add_label(hdr, sizeof(request), policy->label))
+ {
+ policy_change_done(this, policy);
+ return FAILED;
+ }
this->mutex->unlock(this->mutex);
status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
policy_sa_t *assigned_sa, *current_sa;
enumerator_t *enumerator;
bool found = FALSE, update = TRUE;
- char markstr[32] = "";
+ char markstr[32] = "", labelstr[128] = "";
uint32_t cur_priority = 0;
int use_count;
.sel = ts2selector(id->src_ts, id->dst_ts, id->interface),
.mark = id->mark.value & id->mark.mask,
.if_id = id->if_id,
+ .label = id->label ? id->label->clone(id->label) : NULL,
.direction = id->dir,
.reqid = data->sa->reqid,
);
format_mark(markstr, sizeof(markstr), id->mark);
+ format_label(labelstr, sizeof(labelstr), id->label);
/* find the policy, which matches EXACTLY */
this->mutex->lock(this->mutex);
if (current->reqid && data->sa->reqid &&
current->reqid != data->sa->reqid)
{
- DBG1(DBG_CFG, "unable to install policy %R === %R %N%s for reqid "
+ DBG1(DBG_CFG, "unable to install policy %R === %R %N%s%s for reqid "
"%u, the same policy for reqid %u exists",
id->src_ts, id->dst_ts, policy_dir_names, id->dir, markstr,
- data->sa->reqid, current->reqid);
+ labelstr, data->sa->reqid, current->reqid);
policy_entry_destroy(this, policy);
this->mutex->unlock(this->mutex);
return INVALID_STATE;
}
/* use existing policy */
- DBG2(DBG_KNL, "policy %R === %R %N%s already exists, increasing "
+ DBG2(DBG_KNL, "policy %R === %R %N%s%s already exists, increasing "
"refcount", id->src_ts, id->dst_ts, policy_dir_names, id->dir,
- markstr);
+ markstr, labelstr);
policy_entry_destroy(this, policy);
policy = current;
found = TRUE;
{ /* we don't update the policy if the priority is lower than that of
* the currently installed one */
policy_change_done(this, policy);
- DBG2(DBG_KNL, "not updating policy %R === %R %N%s [priority %u, "
+ DBG2(DBG_KNL, "not updating policy %R === %R %N%s%s [priority %u, "
"refcount %d]", id->src_ts, id->dst_ts, policy_dir_names,
- id->dir, markstr, cur_priority, use_count);
+ id->dir, markstr, labelstr, cur_priority, use_count);
return SUCCESS;
}
policy->reqid = assigned_sa->sa->cfg.reqid;
found = TRUE;
}
- DBG2(DBG_KNL, "%s policy %R === %R %N%s [priority %u, refcount %d]",
+ DBG2(DBG_KNL, "%s policy %R === %R %N%s%s [priority %u, refcount %d]",
found ? "updating" : "adding", id->src_ts, id->dst_ts,
- policy_dir_names, id->dir, markstr, assigned_sa->priority, use_count);
+ policy_dir_names, id->dir, markstr, labelstr, assigned_sa->priority,
+ use_count);
if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to %s policy %R === %R %N%s",
+ DBG1(DBG_KNL, "unable to %s policy %R === %R %N%s%s",
found ? "update" : "add", id->src_ts, id->dst_ts,
- policy_dir_names, id->dir, markstr);
+ policy_dir_names, id->dir, markstr, labelstr);
return FAILED;
}
return SUCCESS;
struct xfrm_userpolicy_id *policy_id;
struct xfrm_userpolicy_info *policy = NULL;
size_t len;
- char markstr[32] = "";
+ char markstr[32] = "", labelstr[128] = "";
memset(&request, 0, sizeof(request));
format_mark(markstr, sizeof(markstr), id->mark);
+ format_label(labelstr, sizeof(labelstr), id->label);
- DBG2(DBG_KNL, "querying policy %R === %R %N%s", id->src_ts, id->dst_ts,
- policy_dir_names, id->dir, markstr);
+ DBG2(DBG_KNL, "querying policy %R === %R %N%s%s", id->src_ts, id->dst_ts,
+ policy_dir_names, id->dir, markstr, labelstr);
hdr = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST;
{
return FAILED;
}
+ if (!add_label(hdr, sizeof(request), id->label))
+ {
+ return FAILED;
+ }
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
.if_id = id->if_id,
.cfg = *data->sa,
};
- char markstr[32] = "";
+ char markstr[32] = "", labelstr[128] = "";
int use_count;
status_t status = SUCCESS;
format_mark(markstr, sizeof(markstr), id->mark);
+ format_label(labelstr, sizeof(labelstr), id->label);
- DBG2(DBG_KNL, "deleting policy %R === %R %N%s", id->src_ts, id->dst_ts,
- policy_dir_names, id->dir, markstr);
+ DBG2(DBG_KNL, "deleting policy %R === %R %N%s%s", id->src_ts, id->dst_ts,
+ policy_dir_names, id->dir, markstr, labelstr);
/* create a policy */
memset(&policy, 0, sizeof(policy_entry_t));
policy.sel = ts2selector(id->src_ts, id->dst_ts, id->interface);
policy.mark = id->mark.value & id->mark.mask;
policy.if_id = id->if_id;
+ policy.label = id->label;
policy.direction = id->dir;
/* find the policy */
current = this->policies->get(this->policies, &policy);
if (!current)
{
- DBG1(DBG_KNL, "deleting policy %R === %R %N%s failed, not found",
- id->src_ts, id->dst_ts, policy_dir_names, id->dir, markstr);
+ DBG1(DBG_KNL, "deleting policy %R === %R %N%s%s failed, not found",
+ id->src_ts, id->dst_ts, policy_dir_names, id->dir, markstr,
+ labelstr);
this->mutex->unlock(this->mutex);
return NOT_FOUND;
}
current->waiting--;
/* remove mapping to SA by reqid and priority */
- auto_priority = get_priority(current, data->prio,id->interface);
+ auto_priority = get_priority(current, data->prio, id->interface);
priority = this->get_priority ? this->get_priority(id, data)
: data->manual_prio;
priority = priority ?: auto_priority;
if (!is_installed)
{ /* no need to update as the policy was not installed for this SA */
policy_change_done(this, current);
- DBG2(DBG_KNL, "not updating policy %R === %R %N%s [priority %u, "
+ DBG2(DBG_KNL, "not updating policy %R === %R %N%s%s [priority %u, "
"refcount %d]", id->src_ts, id->dst_ts, policy_dir_names,
- id->dir, markstr, cur_priority, use_count);
+ id->dir, markstr, labelstr, cur_priority, use_count);
return SUCCESS;
}
current->used_by->get_first(current->used_by, (void**)&mapping);
current->reqid = mapping->sa->cfg.reqid;
- DBG2(DBG_KNL, "updating policy %R === %R %N%s [priority %u, "
+ DBG2(DBG_KNL, "updating policy %R === %R %N%s%s [priority %u, "
"refcount %d]", id->src_ts, id->dst_ts, policy_dir_names, id->dir,
- markstr, mapping->priority, use_count);
+ markstr, labelstr, mapping->priority, use_count);
if (add_policy_internal(this, current, mapping, TRUE) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to update policy %R === %R %N%s",
- id->src_ts, id->dst_ts, policy_dir_names, id->dir, markstr);
+ DBG1(DBG_KNL, "unable to update policy %R === %R %N%s%s",
+ id->src_ts, id->dst_ts, policy_dir_names, id->dir, markstr,
+ labelstr);
return FAILED;
}
return SUCCESS;
policy_change_done(this, current);
return FAILED;
}
+ if (!add_label(hdr, sizeof(request), id->label))
+ {
+ policy_change_done(this, current);
+ return FAILED;
+ }
if (current->route)
{
route->pass) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with policy "
- "%R === %R %N%s", id->src_ts, id->dst_ts, policy_dir_names,
- id->dir, markstr);
+ "%R === %R %N%s%s", id->src_ts, id->dst_ts, policy_dir_names,
+ id->dir, markstr, labelstr);
}
}
this->mutex->unlock(this->mutex);
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to delete policy %R === %R %N%s", id->src_ts,
- id->dst_ts, policy_dir_names, id->dir, markstr);
+ DBG1(DBG_KNL, "unable to delete policy %R === %R %N%s%s", id->src_ts,
+ id->dst_ts, policy_dir_names, id->dir, markstr, labelstr);
status = FAILED;
}