]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
child-cfg: Add method to select a security label
authorTobias Brunner <tobias@strongswan.org>
Tue, 11 Jan 2022 09:15:53 +0000 (10:15 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 14 Apr 2022 16:42:01 +0000 (18:42 +0200)
src/libcharon/config/child_cfg.c
src/libcharon/config/child_cfg.h

index 92a1ed502731e0a13679d7c03281935103d25276..862ec69ea2a99d8bf4c415642091eee25e75d1e7 100644 (file)
@@ -544,6 +544,85 @@ METHOD(child_cfg_t, get_label_mode, sec_label_mode_t,
        return this->label_mode;
 }
 
+METHOD(child_cfg_t, select_label, bool,
+       private_child_cfg_t *this, linked_list_t *labels, bool log,
+       sec_label_t **label, bool *exact_out)
+{
+       enumerator_t *enumerator;
+       sec_label_t *current, *match = NULL;
+       bool exact = FALSE;
+
+       if (labels && labels->get_count(labels))
+       {
+               if (!this->label)
+               {
+                       DBG2(DBG_CFG, "peer proposed a security label, but none expected");
+                       return FALSE;
+               }
+               if (log)
+               {
+                       DBG2(DBG_CFG, "selecting security label matching '%s':",
+                                this->label->get_string(this->label));
+               }
+               enumerator = labels->create_enumerator(labels);
+               while (enumerator->enumerate(enumerator, &current))
+               {
+                       if (this->label->equals(this->label, current))
+                       {
+                               if (log)
+                               {
+                                       DBG2(DBG_CFG, " %s => matches exactly",
+                                                current->get_string(current));
+                               }
+                               match = current;
+                               exact = TRUE;
+                               break;
+                       }
+                       else if (this->label_mode == SEC_LABEL_MODE_SELINUX &&
+                                        this->label->matches(this->label, current))
+                       {
+                               if (log)
+                               {
+                                       DBG2(DBG_CFG, " %s => matches%s",
+                                                current->get_string(current), match ? ", ignored" : "");
+                               }
+                               /* return the first match if we don't find an exact one */
+                               if (!match)
+                               {
+                                       match = current;
+                               }
+                       }
+                       else if (log)
+                       {
+                               DBG2(DBG_CFG, " %s => no match", current->get_string(current));
+                       }
+               }
+               enumerator->destroy(enumerator);
+               if (!match)
+               {
+                       DBG2(DBG_CFG, "none of the proposed security labels match the "
+                                "configured label '%s'", this->label->get_string(this->label));
+                       return FALSE;
+               }
+       }
+       else if (this->label)
+       {
+               DBG2(DBG_CFG, "peer didn't propose any security labels, we expect one "
+                        "matching '%s'", this->label->get_string(this->label));
+               return FALSE;
+       }
+
+       if (label)
+       {
+               *label = match;
+       }
+       if (exact_out)
+       {
+               *exact_out = exact;
+       }
+       return TRUE;
+}
+
 METHOD(child_cfg_t, get_tfc, uint32_t,
        private_child_cfg_t *this)
 {
@@ -686,6 +765,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
                        .get_set_mark = _get_set_mark,
                        .get_label = _get_label,
                        .get_label_mode = _get_label_mode,
+                       .select_label = _select_label,
                        .get_tfc = _get_tfc,
                        .get_manual_prio = _get_manual_prio,
                        .get_interface = _get_interface,
index 15c52b7bc98c58a192937b1e9e9896e72e24643a..710596d89b6df47c89cad163429f99718b1727bb 100644 (file)
@@ -261,6 +261,27 @@ struct child_cfg_t {
         */
        sec_label_mode_t (*get_label_mode)(child_cfg_t *this);
 
+       /**
+        * Select a security label from the given list that matches the configured
+        * label.
+        *
+        * This fails under the following conditions:
+        * - a label is configured but no labels are provided
+        * - no label is configured but at least one label is provided
+        * - the configured and provided labels don't match
+        *
+        * If no label is configured and none are provided, that's considered a
+        * success and label will be set to NULL.
+        *
+        * @param labels                list of labels to match
+        * @param log                   FALSE to avoid logging details about the selection
+        * @param label[out]    selected label or NULL if no label necessary
+        * @param exact[out]    TRUE if there was an exact match
+        * @return                              FALSE on failure
+        */
+       bool (*select_label)(child_cfg_t *this, linked_list_t *labels, bool log,
+                                                sec_label_t **label, bool *exact);
+
        /**
         * Get the TFC padding value to use for CHILD_SA.
         *