diff options
Diffstat (limited to 'src/global/match_service.c')
-rw-r--r-- | src/global/match_service.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/global/match_service.c b/src/global/match_service.c new file mode 100644 index 0000000..856355e --- /dev/null +++ b/src/global/match_service.c @@ -0,0 +1,176 @@ +/*++ +/* NAME +/* match_service 3 +/* SUMMARY +/* simple master.cf service name.type pattern matcher +/* SYNOPSIS +/* #include <match_service.h> +/* +/* 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 <sys_defs.h> +#include <string.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include <msg.h> +#include <argv.h> +#include <mymalloc.h> +#include <stringops.h> +#include <match_service.h> + +/* 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); +} |