summaryrefslogtreecommitdiffstats
path: root/src/global/match_service.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/global/match_service.c176
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);
+}