Esempio n. 1
0
int     match_string(MATCH_LIST *list, const char *string, const char *pattern)
{
    const char *myname = "match_string";
    DICT   *dict;

    if (msg_verbose)
	msg_info("%s: %s ~? %s", myname, string, pattern);

    /*
     * Try dictionary lookup: exact match.
     */
    if (MATCH_DICTIONARY(pattern)) {
	if ((dict = dict_handle(pattern)) == 0)
	    msg_panic("%s: unknown dictionary: %s", myname, pattern);
	if (dict_get(dict, string) != 0)
	    return (1);
	if ((list->error = dict->error) != 0)
	    return (match_error(list, "%s:%s: table lookup problem",
				dict->type, dict->name));
	return (0);
    }

    /*
     * Try an exact string match.
     */
    if (strcasecmp(string, pattern) == 0) {
	return (1);
    }

    /*
     * No match found.
     */
    return (0);
}
Esempio n. 2
0
static ARGV *match_list_parse(ARGV *list, char *string, int init_match)
{
    const char *myname = "match_list_parse";
    VSTRING *buf = vstring_alloc(10);
    VSTREAM *fp;
    const char *delim = " ,\t\r\n";
    char   *bp = string;
    char   *start;
    char   *item;
    char   *map_type_name_flags;
    int     match;

#define OPEN_FLAGS	O_RDONLY
#define DICT_FLAGS	(DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX)
#define STR(x)		vstring_str(x)

    /*
     * /filename contents are expanded in-line. To support !/filename we
     * prepend the negation operator to each item from the file.
     */
    while ((start = mystrtokq(&bp, delim, "{}")) != 0) {
	if (*start == '#') {
	    msg_warn("%s: comment at end of line is not supported: %s %s",
		     myname, start, bp);
	    break;
	}
	for (match = init_match, item = start; *item == '!'; item++)
	    match = !match;
	if (*item == 0)
	    msg_fatal("%s: no pattern after '!'", myname);
	if (*item == '/') {			/* /file/name */
	    if ((fp = vstream_fopen(item, O_RDONLY, 0)) == 0) {
		vstring_sprintf(buf, "%s:%s", DICT_TYPE_NOFILE, item);
		/* XXX Should increment existing map refcount. */
		if (dict_handle(STR(buf)) == 0)
		    dict_register(STR(buf),
				  dict_surrogate(DICT_TYPE_NOFILE, item,
						 OPEN_FLAGS, DICT_FLAGS,
						 "open file %s: %m", item));
		argv_add(list, STR(buf), (char *) 0);
	    } else {
		while (vstring_fgets(buf, fp))
		    if (vstring_str(buf)[0] != '#')
			list = match_list_parse(list, vstring_str(buf), match);
		if (vstream_fclose(fp))
		    msg_fatal("%s: read file %s: %m", myname, item);
	    }
	} else if (MATCH_DICTIONARY(item)) {	/* type:table */
	    vstring_sprintf(buf, "%s%s(%o,%s)", match ? "" : "!",
			    item, OPEN_FLAGS, dict_flags_str(DICT_FLAGS));
	    map_type_name_flags = STR(buf) + (match == 0);
	    /* XXX Should increment existing map refcount. */
	    if (dict_handle(map_type_name_flags) == 0)
		dict_register(map_type_name_flags,
			      dict_open(item, OPEN_FLAGS, DICT_FLAGS));
	    argv_add(list, STR(buf), (char *) 0);
	} else {				/* other pattern */
	    argv_add(list, match ? item :
		     STR(vstring_sprintf(buf, "!%s", item)), (char *) 0);
	}
    }
    vstring_free(buf);
    return (list);
}
Esempio n. 3
0
int     match_hostaddr(MATCH_LIST *list, const char *addr, const char *pattern)
{
    const char *myname = "match_hostaddr";
    char   *saved_patt;
    CIDR_MATCH match_info;
    DICT   *dict;
    VSTRING *err;
    int     rc;

    if (msg_verbose)
	msg_info("%s: %s ~? %s", myname, addr, pattern);

#define V4_ADDR_STRING_CHARS	"01234567890."
#define V6_ADDR_STRING_CHARS	V4_ADDR_STRING_CHARS "abcdefABCDEF:"

    if (addr[strspn(addr, V6_ADDR_STRING_CHARS)] != 0)
	return (0);

    /*
     * Try dictionary lookup. This can be case insensitive.
     */
    if (MATCH_DICTIONARY(pattern)) {
	if ((dict = dict_handle(pattern)) == 0)
	    msg_panic("%s: unknown dictionary: %s", myname, pattern);
	if (dict_get(dict, addr) != 0)
	    return (1);
	if ((list->error = dict->error) != 0)
	    return (match_error(list, "%s:%s: table lookup problem",
				dict->type, dict->name));
	return (0);
    }

    /*
     * Try an exact match with the host address.
     */
    if (pattern[0] != '[') {
	if (strcasecmp(addr, pattern) == 0)
	    return (1);
    } else {
	size_t  addr_len = strlen(addr);

	if (strncasecmp(addr, pattern + 1, addr_len) == 0
	    && strcmp(pattern + 1 + addr_len, "]") == 0)
	    return (1);
    }

    /*
     * Light-weight tests before we get into expensive operations.
     * 
     * - Don't bother matching IPv4 against IPv6. Postfix transforms
     * IPv4-in-IPv6 to native IPv4 form when IPv4 support is enabled in
     * Postfix; if not, then Postfix has no business dealing with IPv4
     * addresses anyway.
     * 
     * - Don't bother unless the pattern is either an IPv6 address or net/mask.
     * 
     * We can safely skip IPv4 address patterns because their form is
     * unambiguous and they did not match in the strcasecmp() calls above.
     * 
     * XXX We MUST skip (parent) domain names, which may appear in NAMADR_LIST
     * input, to avoid triggering false cidr_match_parse() errors.
     * 
     * The last two conditions below are for backwards compatibility with
     * earlier Postfix versions: don't abort with fatal errors on junk that
     * was silently ignored (principle of least astonishment).
     */
    if (!strchr(addr, ':') != !strchr(pattern, ':')
	|| pattern[strcspn(pattern, ":/")] == 0
	|| pattern[strspn(pattern, V4_ADDR_STRING_CHARS)] == 0
	|| pattern[strspn(pattern, V6_ADDR_STRING_CHARS "[]/")] != 0)
	return (0);

    /*
     * No escape from expensive operations: either we have a net/mask
     * pattern, or we have an address that can have multiple valid
     * representations (e.g., 0:0:0:0:0:0:0:1 versus ::1, etc.). The only way
     * to find out if the address matches the pattern is to transform
     * everything into to binary form, and to do the comparison there.
     */
    saved_patt = mystrdup(pattern);
    err = cidr_match_parse(&match_info, saved_patt, (VSTRING *) 0);
    myfree(saved_patt);
    if (err != 0) {
	list->error = DICT_ERR_RETRY;
	rc = match_error(list, "%s", vstring_str(err));
	vstring_free(err);
	return (rc);
    }
    return (cidr_match_execute(&match_info, addr) != 0);
}
Esempio n. 4
0
int     match_hostname(MATCH_LIST *list, const char *name, const char *pattern)
{
    const char *myname = "match_hostname";
    const char *pd;
    const char *entry;
    const char *next;
    int     match;
    DICT   *dict;

    if (msg_verbose)
	msg_info("%s: %s ~? %s", myname, name, pattern);

    /*
     * Try dictionary lookup: exact match and parent domains.
     * 
     * Don't look up parent domain substrings with regexp maps etc.
     */
    if (MATCH_DICTIONARY(pattern)) {
	if ((dict = dict_handle(pattern)) == 0)
	    msg_panic("%s: unknown dictionary: %s", myname, pattern);
	match = 0;
	for (entry = name; *entry != 0; entry = next) {
	    if (entry == name || (dict->flags & DICT_FLAG_FIXED)) {
		match = (dict_get(dict, entry) != 0);
		if (msg_verbose > 1)
		    msg_info("%s: lookup %s:%s %s: %s",
			     myname, dict->type, dict->name, entry,
			     match ? "found" : "notfound");
		if (match != 0)
		    break;
		if ((list->error = dict->error) != 0)
		    return (match_error(list, "%s:%s: table lookup problem",
					dict->type, dict->name));
	    }
	    if ((next = strchr(entry + 1, '.')) == 0)
		break;
	    if (list->flags & MATCH_FLAG_PARENT)
		next += 1;
	}
	return (match);
    }

    /*
     * Try an exact match with the host name.
     */
    if (strcasecmp(name, pattern) == 0) {
	return (1);
    }

    /*
     * See if the pattern is a parent domain of the hostname.
     */
    else {
	if (list->flags & MATCH_FLAG_PARENT) {
	    pd = name + strlen(name) - strlen(pattern);
	    if (pd > name && pd[-1] == '.' && strcasecmp(pd, pattern) == 0)
		return (1);
	} else if (pattern[0] == '.') {
	    pd = name + strlen(name) - strlen(pattern);
	    if (pd > name && strcasecmp(pd, pattern) == 0)
		return (1);
	}
    }
    return (0);
}