2 * Copyright (c) 2012, 2013, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include <tr_filter.h>
43 #include <trp_internal.h>
44 #include <tid_internal.h>
46 const TR_FILTER_TYPE tr_filter_types[] = {
47 TR_FILTER_TYPE_TID_INBOUND,
48 TR_FILTER_TYPE_TRP_INBOUND,
49 TR_FILTER_TYPE_TRP_OUTBOUND
51 const size_t tr_num_filter_types=sizeof(tr_filter_types)/sizeof(tr_filter_types[0]);
52 static const char *tr_filter_type_strings[] = {
58 const char *tr_filter_type_to_string(TR_FILTER_TYPE t) {
60 for (ii=0; ii<tr_num_filter_types;ii++) {
61 if (t==tr_filter_types[ii])
62 return tr_filter_type_strings[ii];
67 TR_FILTER_TYPE tr_filter_type_from_string(const char *s)
70 for (ii=0; ii<tr_num_filter_types; ii++) {
71 if (strcasecmp(s, tr_filter_type_strings[ii])==0)
72 return tr_filter_types[ii];
74 return TR_FILTER_TYPE_UNKNOWN;
77 /* Function types for handling filter fields generally. All target values
78 * are represented as strings in a TR_NAME.
80 typedef int (*TR_FILTER_FIELD_CMP)(void *target, TR_NAME *val); /* returns 1 on match, 0 on no match */
81 typedef TR_NAME *(*TR_FILTER_FIELD_GET)(void *target); /* returns string form of the field value */
83 /* static handler prototypes */
84 static int tr_ff_cmp_tid_rp_realm(void *rp_req_arg, TR_NAME *val);
85 static TR_NAME *tr_ff_get_tid_rp_realm(void *rp_req_arg);
86 static int tr_ff_cmp_trp_info_type(void *inforec_arg, TR_NAME *val);
87 static TR_NAME *tr_ff_get_trp_info_type(void *inforec_arg);
90 * Filter field handler table
92 struct tr_filter_field_entry {
93 TR_FILTER_TYPE filter_type;
95 TR_FILTER_FIELD_CMP cmp;
96 TR_FILTER_FIELD_GET get;
98 static struct tr_filter_field_entry tr_filter_field_table[] = {
99 {TR_FILTER_TYPE_TID_INBOUND, "rp_realm", tr_ff_cmp_tid_rp_realm, tr_ff_get_tid_rp_realm},
100 {TR_FILTER_TYPE_TRP_INBOUND, "info_type", tr_ff_cmp_trp_info_type, tr_ff_get_trp_info_type},
101 {TR_FILTER_TYPE_TRP_OUTBOUND, "info_type", tr_ff_cmp_trp_info_type, tr_ff_get_trp_info_type},
102 {TR_FILTER_TYPE_UNKNOWN, NULL } /* This must be the final entry */
105 static struct tr_filter_field_entry *tr_filter_field_entry(TR_FILTER_TYPE filter_type, TR_NAME *field_name)
109 for (ii=0; tr_filter_field_table[ii].filter_type!=TR_FILTER_TYPE_UNKNOWN; ii++) {
110 if ((tr_filter_field_table[ii].filter_type==filter_type)
111 && (tr_name_cmp_str(field_name, tr_filter_field_table[ii].name)==0)) {
112 return tr_filter_field_table+ii;
118 static int tr_ff_cmp_tid_rp_realm(void *rp_req_arg, TR_NAME *val)
120 TID_REQ *req=talloc_get_type_abort(rp_req_arg, TID_REQ);
122 return 0==tr_name_cmp(val, req->rp_realm);
125 static TR_NAME *tr_ff_get_tid_rp_realm(void *rp_req_arg)
127 TID_REQ *req=talloc_get_type_abort(rp_req_arg, TID_REQ);
129 return tr_dup_name(req->rp_realm);
132 static int tr_ff_cmp_trp_info_type(void *inforec_arg, TR_NAME *val)
134 TRP_INFOREC *inforec=talloc_get_type_abort(inforec_arg, TRP_INFOREC);
141 /* nothing matches unknown */
142 if (inforec->type==TRP_INFOREC_TYPE_UNKNOWN)
145 valstr = tr_name_strdup(val); /* get this as an official null-terminated string */
146 val_type = trp_inforec_type_from_string(valstr);
149 return (val_type==inforec->type);
152 static TR_NAME *tr_ff_get_trp_info_type(void *inforec_arg)
154 TRP_INFOREC *inforec=talloc_get_type_abort(inforec_arg, TRP_INFOREC);
155 return tr_new_name(trp_inforec_type_to_string(inforec->type));
159 * Apply a filter to a target record or TID request.
161 * If one of the filter lines matches, out_action is set to the applicable action. If constraints
162 * is not NULL, the constraints from the matching filter line will be added to the constraint set
163 * *constraints, or to a new one if *constraints is NULL. In this case, TR_FILTER_MATCH will be
166 * If there is no match, returns TR_FILTER_NO_MATCH, out_action is undefined, and constraints
167 * will not be changed.
169 * @param target Record or request to which the filter is applied
170 * @param filt Filter to apply
171 * @param constraints Pointer to existing set of constraints (NULL if not tracking constraints)
172 * @param out_action Action to be carried out (output)
173 * @return TR_FILTER_MATCH or TR_FILTER_NO_MATCH
175 int tr_filter_apply(void *target,
177 TR_CONSTRAINT_SET **constraints,
178 TR_FILTER_ACTION *out_action)
180 unsigned int ii=0, jj=0;
181 int retval=TR_FILTER_NO_MATCH;
183 /* Default action is reject */
184 *out_action = TR_FILTER_ACTION_REJECT;
186 /* Validate filter */
187 if ((filt==NULL) || (filt->type==TR_FILTER_TYPE_UNKNOWN))
188 return TR_FILTER_NO_MATCH;
190 /* Step through filter lines looking for a match. If a line matches, retval
191 * will be set to TR_FILTER_MATCH, so stop then. */
192 for (ii=0, retval=TR_FILTER_NO_MATCH;
193 (ii<TR_MAX_FILTER_LINES) && (retval==TR_FILTER_NO_MATCH);
195 /* skip empty lines (these shouldn't really happen) */
196 if (filt->lines[ii]==NULL)
199 /* Assume we are going to succeed. If any specs fail to match, we'll set
200 * this to TR_FILTER_NO_MATCH. */
201 retval=TR_FILTER_MATCH;
202 for (jj=0; jj<TR_MAX_FILTER_SPECS; jj++) {
203 /* skip empty specs (these shouldn't really happen either) */
204 if (filt->lines[ii]->specs[jj]==NULL)
207 if (!tr_fspec_matches(filt->lines[ii]->specs[jj], filt->type, target)) {
208 retval=TR_FILTER_NO_MATCH; /* set this in case this is the last filter line */
209 break; /* give up on this filter line */
214 if (retval==TR_FILTER_MATCH) {
215 /* Matched line ii. Grab its action and constraints. */
216 *out_action = filt->lines[ii]->action;
217 if (constraints!=NULL) {
218 /* if either constraint is missing, these are no-ops */
219 tr_constraint_add_to_set(constraints, filt->lines[ii]->realm_cons);
220 tr_constraint_add_to_set(constraints, filt->lines[ii]->domain_cons);
227 int tr_filter_process_rp_permitted(TR_NAME *rp_realm,
228 TR_FILTER *rpp_filter,
229 TR_CONSTRAINT_SET *in_constraints,
230 TR_CONSTRAINT_SET **out_constraints,
231 TR_FILTER_ACTION *out_action)
235 *out_action = TR_FILTER_ACTION_REJECT;
236 *out_constraints = NULL;
238 /* If this isn't a valid rp_permitted filter, return no match. */
240 (TR_FILTER_TYPE_TID_INBOUND != rpp_filter->type)) {
241 return TR_FILTER_NO_MATCH;
244 /* Check if there is a match for this filter. */
245 for (i = 0; i < TR_MAX_FILTER_LINES; i++) {
246 for (j = 0; j < TR_MAX_FILTER_SPECS; j++) {
248 if ((rpp_filter->lines[i]) &&
249 (rpp_filter->lines[i]->specs[j]) &&
250 (tr_fspec_matches(rpp_filter->lines[i]->specs[j], 0, rp_realm))) { /* todo: fix or remove */
251 *out_action = rpp_filter->lines[i]->action;
252 *out_constraints = in_constraints;
253 if (rpp_filter->lines[i]->realm_cons)
254 tr_constraint_add_to_set(out_constraints,
255 rpp_filter->lines[i]->realm_cons);
256 if (rpp_filter->lines[i]->domain_cons)
257 tr_constraint_add_to_set(out_constraints,
258 rpp_filter->lines[i]->domain_cons);
260 return TR_FILTER_MATCH;
264 /* If there is no match, indicate that. */
265 return TR_FILTER_NO_MATCH;
268 void tr_fspec_free(TR_FSPEC *fspec)
273 static int tr_fspec_destructor(void *obj)
275 TR_FSPEC *fspec = talloc_get_type_abort(obj, TR_FSPEC);
277 if (fspec->field != NULL)
278 tr_free_name(fspec->field);
279 if (fspec->match != NULL)
280 tr_free_name(fspec->match);
284 TR_FSPEC *tr_fspec_new(TALLOC_CTX *mem_ctx)
286 TR_FSPEC *fspec = talloc(mem_ctx, TR_FSPEC);
291 talloc_set_destructor((void *) fspec, tr_fspec_destructor);
296 void tr_fspec_set_match(TR_FSPEC *fspec, TR_NAME *match)
298 if (fspec->match != NULL)
299 tr_free_name(fspec->match);
300 fspec->match = match;
303 /* returns 1 if the spec matches */
304 int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target)
306 struct tr_filter_field_entry *field=NULL;
309 if ((fspec==NULL) || (fspec->match==NULL))
312 /* Look up how to handle the requested field */
313 field = tr_filter_field_entry(ftype, fspec->field);
317 name=field->get(target);
318 return ((fspec->match != NULL) &&
319 (0 != tr_name_prefix_wildcard_match(name, fspec->match)));
322 void tr_fline_free(TR_FLINE *fline)
327 TR_FLINE *tr_fline_new(TALLOC_CTX *mem_ctx)
329 TR_FLINE *fl = talloc(mem_ctx, TR_FLINE);
333 fl->action = TR_FILTER_ACTION_UNKNOWN;
334 fl->realm_cons = NULL;
335 fl->domain_cons = NULL;
336 for (ii = 0; ii < TR_MAX_FILTER_SPECS; ii++)
337 fl->specs[ii] = NULL;
342 TR_FILTER *tr_filter_new(TALLOC_CTX *mem_ctx)
344 TR_FILTER *f = talloc(mem_ctx, TR_FILTER);
348 f->type = TR_FILTER_TYPE_UNKNOWN;
349 for (ii = 0; ii < TR_MAX_FILTER_LINES; ii++)
355 void tr_filter_free(TR_FILTER *filt)
360 void tr_filter_set_type(TR_FILTER *filt, TR_FILTER_TYPE type)
365 TR_FILTER_TYPE tr_filter_get_type(TR_FILTER *filt)