Пример #1
0
int IsMatchItemIn(EvalContext *ctx, Item *list, const char *item)
/* Solve for possible regex/fuzzy models unified */
{
    Item *ptr;

    if ((item == NULL) || (strlen(item) == 0))
    {
        return true;
    }

    for (ptr = list; ptr != NULL; ptr = ptr->next)
    {
        if (FuzzySetMatch(ptr->name, item) == 0)
        {
            return (true);
        }

        if (IsRegex(ptr->name))
        {
            if (FullTextMatch(ctx, ptr->name, item))
            {
                return (true);
            }
        }
    }

    return (false);
}
    void AbstractFinder::AddSql(String Col, String Pattern, std::stringstream& Sql) {
        if (Pattern.length() == 0) return;

        if (IsRegex(Pattern)) {
#ifndef WIN32
            Sql << " AND " << Col << " regexp ?";
#else
            for (int i = 0; i < Pattern.length(); i++) {
                if (Pattern.at(i) == '?') Pattern.at(i) = '_';
                else if (Pattern.at(i) == '*') Pattern.at(i) = '%';
            }
            Sql << " AND " << Col << " LIKE ?";
#endif
            Params.push_back(Pattern);
            return;
        }

        String buf;
        std::vector<String> tokens;
        std::vector<String> tokens2;
        std::stringstream ss(Pattern);
        while (ss >> buf) tokens.push_back(buf);

        if (tokens.size() == 0) {
            Sql << " AND " << Col << " LIKE ?";
            Params.push_back("%" + Pattern + "%");
            return;
        }

        bool b = false;
        for (int i = 0; i < tokens.size(); i++) {
            Sql << (i == 0 ? " AND (" : "");

            for (int j = 0; j < tokens.at(i).length(); j++) {
                if (tokens.at(i).at(j) == '+') tokens.at(i).at(j) = ' ';
            }

            ss.clear();
            ss.str("");
            ss << tokens.at(i);

            tokens2.clear();
            while (ss >> buf) tokens2.push_back(buf);

            if (b && tokens2.size() > 0) Sql << " OR ";
            if (tokens2.size() > 1) Sql << "(";
            for (int j = 0; j < tokens2.size(); j++) {
                if (j != 0) Sql << " AND ";
                Sql << Col << " LIKE ?";
                Params.push_back("%" + tokens2.at(j) + "%");
                b = true;
            }
            if (tokens2.size() > 1) Sql << ")";
        }
        if (!b) Sql << "0)";
        else Sql << ")";
    }
Пример #3
0
int IsPathRegex(char *str)
{
    char *sp;
    int result = false, s = 0, r = 0;

    if ((result = IsRegex(str)))
    {
        for (sp = str; *sp != '\0'; sp++)
        {
            switch (*sp)
            {
            case '[':
                s++;
                break;
            case ']':
                s--;
                if (s % 2 == 0)
                {
                    result++;
                }
                break;
            case '(':
                r++;
                break;
            case ')':
                r--;
                if (r % 2 == 0)
                {
                    result++;
                }
                break;
            default:

                if ((*sp == FILE_SEPARATOR) && (r || s))
                {
                    Log(LOG_LEVEL_ERR,
                          "Path regular expression %s seems to use expressions containing the directory symbol %c", str,
                          FILE_SEPARATOR);
                    Log(LOG_LEVEL_ERR, "Use a work-around to avoid pathological behaviour");
                    return false;
                }
                break;
            }
        }
    }

    return result;
}
Пример #4
0
int IsMatchItemIn(const Item *list, const char *item)
/* Solve for possible regex/fuzzy models unified */
{
    if (item == NULL || item[0] == '\0')
    {
        return true;
    }

    const Item *ptr = list;
    CYCLE_DECLARE(ptr, slow, toggle);
    while (ptr != NULL)
    {
        if (FuzzySetMatch(ptr->name, item) == 0 ||
            (IsRegex(ptr->name) &&
             StringMatchFull(ptr->name, item)))
        {
            return true;
        }
        ptr = ptr->next;
        CYCLE_CHECK(ptr, slow, toggle);
    }

    return false;
}
Пример #5
0
/* Map old-style regex-or-hostname to new-style host-or-domain.
 *
 * Old-style ACLs could include regexes to be matched against host
 * names; but new-style ones only support sub-domain matching.  If the
 * old-style host regex looks like ".*\.sub\.domain\.tld" we can take
 * it in as ".sub.domain.tld"; otherwise, we can only really map exact
 * match hostnames.  However, we know some old policy (including our
 * own masterfiles) had cases of .*sub.domain.tld and it's possible
 * that someone might include a new-style .sub.domain.tld by mistake
 * in an (old-style) accept list; so cope with these cases, too.
 *
 * @param sl The string-list to which to add entries.
 * @param host The name-or-regex to add to the ACL.
 * @return An index at which an entry was added to the list (there may
 * be another), or -1 if nothing added.
 */
static size_t DeRegexify(StrList **sl, const char *host)
{
    if (IsRegex(host))
    {
        if (host[strcspn(host, "({[|+?]})")] != '\0')
        {
            return -1; /* Not a regex we can sensibly massage; discard. */
        }
        bool skip[2] = { false, false }; /* { domain, host } passes below */
        const char *name = host;
        if (name[0] == '^') /* Was always implicit; but read as hint to intent. */
        {
            /* Default to skipping domain-form if anchored explicitly: */
            skip[0] = true; /* Over-ridden below if followed by .* of course. */
            name++;
        }
        if (StringStartsWith(name, ".*"))
        {
            skip[0] = false; /* Domain-form should match */
            name += 2;
        }
        if (StringStartsWith(name, "\\."))
        {
            /* Skip host-form, as the regex definitely wants something
             * before the given name. */
            skip[1] = true;
            name += 2;
        }
        if (strchr(name, '*') != NULL)
        {
            /* Can't handle a * later than the preamble. */
            return (size_t) -1;
        }

        if (name > host || NULL != strchr(host, '\\'))
        {
            /* 2: leading '.' and final '\0' */
            char copy[2 + strlen(name)], *c = copy;
            c++[0] = '.'; /* For domain-form; and copy+1 gives host-form. */
            /* Now copy the rest of the name, de-regex-ifying as we go: */
            for (const char *p = name; p[0] != '\0'; p++)
            {
                if (p[0] == '\\')
                {
                    p++;
                    if (p[0] != '.')
                    {
                        /* Regex includes a non-dot escape */
                        return (size_t) -1;
                    }
                }
#if 0
                else if (p[0] == '.')
                {
                    /* In principle, this is a special character; but
                     * it may just be an unescaped dot, so let it be. */
                }
#endif
                c++[0] = p[0];
            }
            assert(c < copy + sizeof(copy));
            c[0] = '\0';

            /* Now, for host then domain, add entry if suitable */
            int pass = 2;
            size_t ret = -1;
            while (pass > 0)
            {
                pass--;
                if (!skip[pass]) /* pass 0 is domain, pass 1 is host */
                {
                    ret = StrList_Append(sl, copy + pass);
                }
            }
            return ret;
        }
        /* IsRegex() but is actually so boring it's just a name ! */
    }
    /* Just a simple host name. */

    return StrList_Append(sl, host);
}
Пример #6
0
void LocateFilePromiserGroup(EvalContext *ctx, char *wildpath, Promise *pp, void (*fnptr) (EvalContext *ctx, char *path, Promise *ptr))
{
    Item *path, *ip, *remainder = NULL;
    char pbuffer[CF_BUFSIZE];
    struct stat statbuf;
    int count = 0, lastnode = false, expandregex = false;
    uid_t agentuid = getuid();
    int create = PromiseGetConstraintAsBoolean(ctx, "create", pp);
    char *pathtype = ConstraintGetRvalValue(ctx, "pathtype", pp, RVAL_TYPE_SCALAR);

/* Do a search for promiser objects matching wildpath */

    if ((!IsPathRegex(wildpath)) || (pathtype && (strcmp(pathtype, "literal") == 0)))
    {
        Log(LOG_LEVEL_VERBOSE, "Using literal pathtype for '%s'", wildpath);
        (*fnptr) (ctx, wildpath, pp);
        return;
    }
    else
    {
        Log(LOG_LEVEL_VERBOSE, "Using regex pathtype for '%s' (see pathtype)", wildpath);
    }

    pbuffer[0] = '\0';
    path = SplitString(wildpath, '/');  // require forward slash in regex on all platforms

    for (ip = path; ip != NULL; ip = ip->next)
    {
        if ((ip->name == NULL) || (strlen(ip->name) == 0))
        {
            continue;
        }

        if (ip->next == NULL)
        {
            lastnode = true;
        }

        /* No need to chdir as in recursive descent, since we know about the path here */

        if (IsRegex(ip->name))
        {
            remainder = ip->next;
            expandregex = true;
            break;
        }
        else
        {
            expandregex = false;
        }

        if (!JoinPath(pbuffer, ip->name))
        {
            Log(LOG_LEVEL_ERR, "Buffer has limited size in LocateFilePromiserGroup");
            return;
        }

        if (stat(pbuffer, &statbuf) != -1)
        {
            if ((S_ISDIR(statbuf.st_mode)) && ((statbuf.st_uid) != agentuid) && ((statbuf.st_uid) != 0))
            {
                Log(LOG_LEVEL_INFO,
                    "Directory '%s' in search path '%s' is controlled by another user (uid %ju) - trusting its content is potentially risky (possible race condition)",
                      pbuffer, wildpath, (uintmax_t)statbuf.st_uid);
                PromiseRef(LOG_LEVEL_INFO, pp);
            }
        }
    }

    if (expandregex)            /* Expand one regex link and hand down */
    {
        char nextbuffer[CF_BUFSIZE], nextbufferOrig[CF_BUFSIZE], regex[CF_BUFSIZE];
        const struct dirent *dirp;
        Dir *dirh;

        memset(regex, 0, CF_BUFSIZE);

        strncpy(regex, ip->name, CF_BUFSIZE - 1);

        if ((dirh = DirOpen(pbuffer)) == NULL)
        {
            // Could be a dummy directory to be created so this is not an error.
            Log(LOG_LEVEL_VERBOSE, "Using best-effort expanded (but non-existent) file base path '%s'", wildpath);
            (*fnptr) (ctx, wildpath, pp);
            DeleteItemList(path);
            return;
        }
        else
        {
            count = 0;

            for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh))
            {
                if (!ConsiderLocalFile(dirp->d_name, pbuffer))
                {
                    continue;
                }

                if ((!lastnode) && (!S_ISDIR(statbuf.st_mode)))
                {
                    Log(LOG_LEVEL_DEBUG, "Skipping non-directory '%s'", dirp->d_name);
                    continue;
                }

                if (FullTextMatch(regex, dirp->d_name))
                {
                    Log(LOG_LEVEL_DEBUG, "Link '%s' matched regex '%s'", dirp->d_name, regex);
                }
                else
                {
                    continue;
                }

                count++;

                strncpy(nextbuffer, pbuffer, CF_BUFSIZE - 1);
                AddSlash(nextbuffer);
                strcat(nextbuffer, dirp->d_name);

                for (ip = remainder; ip != NULL; ip = ip->next)
                {
                    AddSlash(nextbuffer);
                    strcat(nextbuffer, ip->name);
                }

                /* The next level might still contain regexs, so go again as long as expansion is not nullpotent */

                if ((!lastnode) && (strcmp(nextbuffer, wildpath) != 0))
                {
                    LocateFilePromiserGroup(ctx, nextbuffer, pp, fnptr);
                }
                else
                {
                    Promise *pcopy;

                    Log(LOG_LEVEL_VERBOSE, "Using expanded file base path '%s'", nextbuffer);

                    /* Now need to recompute any back references to get the complete path */

                    snprintf(nextbufferOrig, sizeof(nextbufferOrig), "%s", nextbuffer);
                    MapNameForward(nextbuffer);

                    if (!FullTextMatch(pp->promiser, nextbuffer))
                    {
                        Log(LOG_LEVEL_DEBUG, "Error recomputing references for '%s' in '%s'", pp->promiser, nextbuffer);
                    }

                    /* If there were back references there could still be match.x vars to expand */

                    pcopy = ExpandDeRefPromise(ctx, ScopeGetCurrent()->scope, pp);
                    (*fnptr) (ctx, nextbufferOrig, pcopy);
                    PromiseDestroy(pcopy);
                }
            }

            DirClose(dirh);
        }
    }
    else
    {
        Log(LOG_LEVEL_VERBOSE, "Using file base path '%s'", pbuffer);
        (*fnptr) (ctx, pbuffer, pp);
    }

    if (count == 0)
    {
        Log(LOG_LEVEL_VERBOSE, "No promiser file objects matched as regular expression '%s'", wildpath);

        if (create)
        {
            (*fnptr)(ctx, pp->promiser, pp);
        }
    }

    DeleteItemList(path);
}