/*++ /* NAME /* match_service 3 /* SUMMARY /* simple master.cf service name.type pattern matcher /* SYNOPSIS /* #include /* /* ARGV *match_service_init(pattern_list) /* const char *pattern_list; /* /* ARGV *match_service_init_argv(pattern_list) /* char **pattern_list; /* /* int match_service_match(list, name_type) /* ARGV *list; /* const char *name_type; /* /* void match_service_free(list) /* ARGV *list; /* DESCRIPTION /* This module implements pattern matching for Postfix master.cf /* services. This is more precise than using domain_list(3), /* because match_service(3) won't treat a dotted service name /* as a domain hierarchy. Moreover, this module has the advantage /* that it does not drag in all the LDAP, SQL and other map /* lookup client code into programs that don't need it. /* /* Each pattern is of the form "name/type" or "type", where /* "name" and "type" are the first two fields of a master.cf /* entry. Patterns are separated by whitespace and/or commas. /* Matches are case insensitive. Patterns are matched in the /* specified order, and the matching process stops at the first /* match. In order to reverse the result of a pattern match, /* precede a pattern with an exclamation point (!). /* /* For backwards compatibility, the form name.type is still /* supported. /* /* match_service_init() parses the pattern list. The result /* must be passed to match_service_match() or match_service_free(). /* /* match_service_init_argv() provides an alternate interface /* for pre-parsed strings. /* /* match_service_match() matches one service name.type string /* against the specified pattern list. /* /* match_service_free() releases storage allocated by /* match_service_init(). /* DIAGNOSTICS /* Fatal error: out of memory, malformed pattern. /* Panic: malformed search string. /* SEE ALSO /* domain_list(3) match domain names. /* LICENSE /* .ad /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /*--*/ /* System library. */ #include #include #ifdef STRCASECMP_IN_STRINGS_H #include #endif /* Utility library. */ #include #include #include #include #include /* match_service_compat - backwards compatibility */ static void match_service_compat(ARGV *argv) { char **cpp; char *cp; for (cpp = argv->argv; *cpp; cpp++) { if (strrchr(*cpp, '/') == 0 && (cp = strrchr(*cpp, '.')) != 0) *cp = '/'; } } /* match_service_init - initialize pattern list */ ARGV *match_service_init(const char *patterns) { const char *delim = CHARS_COMMA_SP; ARGV *list = argv_alloc(1); char *saved_patterns = mystrdup(patterns); char *bp = saved_patterns; const char *item; while ((item = mystrtok(&bp, delim)) != 0) argv_add(list, item, (char *) 0); argv_terminate(list); myfree(saved_patterns); match_service_compat(list); return (list); } /* match_service_init_argv - impedance adapter */ ARGV *match_service_init_argv(char **patterns) { ARGV *list = argv_alloc(1); char **cpp; for (cpp = patterns; *cpp; cpp++) argv_add(list, *cpp, (char *) 0); argv_terminate(list); match_service_compat(list); return (list); } /* match_service_match - match service name.type against pattern list */ int match_service_match(ARGV *list, const char *name_type) { const char *myname = "match_service_match"; const char *type; char **cpp; char *pattern; int match; /* * Quick check for empty list. */ if (list->argv[0] == 0) return (0); /* * Sanity check. */ if ((type = strrchr(name_type, '/')) == 0 || *++type == 0) msg_panic("%s: malformed service: \"%s\"; need \"name/type\" format", myname, name_type); /* * Iterate over all patterns in the list, stop at the first match. */ for (cpp = list->argv; (pattern = *cpp) != 0; cpp++) { if (msg_verbose) msg_info("%s: %s ~? %s", myname, name_type, pattern); for (match = 1; *pattern == '!'; pattern++) match = !match; if (strcasecmp(strchr(pattern, '/') ? name_type : type, pattern) == 0) { if (msg_verbose) msg_info("%s: %s: found match", myname, name_type); return (match); } } if (msg_verbose) msg_info("%s: %s: no match", myname, name_type); return (0); } /* match_service_free - release storage */ void match_service_free(ARGV *list) { argv_free(list); }