Beispiel #1
0
/**
 * Run this function on every resource (file, class, var etc) access to
 * grant/deny rights. Currently it checks if:
 *  1. #ipaddr matches the subnet expression in {admit,deny}_ips
 *  2. #hostname matches the subdomain expression in {admit,deny}_hostnames
 *  3. #key is found exactly as it is in {admit,deny}_keys
 *
 * @return Default is false, i.e. deny. If a match is found in #acl->admit.*
 *         then return true, unless a match is also found in #acl->deny.* in
 *         which case return false.
 *
 * @TODO preprocess our global ACL the moment a client connects, and store in
 *       ServerConnectionState a list of objects that he can access. That way
 *       only his relevant resources will be stored in e.g. {admit,deny}_paths
 *       lists, and running through these two lists on every file request will
 *       be much faster.
 */
bool access_CheckResource(const struct resource_acl *acl,
                          const char *ipaddr, const char *hostname,
                          const char *key)
{
    /* Only hostname may be NULL in case of resolution failure. */
    assert(ipaddr != NULL);
    assert(key != NULL);

    size_t pos = (size_t) -1;
    bool access = false;                                 /* DENY by default */

    /* First we check for admission, secondly for denial, so that denial takes
     * precedence. */

    const char *rule;
    if (acl->admit.ips)
    {
        /* Still using legacy code here, doing linear search over all IPs in
         * textual representation... too CPU intensive! TODO store the ACL as
         * one list of struct sockaddr_storage, together with CIDR notation
         * subnet length.
         */

        bool found_rule = false;
        for (int i = 0; i < StrList_Len(acl->admit.ips); i++)
        {
            if (FuzzySetMatch(StrList_At(acl->admit.ips, i),
                              MapAddress(ipaddr))
                == 0 ||
                /* Legacy regex matching, TODO DEPRECATE */
                StringMatchFull(StrList_At(acl->admit.ips, i),
                                MapAddress(ipaddr)))
            {
                found_rule = true;
                rule = StrList_At(acl->admit.ips, i);
                break;
            }
        }

        if (found_rule)
        {
            Log(LOG_LEVEL_DEBUG, "access_Check: admit IP: %s", rule);
            access = true;
        }
    }
    if (!access && acl->admit.keys != NULL)
    {
        bool ret = StrList_BinarySearch(acl->admit.keys, key, &pos);
        if (ret)
        {
            rule = acl->admit.keys->list[pos]->str;
            Log(LOG_LEVEL_DEBUG, "access_Check: admit key: %s", rule);
            access = true;
        }
    }
    if (!access && acl->admit.hostnames != NULL && hostname != NULL)
    {
        size_t hostname_len = strlen(hostname);
        size_t pos = StrList_SearchForPrefix(acl->admit.hostnames,
                                             hostname, hostname_len,
                                             false);

        /* === Legacy regex matching, slow, TODO DEPRECATE === */
        bool regex_match = false;
        if (pos == (size_t) -1)
        {
            for (int i = 0; i < StrList_Len(acl->admit.hostnames); i++)
            {
                if (StringMatchFull(StrList_At(acl->admit.hostnames, i),
                                    hostname))
                {
                    pos = i;
                    break;
                }
            }
        }
        /* ===   === */

        if (pos != (size_t) -1)
        {
            rule            = acl->admit.hostnames->list[pos]->str;
            size_t rule_len = acl->admit.hostnames->list[pos]->len;
            /* The rule in the access list has to be an exact match, or be a
             * subdomain match (i.e. the rule begins with '.') or a regex. */
            if (rule_len == hostname_len || rule[0] == '.' || regex_match)
            {
                Log(LOG_LEVEL_DEBUG, "access_Check: admit hostname: %s", rule);
                access = true;
            }
        }
    }

    /* If access has been granted, we might need to deny it based on ACL. */

    if (access && acl->deny.ips != NULL)
    {
        bool found_rule = false;
        for (int i = 0; i < StrList_Len(acl->deny.ips); i++)
        {
            if (FuzzySetMatch(StrList_At(acl->deny.ips, i),
                              MapAddress(ipaddr))
                == 0 ||
                /* Legacy regex matching, TODO DEPRECATE */
                StringMatchFull(StrList_At(acl->deny.ips, i),
                                MapAddress(ipaddr)))
            {
                found_rule = true;
                rule = acl->deny.ips->list[i]->str;
                break;
            }
        }

        if (found_rule)
        {
            Log(LOG_LEVEL_DEBUG, "access_Check: deny IP: %s", rule);
            access = false;
        }
    }
    if (access && acl->deny.keys != NULL)
    {
        bool ret = StrList_BinarySearch(acl->deny.keys, key, &pos);
        if (ret)
        {
            rule = StrList_At(acl->deny.keys, pos);
            Log(LOG_LEVEL_DEBUG, "access_Check: deny key: %s", rule);
            access = false;
        }
    }
    if (access && acl->deny.hostnames != NULL && hostname != NULL)
    {
        size_t hostname_len = strlen(hostname);
        size_t pos = StrList_SearchForPrefix(acl->deny.hostnames,
                                             hostname, hostname_len,
                                             false);
        /* === Legacy regex matching, slow, TODO DEPRECATE === */
        bool regex_match = false;
        if (pos == (size_t) -1)
        {
            for (int i = 0; i < StrList_Len(acl->deny.hostnames); i++)
            {
                if (StringMatchFull(StrList_At(acl->deny.hostnames, i),
                                    hostname))
                {
                    pos = i;
                    break;
                }
            }
        }
        /* ===   === */

        if (pos != (size_t) -1)
        {
            rule            = acl->deny.hostnames->list[pos]->str;
            size_t rule_len = acl->deny.hostnames->list[pos]->len;
            /* The rule in the access list has to be an exact match, or be a
             * subdomain match (i.e. the rule begins with '.') or a regex. */
            if (rule_len == hostname_len || rule[0] == '.' || regex_match)
            {
                Log(LOG_LEVEL_DEBUG, "access_Check: deny hostname: %s", rule);
                access = false;
            }
        }
    }

    return access;
}
Beispiel #2
0
static void test_StrList_SearchForSuffix()
{
    /* REMINDER: HOSTNAME_STRINGS[] =
       {  "*", ".*", ".", "com", "cfengine.com", ".allowed.cfengine.com", "www.cfengine.com", ".no" }; */

    size_t ret, ret2, ret3, ret4, ret5, ret6, ret7, ret8, ret9, ret10, ret11;

    ret  = StrList_SearchForPrefix(HOSTNAME_SL, "cfengine.com", 0, false);
    ret2 = StrList_SearchForPrefix(HOSTNAME_SL, "google.com", 0, false);
    ret3 = StrList_SearchForPrefix(HOSTNAME_SL, "yr.no", 0, false);
    ret4 = StrList_SearchForPrefix(HOSTNAME_SL, "ntua.gr", 0, false);
    ret5 = StrList_SearchForPrefix(HOSTNAME_SL, "disallowed.cfengine.com", 0, false);
    ret6 = StrList_SearchForPrefix(HOSTNAME_SL, "allowed.cfengine.com", 0, false);
    ret7 = StrList_SearchForPrefix(HOSTNAME_SL, "blah.allowed.cfengine.com", 0, false);
    ret8 = StrList_SearchForPrefix(HOSTNAME_SL, "www.cfengine.com", 0, false);
    ret9 = StrList_SearchForPrefix(HOSTNAME_SL, "www1.cfengine.com", 0, false);
    ret10 = StrList_SearchForPrefix(HOSTNAME_SL, "1www.cfengine.com", 0, false);
    ret11 = StrList_SearchForPrefix(HOSTNAME_SL, "no", 0, false);

    /* SearchForPrefix() does not guarantee which one of all the matches it
     * will return if there are many matches. */

    /* E.g. the first search might return "cfengine.com" or "com" entry. */
    LargestIntegralType set[] = {3, 4};
    assert_in_set(ret, set, 2);
    assert_string_equal(StrList_At(HOSTNAME_SL, ret2),  "com");
    assert_string_equal(StrList_At(HOSTNAME_SL, ret3),  ".no");
    assert_int_equal(ret4,  (size_t) -1);
    assert_in_set(ret5, set, 2);
    assert_in_set(ret6, set, 2);
    LargestIntegralType set2[] = {3, 4, 5};
    assert_in_set(ret7, set2, 3);
    assert_in_set(ret8, set, 2);
    assert_in_set(ret9, set, 2);
    LargestIntegralType set3[] = {3, 4, 6};
    assert_in_set(ret10, set3, 3);
    assert_int_equal(ret11, (size_t) -1);
}