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 /* Function types for handling filter fields generally. All target values
47 * are represented as strings in a TR_NAME.
49 typedef int (*TR_FILTER_FIELD_CMP)(void *target, TR_NAME *val); /* returns 1 on match, 0 on no match */
50 typedef TR_NAME *(*TR_FILTER_FIELD_GET)(void *target); /* returns string form of the field value */
52 /* static handler prototypes */
53 static int tr_ff_cmp_tid_rp_realm(void *rp_req_arg, TR_NAME *val);
54 static TR_NAME *tr_ff_get_tid_rp_realm(void *rp_req_arg);
55 static int tr_ff_cmp_trp_info_type(void *inforec_arg, TR_NAME *val);
56 static TR_NAME *tr_ff_get_trp_info_type(void *inforec_arg);
59 * Filter field handler table
61 struct tr_filter_field_entry {
62 TR_FILTER_TYPE filter_type;
64 TR_FILTER_FIELD_CMP cmp;
65 TR_FILTER_FIELD_GET get;
67 static struct tr_filter_field_entry tr_filter_field_table[] = {
68 {TR_FILTER_TYPE_TID_INBOUND, "rp_realm", tr_ff_cmp_tid_rp_realm, tr_ff_get_tid_rp_realm},
69 {TR_FILTER_TYPE_TRP_INBOUND, "info_type", tr_ff_cmp_trp_info_type, tr_ff_get_trp_info_type},
70 {TR_FILTER_TYPE_TRP_OUTBOUND, "info_type", tr_ff_cmp_trp_info_type, tr_ff_get_trp_info_type},
71 {TR_FILTER_TYPE_UNKNOWN, NULL } /* This must be the final entry */
74 static struct tr_filter_field_entry *tr_filter_field_entry(TR_FILTER_TYPE filter_type, TR_NAME *field_name)
78 for (ii=0; tr_filter_field_table[ii].filter_type!=TR_FILTER_TYPE_UNKNOWN; ii++) {
79 if ((tr_filter_field_table[ii].filter_type==filter_type)
80 && (tr_name_cmp_str(field_name, tr_filter_field_table[ii].name)==0)) {
81 return tr_filter_field_table+ii;
87 static int tr_ff_cmp_tid_rp_realm(void *rp_req_arg, TR_NAME *val)
89 TID_REQ *req=talloc_get_type_abort(rp_req_arg, TID_REQ);
91 return 0==tr_name_cmp(val, req->rp_realm);
94 static TR_NAME *tr_ff_get_tid_rp_realm(void *rp_req_arg)
96 TID_REQ *req=talloc_get_type_abort(rp_req_arg, TID_REQ);
98 return tr_dup_name(req->rp_realm);
101 static int tr_ff_cmp_trp_info_type(void *inforec_arg, TR_NAME *val)
103 TRP_INFOREC *inforec=talloc_get_type_abort(inforec_arg, TRP_INFOREC);
110 /* nothing matches unknown */
111 if (inforec->type==TRP_INFOREC_TYPE_UNKNOWN)
114 valstr = tr_name_strdup(val); /* get this as an official null-terminated string */
115 val_type = trp_inforec_type_from_string(valstr);
118 return (val_type==inforec->type);
121 static TR_NAME *tr_ff_get_trp_info_type(void *inforec_arg)
123 TRP_INFOREC *inforec=talloc_get_type_abort(inforec_arg, TRP_INFOREC);
124 return tr_new_name(trp_inforec_type_to_string(inforec->type));
128 * Apply a filter to a target record or TID request.
130 * If one of the filter lines matches, out_action is set to the applicable action. If constraints
131 * is not NULL, the constraints from the matching filter line will be added to the constraint set
132 * *constraints, or to a new one if *constraints is NULL. In this case, TR_FILTER_MATCH will be
135 * If there is no match, returns TR_FILTER_NO_MATCH, out_action is undefined, and constraints
136 * will not be changed.
138 * @param target Record or request to which the filter is applied
139 * @param filt Filter to apply
140 * @param constraints Pointer to existing set of constraints (NULL if not tracking constraints)
141 * @param out_action Action to be carried out (output)
142 * @return TR_FILTER_MATCH or TR_FILTER_NO_MATCH
144 int tr_filter_apply(void *target,
146 TR_CONSTRAINT_SET **constraints,
147 TR_FILTER_ACTION *out_action)
149 unsigned int ii=0, jj=0;
150 int retval=TR_FILTER_NO_MATCH;
152 /* Default action is reject */
153 *out_action = TR_FILTER_ACTION_REJECT;
155 /* Validate filter */
156 if ((filt==NULL) || (filt->type==TR_FILTER_TYPE_UNKNOWN))
157 return TR_FILTER_NO_MATCH;
159 /* Step through filter lines looking for a match. If a line matches, retval
160 * will be set to TR_FILTER_MATCH, so stop then. */
161 for (ii=0, retval=TR_FILTER_NO_MATCH;
162 ii<TR_MAX_FILTER_LINES;
164 /* skip empty lines (these shouldn't really happen) */
165 if (filt->lines[ii]==NULL)
168 /* Assume we are going to succeed. If any specs fail to match, we'll set
169 * this to TR_FILTER_NO_MATCH. */
170 retval=TR_FILTER_MATCH;
171 for (jj=0; jj<TR_MAX_FILTER_SPECS; jj++) {
172 /* skip empty specs (these shouldn't really happen either) */
173 if (filt->lines[ii]->specs[jj]==NULL)
176 if (!tr_fspec_matches(filt->lines[ii]->specs[jj], filt->type, target)) {
177 retval=TR_FILTER_NO_MATCH; /* set this in case this is the last filter line */
178 break; /* give up on this filter line */
182 if (retval==TR_FILTER_MATCH)
186 if (retval==TR_FILTER_MATCH) {
187 /* Matched line ii. Grab its action and constraints. */
188 *out_action = filt->lines[ii]->action;
189 if (constraints!=NULL) {
190 /* if either constraint is missing, these are no-ops */
191 tr_constraint_add_to_set(constraints, filt->lines[ii]->realm_cons);
192 tr_constraint_add_to_set(constraints, filt->lines[ii]->domain_cons);
199 void tr_fspec_free(TR_FSPEC *fspec)
204 static int tr_fspec_destructor(void *obj)
206 TR_FSPEC *fspec = talloc_get_type_abort(obj, TR_FSPEC);
209 if (fspec->field != NULL)
210 tr_free_name(fspec->field);
211 for (ii=0; ii<TR_MAX_FILTER_SPEC_MATCHES; ii++) {
212 if (fspec->match[ii] != NULL)
213 tr_free_name(fspec->match[ii]);
218 TR_FSPEC *tr_fspec_new(TALLOC_CTX *mem_ctx)
220 TR_FSPEC *fspec = talloc(mem_ctx, TR_FSPEC);
225 for (ii=0; ii<TR_MAX_FILTER_SPEC_MATCHES; ii++)
226 fspec->match[ii] = NULL;
228 talloc_set_destructor((void *)fspec, tr_fspec_destructor);
233 void tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match)
236 for (ii=0; ii<TR_MAX_FILTER_SPEC_MATCHES; ii++) {
237 if (fspec->match[ii]==NULL) {
238 fspec->match[ii]=match;
242 /* TODO: handle case that adding the match failed */
245 /* returns 1 if the spec matches */
246 int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target)
248 struct tr_filter_field_entry *field=NULL;
255 /* Look up how to handle the requested field */
256 field = tr_filter_field_entry(ftype, fspec->field);
260 name=field->get(target);
261 for (ii=0; ii<TR_MAX_FILTER_SPEC_MATCHES; ii++) {
262 if (fspec->match[ii]!=NULL) {
263 if (tr_name_prefix_wildcard_match(name, fspec->match[ii]))
270 void tr_fline_free(TR_FLINE *fline)
275 TR_FLINE *tr_fline_new(TALLOC_CTX *mem_ctx)
277 TR_FLINE *fl = talloc(mem_ctx, TR_FLINE);
281 fl->action = TR_FILTER_ACTION_UNKNOWN;
282 fl->realm_cons = NULL;
283 fl->domain_cons = NULL;
284 for (ii = 0; ii < TR_MAX_FILTER_SPECS; ii++)
285 fl->specs[ii] = NULL;
290 TR_FILTER *tr_filter_new(TALLOC_CTX *mem_ctx)
292 TR_FILTER *f = talloc(mem_ctx, TR_FILTER);
296 f->type = TR_FILTER_TYPE_UNKNOWN;
297 for (ii = 0; ii < TR_MAX_FILTER_LINES; ii++)
303 void tr_filter_free(TR_FILTER *filt)
308 void tr_filter_set_type(TR_FILTER *filt, TR_FILTER_TYPE type)
313 TR_FILTER_TYPE tr_filter_get_type(TR_FILTER *filt)
319 * Check that a filter is valid, i.e., can be processed.
321 * @param filt Filter to verify
322 * @return 1 if the filter is valid, 0 otherwise
324 int tr_filter_validate(TR_FILTER *filt)
326 size_t ii=0, jj=0, kk=0;
331 /* check that we recognize the type */
333 case TR_FILTER_TYPE_TID_INBOUND:
334 case TR_FILTER_TYPE_TRP_INBOUND:
335 case TR_FILTER_TYPE_TRP_OUTBOUND:
339 return 0; /* if we get here, either TR_FILTER_TYPE_UNKNOWN or an invalid value was found */
341 for (ii=0; ii<TR_MAX_FILTER_LINES; ii++) {
342 if (filt->lines[ii]==NULL)
343 continue; /* an empty filter line is valid */
345 /* check that we recognize the action */
346 switch(filt->lines[ii]->action) {
347 case TR_FILTER_ACTION_ACCEPT:
348 case TR_FILTER_ACTION_REJECT:
352 /* if we get here, either TR_FILTER_ACTION_UNKNOWN or an invalid value was found */
356 for (jj=0; jj<TR_MAX_FILTER_SPECS; jj++) {
357 if (filt->lines[ii]->specs[jj]==NULL)
358 continue; /* an empty filter spec is valid */
360 if (!tr_filter_validate_spec_field(filt->type, filt->lines[ii]->specs[jj]))
363 /* check that at least one match is non-null */
364 for (kk=0; kk<TR_MAX_FILTER_SPEC_MATCHES; kk++) {
365 if (filt->lines[ii]->specs[jj]->match[kk]!=NULL)
368 if (kk==TR_MAX_FILTER_SPEC_MATCHES)
373 /* We ran the gauntlet. Success! */
377 int tr_filter_validate_spec_field(TR_FILTER_TYPE ftype, TR_FSPEC *fspec)
379 if ((fspec==NULL) || (tr_filter_field_entry(ftype, fspec->field)==NULL))
380 return 0; /* unknown field */
386 * Allocate a new filter set.
388 * @param mem_ctx Talloc context for the new set
389 * @return Pointer to new set, or null on error
391 TR_FILTER_SET *tr_filter_set_new(TALLOC_CTX *mem_ctx)
393 TR_FILTER_SET *set=talloc(mem_ctx, TR_FILTER_SET);
404 * @param fs Filter set to free
406 void tr_filter_set_free(TR_FILTER_SET *fs)
412 * Find the tail of the filter set linked list.
414 * @param set Set to find tail of
415 * @return Last element in the list
417 static TR_FILTER_SET *tr_filter_set_tail(TR_FILTER_SET *set)
425 * Add new filter to filter set.
427 * @param set Filter set
428 * @param new New filter to add
429 * @return 0 on success, nonzero on error
431 int tr_filter_set_add(TR_FILTER_SET *set, TR_FILTER *new)
433 TR_FILTER_SET *tail=NULL;
438 tail=tr_filter_set_tail(set);
439 tail->next=tr_filter_set_new(set);
440 if (tail->next==NULL)
445 talloc_steal(tail, new);
450 * Find a filter of a given type in the filter set. If there are multiple, returns the first one.
452 * @param set Filter set to search
453 * @param type Type of filter to find
454 * @return Borrowed pointer to the filter, or null if no filter of that type is found
456 TR_FILTER *tr_filter_set_get(TR_FILTER_SET *set, TR_FILTER_TYPE type)
458 TR_FILTER_SET *cur=set;
460 if ((cur->this != NULL) && (cur->this->type == type))
467 TR_FILTER_TYPE filter_type[]={TR_FILTER_TYPE_TID_INBOUND,
468 TR_FILTER_TYPE_TRP_INBOUND,
469 TR_FILTER_TYPE_TRP_OUTBOUND};
470 const char *filter_label[]={"tid_inbound",
473 size_t num_filter_types=sizeof(filter_type)/sizeof(filter_type[0]);
475 const char *tr_filter_type_to_string(TR_FILTER_TYPE ftype)
479 for (ii=0; ii<num_filter_types; ii++) {
480 if (ftype==filter_type[ii])
481 return filter_label[ii];
486 TR_FILTER_TYPE tr_filter_type_from_string(const char *s)
490 for(ii=0; ii<num_filter_types; ii++) {
491 if (0==strcmp(s, filter_label[ii]))
492 return filter_type[ii];
494 return TR_FILTER_TYPE_UNKNOWN;