1 /* $NetBSD: match_service.c,v 1.1.1.3 2014/07/06 19:27:51 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 /* For backwards compatibility, the form name.type is still 40 /* supported. 41 /* 42 /* match_service_init() parses the pattern list. The result 43 /* must be passed to match_service_match() or match_service_free(). 44 /* 45 /* match_service_init_argv() provides an alternate interface 46 /* for pre-parsed strings. 47 /* 48 /* match_service_match() matches one service name.type string 49 /* against the specified pattern list. 50 /* 51 /* match_service_free() releases storage allocated by 52 /* match_service_init(). 53 /* DIAGNOSTICS 54 /* Fatal error: out of memory, malformed pattern. 55 /* Panic: malformed search string. 56 /* SEE ALSO 57 /* domain_list(3) match domain names. 58 /* LICENSE 59 /* .ad 60 /* .fi 61 /* The Secure Mailer license must be distributed with this software. 62 /* AUTHOR(S) 63 /* Wietse Venema 64 /* IBM T.J. Watson Research 65 /* P.O. Box 704 66 /* Yorktown Heights, NY 10598, USA 67 /*--*/ 68 69 /* System library. */ 70 71 #include <sys_defs.h> 72 #include <string.h> 73 74 #ifdef STRCASECMP_IN_STRINGS_H 75 #include <strings.h> 76 #endif 77 78 /* Utility library. */ 79 80 #include <msg.h> 81 #include <argv.h> 82 #include <mymalloc.h> 83 #include <stringops.h> 84 #include <match_service.h> 85 86 /* match_service_compat - backwards compatibility */ 87 88 static void match_service_compat(ARGV *argv) 89 { 90 char **cpp; 91 char *cp; 92 93 for (cpp = argv->argv; *cpp; cpp++) { 94 if (strrchr(*cpp, '/') == 0 && (cp = strrchr(*cpp, '.')) != 0) 95 *cp = '/'; 96 } 97 } 98 99 /* match_service_init - initialize pattern list */ 100 101 ARGV *match_service_init(const char *patterns) 102 { 103 const char *delim = " ,\t\r\n"; 104 ARGV *list = argv_alloc(1); 105 char *saved_patterns = mystrdup(patterns); 106 char *bp = saved_patterns; 107 const char *item; 108 109 while ((item = mystrtok(&bp, delim)) != 0) 110 argv_add(list, item, (char *) 0); 111 argv_terminate(list); 112 myfree(saved_patterns); 113 match_service_compat(list); 114 return (list); 115 } 116 117 /* match_service_init_argv - impedance adapter */ 118 119 ARGV *match_service_init_argv(char **patterns) 120 { 121 ARGV *list = argv_alloc(1); 122 char **cpp; 123 124 for (cpp = patterns; *cpp; cpp++) 125 argv_add(list, *cpp, (char *) 0); 126 argv_terminate(list); 127 match_service_compat(list); 128 return (list); 129 } 130 131 /* match_service_match - match service name.type against pattern list */ 132 133 int match_service_match(ARGV *list, const char *name_type) 134 { 135 const char *myname = "match_service_match"; 136 const char *type; 137 char **cpp; 138 char *pattern; 139 int match; 140 141 /* 142 * Quick check for empty list. 143 */ 144 if (list->argv[0] == 0) 145 return (0); 146 147 /* 148 * Sanity check. 149 */ 150 if ((type = strrchr(name_type, '/')) == 0 || *++type == 0) 151 msg_panic("%s: malformed service: \"%s\"; need \"name/type\" format", 152 myname, name_type); 153 154 /* 155 * Iterate over all patterns in the list, stop at the first match. 156 */ 157 for (cpp = list->argv; (pattern = *cpp) != 0; cpp++) { 158 if (msg_verbose) 159 msg_info("%s: %s ~? %s", myname, name_type, pattern); 160 for (match = 1; *pattern == '!'; pattern++) 161 match = !match; 162 if (strcasecmp(strchr(pattern, '/') ? name_type : type, pattern) == 0) { 163 if (msg_verbose) 164 msg_info("%s: %s: found match", myname, name_type); 165 return (match); 166 } 167 } 168 if (msg_verbose) 169 msg_info("%s: %s: no match", myname, name_type); 170 return (0); 171 } 172 173 /* match_service_free - release storage */ 174 175 void match_service_free(ARGV *list) 176 { 177 argv_free(list); 178 } 179