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