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