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