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