1/*++
2/* NAME
3/*	postconf_match 3
4/* SUMMARY
5/*	pattern-matching support
6/* SYNOPSIS
7/*	#include <postconf.h>
8/*
9/*	int	pcf_parse_field_pattern(field_expr)
10/*	char	*field_expr;
11/*
12/*	const char *pcf_str_field_pattern(field_pattern)
13/*	int	field_pattern;
14/*
15/*	int	pcf_is_magic_field_pattern(field_pattern)
16/*	int	field_pattern;
17/*
18/*	ARGV	*pcf_parse_service_pattern(service_expr, min_expr, max_expr)
19/*	const char *service_expr;
20/*	int	min_expr;
21/*	int	max_expr;
22/*
23/*	int	PCF_IS_MAGIC_SERVICE_PATTERN(service_pattern)
24/*	const ARGV *service_pattern;
25/*
26/*	int	PCF_MATCH_SERVICE_PATTERN(service_pattern, service_name,
27/*					service_type)
28/*	const ARGV *service_pattern;
29/*	const char *service_name;
30/*	const char *service_type;
31/*
32/*	const char *pcf_str_field_pattern(field_pattern)
33/*	int	field_pattern;
34/*
35/*	int	PCF_IS_MAGIC_PARAM_PATTERN(param_pattern)
36/*	const char *param_pattern;
37/*
38/*	int	PCF_MATCH_PARAM_PATTERN(param_pattern, param_name)
39/*	const char *param_pattern;
40/*	const char *param_name;
41/* DESCRIPTION
42/*	pcf_parse_service_pattern() takes an expression and splits
43/*	it up on '/' into an array of sub-expressions, This function
44/*	returns null if the input does fewer than "min" or more
45/*	than "max" sub-expressions.
46/*
47/*	PCF_IS_MAGIC_SERVICE_PATTERN() returns non-zero if any of
48/*	the service name or service type sub-expressions contains
49/*	a matching operator (as opposed to string literals that
50/*	only match themselves). This is an unsafe macro that evaluates
51/*	its arguments more than once.
52/*
53/*	PCF_MATCH_SERVICE_PATTERN() matches a service name and type
54/*	from master.cf against the parsed pattern. This is an unsafe
55/*	macro that evaluates its arguments more than once.
56/*
57/*	pcf_parse_field_pattern() converts a field sub-expression,
58/*	and returns the conversion result.
59/*
60/*	pcf_str_field_pattern() converts a result from
61/*	pcf_parse_field_pattern() into string form.
62/*
63/*	pcf_is_magic_field_pattern() returns non-zero if the field
64/*	pattern sub-expression contained a matching operator (as
65/*	opposed to a string literal that only matches itself).
66/*
67/*	PCF_IS_MAGIC_PARAM_PATTERN() returns non-zero if the parameter
68/*	sub-expression contains a matching operator (as opposed to
69/*	a string literal that only matches itself). This is an
70/*	unsafe macro that evaluates its arguments more than once.
71/*
72/*	PCF_MATCH_PARAM_PATTERN() matches a parameter name from
73/*	master.cf against the parsed pattern. This is an unsafe
74/*	macro that evaluates its arguments more than once.
75/*
76/*	Arguments
77/* .IP field_expr
78/*	A field expression.
79/* .IP service_expr
80/*	This argument is split on '/' into its constituent
81/*	sub-expressions.
82/* .IP min_expr
83/*	The minimum number of sub-expressions in service_expr.
84/* .IP max_expr
85/*	The maximum number of sub-expressions in service_expr.
86/* .IP service_name
87/*	Service name from master.cf.
88/* .IP service_type
89/*	Service type from master.cf.
90/* .IP param_pattern
91/*	A parameter name expression.
92/* DIAGNOSTICS
93/*	Fatal errors: invalid syntax.
94/* LICENSE
95/* .ad
96/* .fi
97/*	The Secure Mailer license must be distributed with this software.
98/* AUTHOR(S)
99/*	Wietse Venema
100/*	IBM T.J. Watson Research
101/*	P.O. Box 704
102/*	Yorktown Heights, NY 10598, USA
103/*--*/
104
105/* System library. */
106
107#include <sys_defs.h>
108#include <string.h>
109
110/* Utility library. */
111
112#include <msg.h>
113#include <mymalloc.h>
114#include <vstring.h>
115
116/* Global library. */
117
118#include <split_at.h>
119
120/* Application-specific. */
121
122#include <postconf.h>
123
124 /*
125  * Conversion table. Each PCF_MASTER_NAME_XXX name entry must be stored at
126  * table offset PCF_MASTER_FLD_XXX. So don't mess it up.
127  */
128NAME_CODE pcf_field_name_offset[] = {
129    PCF_MASTER_NAME_SERVICE, PCF_MASTER_FLD_SERVICE,
130    PCF_MASTER_NAME_TYPE, PCF_MASTER_FLD_TYPE,
131    PCF_MASTER_NAME_PRIVATE, PCF_MASTER_FLD_PRIVATE,
132    PCF_MASTER_NAME_UNPRIV, PCF_MASTER_FLD_UNPRIV,
133    PCF_MASTER_NAME_CHROOT, PCF_MASTER_FLD_CHROOT,
134    PCF_MASTER_NAME_WAKEUP, PCF_MASTER_FLD_WAKEUP,
135    PCF_MASTER_NAME_MAXPROC, PCF_MASTER_FLD_MAXPROC,
136    PCF_MASTER_NAME_CMD, PCF_MASTER_FLD_CMD,
137    "*", PCF_MASTER_FLD_WILDC,
138    0, PCF_MASTER_FLD_NONE,
139};
140
141/* pcf_parse_field_pattern - parse service attribute pattern */
142
143int     pcf_parse_field_pattern(const char *field_name)
144{
145    int     field_pattern;
146
147    if ((field_pattern = name_code(pcf_field_name_offset,
148				   NAME_CODE_FLAG_STRICT_CASE,
149				   field_name)) == PCF_MASTER_FLD_NONE)
150	msg_fatal("invalid service attribute name: \"%s\"", field_name);
151    return (field_pattern);
152}
153
154/* pcf_parse_service_pattern - parse service pattern */
155
156ARGV   *pcf_parse_service_pattern(const char *pattern, int min_expr, int max_expr)
157{
158    ARGV   *argv;
159    char  **cpp;
160
161    /*
162     * Work around argv_split() lameness.
163     */
164    if (*pattern == '/')
165	return (0);
166    argv = argv_split(pattern, PCF_NAMESP_SEP_STR);
167    if (argv->argc < min_expr || argv->argc > max_expr) {
168	argv_free(argv);
169	return (0);
170    }
171
172    /*
173     * Allow '*' only all by itself.
174     */
175    for (cpp = argv->argv; *cpp; cpp++) {
176	if (!PCF_MATCH_ANY(*cpp) && strchr(*cpp, PCF_MATCH_WILDC_STR[0]) != 0) {
177	    argv_free(argv);
178	    return (0);
179	}
180    }
181
182    /*
183     * Provide defaults for missing fields.
184     */
185    while (argv->argc < max_expr)
186	argv_add(argv, PCF_MATCH_WILDC_STR, ARGV_END);
187    return (argv);
188}
189