xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/match_service.c (revision 75219f3a016dfaad1cb304eb017f9787b1de8292)
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