1/*++ 2/* NAME 3/* match_service 3 4/* SUMMARY 5/* simple master.cf service name.type pattern matcher 6/* SYNOPSIS 7/* #include <match_service.h> 8/* 9/* ARGV *match_service_init(pattern_list) 10/* const char *pattern_list; 11/* 12/* ARGV *match_service_init_argv(pattern_list) 13/* char **pattern_list; 14/* 15/* int match_service_match(list, name_type) 16/* ARGV *list; 17/* const char *name_type; 18/* 19/* void match_service_free(list) 20/* ARGV *list; 21/* DESCRIPTION 22/* This module implements pattern matching for Postfix master.cf 23/* services. This is more precise than using domain_list(3), 24/* because match_service(3) won't treat a dotted service name 25/* as a domain hierarchy. Moreover, this module has the advantage 26/* that it does not drag in all the LDAP, SQL and other map 27/* lookup client code into programs that don't need it. 28/* 29/* Each pattern is of the form "name.type" or "type", where 30/* "name" and "type" are the first two fields of a master.cf 31/* entry. Patterns are separated by whitespace and/or commas. 32/* Matches are case insensitive. Patterns are matched in the 33/* specified order, and the matching process stops at the first 34/* match. In order to reverse the result of a pattern match, 35/* precede a pattern with an exclamation point (!). 36/* 37/* match_service_init() parses the pattern list. The result 38/* must be passed to match_service_match() or match_service_free(). 39/* 40/* match_service_init_argv() provides an alternate interface 41/* for pre-parsed strings. 42/* 43/* match_service_match() matches one service name.type string 44/* against the specified pattern list. 45/* 46/* match_service_free() releases storage allocated by 47/* match_service_init(). 48/* DIAGNOSTICS 49/* Fatal error: out of memory, malformed pattern. 50/* Panic: malformed search string. 51/* SEE ALSO 52/* domain_list(3) match domain names. 53/* LICENSE 54/* .ad 55/* .fi 56/* The Secure Mailer license must be distributed with this software. 57/* AUTHOR(S) 58/* Wietse Venema 59/* IBM T.J. Watson Research 60/* P.O. Box 704 61/* Yorktown Heights, NY 10598, USA 62/*--*/ 63 64/* System library. */ 65 66#include <sys_defs.h> 67#include <string.h> 68 69#ifdef STRCASECMP_IN_STRINGS_H 70#include <strings.h> 71#endif 72 73/* Utility library. */ 74 75#include <msg.h> 76#include <argv.h> 77#include <mymalloc.h> 78#include <stringops.h> 79#include <match_service.h> 80 81/* match_service_init - initialize pattern list */ 82 83ARGV *match_service_init(const char *patterns) 84{ 85 const char *delim = " ,\t\r\n"; 86 ARGV *list = argv_alloc(1); 87 char *saved_patterns = mystrdup(patterns); 88 char *bp = saved_patterns; 89 const char *item; 90 91 while ((item = mystrtok(&bp, delim)) != 0) 92 argv_add(list, item, (char *) 0); 93 argv_terminate(list); 94 myfree(saved_patterns); 95 return (list); 96} 97 98/* match_service_init_argv - impedance adapter */ 99 100ARGV *match_service_init_argv(char **patterns) 101{ 102 ARGV *list = argv_alloc(1); 103 char **cpp; 104 105 for (cpp = patterns; *cpp; cpp++) 106 argv_add(list, *cpp, (char *) 0); 107 argv_terminate(list); 108 return (list); 109} 110 111/* match_service_match - match service name.type against pattern list */ 112 113int match_service_match(ARGV *list, const char *name_type) 114{ 115 const char *myname = "match_service_match"; 116 const char *type; 117 char **cpp; 118 char *pattern; 119 int match; 120 121 /* 122 * Quick check for empty list. 123 */ 124 if (list->argv[0] == 0) 125 return (0); 126 127 /* 128 * Sanity check. 129 */ 130 if ((type = strrchr(name_type, '.')) == 0 || *++type == 0) 131 msg_panic("%s: malformed service: \"%s\"; need \"name.type\" format", 132 myname, name_type); 133 134 /* 135 * Iterate over all patterns in the list, stop at the first match. 136 */ 137 for (cpp = list->argv; (pattern = *cpp) != 0; cpp++) { 138 if (msg_verbose) 139 msg_info("%s: %s ~? %s", myname, name_type, pattern); 140 for (match = 1; *pattern == '!'; pattern++) 141 match = !match; 142 if (strcasecmp(strchr(pattern, '.') ? name_type : type, pattern) == 0) { 143 if (msg_verbose) 144 msg_info("%s: %s: found match", myname, name_type); 145 return (match); 146 } 147 } 148 if (msg_verbose) 149 msg_info("%s: %s: no match", myname, name_type); 150 return (0); 151} 152 153/* match_service_free - release storage */ 154 155void match_service_free(ARGV *list) 156{ 157 argv_free(list); 158} 159