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