1 #ifdef HAVE_CONFIG_H
2 #include "common.h"
3 #else
4 #include "common-static.h"
5 #endif
6 #include "c_icap/debug.h"
7 #include "c_icap/body.h"
8 #include "filters.h"
9 #include <errno.h>
10 
11 /*Array of srv_cf_profiles_t*/
12 ci_ptr_dyn_array_t *PROFILES = NULL;
13 
14 srv_cf_profile_t DEFAULT_PROFILE = { .name = "default", .access_list =  NULL, .actions = NULL, .filters = NULL, .replaceInfo = NULL};
15 
16 
srv_srv_cf_profile_search(const char * name)17 const srv_cf_profile_t *srv_srv_cf_profile_search(const char *name)
18 {
19     if (!PROFILES)
20         return NULL;
21     return (const srv_cf_profile_t *)ci_ptr_dyn_array_search(PROFILES, name);
22 }
23 
free_profile_step(void * data,const char * name,const void * value)24 static int free_profile_step(void *data, const char *name, const void *value)
25 {
26     int i;
27     srv_cf_action_cfg_t action;
28     srv_cf_profile_t *prof = (srv_cf_profile_t *)value;
29     ci_debug_printf(8, "srv_content_filtering: Releasing profile '%s'...\n", prof->name);
30     free(prof->name);
31     ci_access_entry_release(prof->access_list);
32     while(ci_list_pop(prof->actions, &action)) {
33         for(i = 0; action.replaceInfo && action.replaceInfo[i]; ++i)
34             free(action.replaceInfo[i]);
35         if (action.replaceInfo)
36             free(action.replaceInfo);
37     }
38 
39     free(prof);
40     return 0;
41 }
42 
srv_srv_cf_profiles_reset()43 void srv_srv_cf_profiles_reset()
44 {
45     if (!PROFILES)
46         return;
47 
48     ci_ptr_dyn_array_iterate(PROFILES, NULL, free_profile_step);
49     ci_ptr_dyn_array_destroy(PROFILES);
50     PROFILES = NULL;
51 }
52 
53 
54 struct checkProfileData {
55     ci_request_t *req;
56     const srv_cf_profile_t *prof;
57 };
58 
check_profile(void * data,const char * name,const void * value)59 static int check_profile(void *data, const char *name, const void *value)
60 {
61     struct checkProfileData *checkData = (struct checkProfileData *)data;
62     const srv_cf_profile_t *prof = (const srv_cf_profile_t *)value;
63     if (prof->access_list &&
64         (ci_access_entry_match_request(prof->access_list,
65                                        checkData->req) == CI_ACCESS_ALLOW)) {
66         ci_debug_printf(5, "url_check: profile %s matches!\n", prof->name);
67         checkData->prof = prof;
68         return 1;
69     }
70     return 0;
71 }
72 
srv_srv_cf_profile_select(ci_request_t * req)73 const srv_cf_profile_t *srv_srv_cf_profile_select(ci_request_t *req)
74 {
75     struct checkProfileData checkData;
76     checkData.req = req;
77     checkData.prof = NULL;
78     if (PROFILES) {
79         ci_ptr_dyn_array_iterate(PROFILES, &checkData, check_profile);
80         if (checkData.prof) {
81             ci_debug_printf(5, "url_check: profile %s matches!\n", checkData.prof->name);
82             return checkData.prof;
83         }
84     }
85 
86     ci_debug_printf(5, "url_check: Default profile selected!\n");
87     return &DEFAULT_PROFILE;
88 }
89 
profile_filter_add(srv_cf_profile_t * prof,const srv_cf_user_filter_t * filter,int action)90 static void profile_filter_add(srv_cf_profile_t *prof, const srv_cf_user_filter_t *filter, int action)
91 {
92 
93     srv_cf_filter_apply_t rp, *prp ;
94     if (prof->filters == NULL)
95         prof->filters = ci_list_create(32768, sizeof(srv_cf_filter_apply_t));
96     for (prp = ci_list_first(prof->filters); prp != NULL; prp = ci_list_next(prof->filters)) {
97 
98         if (prp->filter == filter) {
99             /*Already exist in list. Check if must marked as possible to replace text*/
100             if (action == CF_AC_REPLACE)
101                 prp->needReplaceParts = 1;
102             return;
103         }
104     }
105     rp.filter = filter;
106     rp.needReplaceParts = (action == CF_AC_REPLACE ? 1 : 0);
107     ci_list_push_back(prof->filters, &rp);
108 }
109 
srv_cf_cfg_profile(const char * directive,const char ** argv,void * setdata)110 int srv_cf_cfg_profile(const char *directive, const char **argv, void *setdata)
111 {
112     int action = CF_AC_NONE;
113     int scoreOperator = -1;
114     int score = 0;
115     int i, count;
116     const char *header = NULL;
117     const char *template = NULL;
118     srv_cf_profile_t *prof;
119     char **replace = NULL;
120 
121     if(!argv[0] || !argv[1] || !argv[2])
122         return 0;
123 
124     if ((action = srv_cf_action_parse(argv[1])) == CF_AC_NONE) {
125         ci_debug_printf(1, "Action  must be one of the 'block', 'allow', replace or 'addHeader'\n");
126         return 0;
127     }
128 
129     const srv_cf_user_filter_t *filter;
130     if (!(filter = srv_cf_action_score_parse(argv[2], &scoreOperator, &score))) {
131         /*Debug message exist inside srv_cf_filter_parse*/
132         return 0;
133     }
134 
135     if (action == CF_AC_ADD_HEADER) {
136         if (!argv[3]) {
137             ci_debug_printf(1, "Missing header definition for add_header action!\n");
138             return 0;
139         }
140         header = argv[3];
141     } else if (action == CF_AC_BLOCK && argv[3]) {
142         if (strncasecmp(argv[3], "template=", 9) == 0) {
143             template = argv[3]+9;
144         }
145     }else if (action == CF_AC_REPLACE && argv[3]) {
146         /*Count the replaceInfo arguments*/
147         for (i = 3, count = 0; argv[i] != NULL; ++i) {
148             if (strncasecmp(argv[i], "replaceInfo=", 12) == 0)
149                 ++count;
150         }
151         if (count) {
152             replace = malloc(sizeof(char *) * (count + 1));
153             for (i = 3, count = 0 ; argv[i] != NULL; ++i) {
154                 if (strncasecmp(argv[i], "replaceInfo=", 12) == 0) {
155                     replace[count] = strdup(argv[i]+12);
156                     ++count;
157                 }
158             }
159             replace[count] = NULL;
160         }
161     }
162 
163     if (!PROFILES) {
164         if (! (PROFILES = ci_ptr_dyn_array_new(4096))) {
165             ci_debug_printf(1, "srv_content_filtering: Error allocating memory for storing profiles!");
166             return 0;
167         }
168     }
169 
170     if (strcasecmp(argv[0], "default") == 0)
171         prof = &DEFAULT_PROFILE;
172     else if (!(prof = (srv_cf_profile_t *)ci_ptr_dyn_array_search(PROFILES, argv[0]))) {
173         prof = malloc(sizeof(srv_cf_profile_t));
174         ci_ptr_dyn_array_add(PROFILES, argv[0], prof);
175         prof->name = strdup(argv[0]);
176         prof->anyContentType = 0;
177         prof->maxBodyData = 0;
178         prof->access_list = NULL;
179         prof->actions = NULL;
180         prof->filters = NULL;
181         prof->replaceInfo = NULL;
182     }
183 
184     srv_cf_action_cfg_t actionEntry;
185     if (header) {
186         strncpy(actionEntry.header, header, sizeof(actionEntry.header));
187         actionEntry.header[sizeof(actionEntry.header) - 1] = '\0';
188     } else
189         actionEntry.header[0] = '\0';
190     actionEntry.action = action;
191     actionEntry.scoreOperator = scoreOperator;
192     actionEntry.score = score;
193     actionEntry.matchingFilter = filter;
194     actionEntry.replaceInfo = replace;
195     strncpy(actionEntry.template, ((template && template[0] != '\0') ? template : "BLOCK"), sizeof(actionEntry.template));
196     actionEntry.template[sizeof(actionEntry.template) - 1] = '\0';
197 
198     if (prof->actions == NULL)
199         prof->actions = ci_list_create(32768, sizeof(srv_cf_action_cfg_t));
200     ci_list_push_back(prof->actions, &actionEntry);
201 
202     profile_filter_add(prof, filter, action);
203 
204     if (prof->replaceInfo == NULL)
205         prof->replaceInfo = ci_list_create(1024, sizeof(const char *));
206     if (replace) {
207         for(i=0; replace[i] != NULL; ++i) /*we may store duplicates, but we do not care...*/
208             ci_list_push_back(prof->replaceInfo, &(replace[i]));
209     }
210 
211     ci_debug_printf(2,"\n");
212     return 1;
213 }
214 
srv_cf_cfg_action(const char * directive,const char ** argv,void * setdata)215 int srv_cf_cfg_action(const char *directive,const char **argv,void *setdata)
216 {
217     const char *newArgv[5];
218     if (!argv[0] || ! argv[1]) {
219         ci_debug_printf(1, "Missing action (block|allow|addHeader)\n");
220         return 0;
221     }
222 
223     newArgv[0] = "default";
224     newArgv[1] = argv[0];
225     newArgv[2] = argv[1];
226     newArgv[3] = argv[2] ? argv[2] : NULL;
227     newArgv[4] = NULL;
228 
229     return srv_cf_cfg_profile(directive, newArgv, setdata);
230 }
231 
232 
srv_cf_cfg_profile_access(const char * directive,const char ** argv,void * setdata)233 int srv_cf_cfg_profile_access(const char *directive, const char **argv, void *setdata)
234 {
235    srv_cf_profile_t *prof;
236    ci_access_entry_t *access_entry;
237    int argc, error;
238    const char *acl_spec_name;
239 
240    if(!argv[0] || !argv[1])
241     return 0;
242 
243    if (!PROFILES || !(prof = (srv_cf_profile_t *)ci_ptr_dyn_array_search(PROFILES, argv[0]))) {
244        ci_debug_printf(1, "srv_url_check: Error: Unknown profile %s!", argv[0]);
245        return 0;
246    }
247 
248    if ((access_entry = ci_access_entry_new(&(prof->access_list),
249 					   CI_ACCESS_ALLOW)) == NULL) {
250          ci_debug_printf(1, "srv_url_check: Error creating access list for cfg profiles!\n");
251          return 0;
252      }
253 
254    error = 0;
255    for (argc = 1; argv[argc]!= NULL; argc++) {
256        acl_spec_name = argv[argc];
257           /*TODO: check return type.....*/
258           if (!ci_access_entry_add_acl_by_name(access_entry, acl_spec_name)) {
259 	      ci_debug_printf(1,"srv_url_check: Error adding acl spec: %s in profile %s."
260 			        " Probably does not exist!\n",
261 			      acl_spec_name, prof->name);
262               error = 1;
263           }
264           else
265 	    ci_debug_printf(2,"\tAdding acl spec: %s in profile %s\n", acl_spec_name, prof->name);
266      }
267 
268      if (error)
269          return 0;
270 
271      return 1;
272 }
273 
srv_cf_cfg_profile_option(const char * directive,const char ** argv,void * setdata)274 int srv_cf_cfg_profile_option(const char *directive, const char **argv, void *setdata)
275 {
276     srv_cf_profile_t *prof;
277     char *e;
278     if(!argv[0] || !argv[1])
279         return 0;
280 
281     if (!PROFILES || !(prof = (srv_cf_profile_t *)ci_ptr_dyn_array_search(PROFILES, argv[0]))) {
282         ci_debug_printf(1, "srv_url_check: Error: Unknown profile %s!", argv[0]);
283         return 0;
284     }
285 
286     if (strcasecmp(argv[1], "AnyContentType") == 0)
287         prof->anyContentType = 1;
288     else if (strcasecmp(argv[1], "MaxBodyData") == 0) {
289         if (!argv[2]) {
290             ci_debug_printf(1, "srv_url_check: Error: missing value for 'MaxBodyData' option!");
291             return 0;
292         }
293 
294         errno = 0;
295         prof->maxBodyData = (int64_t)strtol(argv[2], &e, 10);
296         if (errno != 0 || e == argv[2]) {
297             ci_debug_printf(1, "srv_url_check: Error: expected integer value for 'MaxBodyData' option got: '%s'", argv[2]);
298             return 0;
299         }
300         if (prof->maxBodyData < 0)
301             prof->maxBodyData = 0;
302 
303         if (*e == 'k' || *e == 'K' )
304             prof->maxBodyData = prof->maxBodyData * 1024;
305         else if (*e == 'm' || *e == 'M' )
306             prof->maxBodyData = prof->maxBodyData * 1024 * 1024;
307     } else {
308         ci_debug_printf(1, "srv_url_check: Error: profile option '%s'!", argv[1]);
309         return 0;
310     }
311     return 1;
312 }
313