1 /*
2 * Copyright (C) 2004 Christos Tsantilas
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA.
18 */
19
20 #include "c-icap.h"
21 #include "common.h"
22 #include "request.h"
23 #include "cfg_param.h"
24 #include "debug.h"
25 #include "simple_api.h"
26 #include "acl.h"
27 #include "access.h"
28 #include "mem.h"
29 #include "filetype.h"
30 #include <ctype.h>
31 #include <time.h>
32
33 /*standard acl types */
34
35 /*Spec types:
36 username: user,
37 servicename: service
38 requet_type: type
39 port : port
40 src_ip: src
41 dst_ip: srvip
42 */
43
get_user(ci_request_t * req,char * param)44 void *get_user(ci_request_t *req, char *param)
45 {
46 return req->user;
47 }
48
get_service(ci_request_t * req,char * param)49 void *get_service(ci_request_t *req, char *param)
50 {
51 return req->service;
52 }
53
get_reqtype(ci_request_t * req,char * param)54 void *get_reqtype(ci_request_t *req, char *param)
55 {
56 return (void *)ci_method_string(req->type);
57 }
58
get_port(ci_request_t * req,char * param)59 void *get_port(ci_request_t *req, char *param)
60 {
61 return &req->connection->srvaddr.ci_sin_port;
62 }
63
get_client_ip(ci_request_t * req,char * param)64 void *get_client_ip(ci_request_t *req, char *param)
65 {
66 return &(req->connection->claddr);
67 }
68
get_srv_ip(ci_request_t * req,char * param)69 void *get_srv_ip(ci_request_t *req, char *param)
70 {
71 return &(req->connection->srvaddr);
72 }
73
get_http_client_ip(ci_request_t * req,char * param)74 void *get_http_client_ip(ci_request_t *req, char *param)
75 {
76 return (void *)ci_http_client_ip(req);
77 }
78
79 #if defined(USE_REGEX)
80 /*They are implemented at the bottom of this file ...*/
81 void *get_icap_header(ci_request_t *req, char *param);
82 void *get_icap_response_header(ci_request_t *req, char *param);
83 void *get_http_req_header(ci_request_t *req, char *param);
84 void *get_http_resp_header(ci_request_t *req, char *param);
85
86 void free_icap_header(ci_request_t *req,void *param);
87 void free_icap_response_header(ci_request_t *req, void *param);
88 void free_http_req_header(ci_request_t *req, void *param);
89 void free_http_resp_header(ci_request_t *req, void *param);
90
91 void *get_http_req_url(ci_request_t *req, char *param);
92 void free_http_req_url(ci_request_t *req, void *data);
93 void *get_http_req_line(ci_request_t *req, char *param);
94 void free_http_req_line(ci_request_t *req, void *data);
95 void *get_http_resp_line(ci_request_t *req, char *param);
96 void free_http_resp_line(ci_request_t *req, void *data);
97 #endif
98
99 void *get_http_req_method(ci_request_t *req, char *param);
100 void free_http_req_method(ci_request_t *req, void *param);
101
102 void *get_data_type(ci_request_t *req, char *param);
103 void free_data_type(ci_request_t *req,void *param);
104
105 ci_acl_type_t acl_user = {
106 "user",
107 get_user,
108 NULL,
109 &ci_str_ops
110 };
111
112 ci_acl_type_t acl_service = {
113 "service",
114 get_service,
115 NULL,
116 &ci_str_ops
117 };
118
119 ci_acl_type_t acl_req_type = {
120 "type",
121 get_reqtype,
122 NULL,
123 &ci_str_ops
124 };
125
126 ci_acl_type_t acl_tcp_port = {
127 "port",
128 get_port,
129 NULL,
130 &ci_int32_ops
131 };
132
133 ci_acl_type_t acl_tcp_src = {
134 "src",
135 get_client_ip,
136 NULL,
137 &ci_ip_sockaddr_ops
138 };
139
140 ci_acl_type_t acl_tcp_srvip = {
141 "srvip",
142 get_srv_ip,
143 NULL,
144 &ci_ip_sockaddr_ops
145 };
146
147 ci_acl_type_t acl_tcp_xclientip = {
148 "http_client_ip",
149 get_http_client_ip,
150 NULL,
151 &ci_ip_ops
152 };
153
154 #if defined(USE_REGEX)
155 ci_acl_type_t acl_icap_header = {
156 "icap_header",
157 get_icap_header,
158 free_icap_header,
159 &ci_regex_ops
160 };
161
162 ci_acl_type_t acl_icap_resp_header = {
163 "icap_resp_header",
164 get_icap_response_header,
165 free_icap_response_header,
166 &ci_regex_ops
167 };
168
169 ci_acl_type_t acl_http_req_header = {
170 "http_req_header",
171 get_http_req_header,
172 free_http_req_header,
173 &ci_regex_ops
174 };
175
176 ci_acl_type_t acl_http_resp_header = {
177 "http_resp_header",
178 get_http_resp_header,
179 free_http_resp_header,
180 &ci_regex_ops
181 };
182
183 ci_acl_type_t acl_http_req_url = {
184 "http_req_url",
185 get_http_req_url,
186 free_http_req_url,
187 &ci_regex_ops
188 };
189
190 ci_acl_type_t acl_http_req_line = {
191 "http_req_line",
192 get_http_req_line,
193 free_http_req_line,
194 &ci_regex_ops
195 };
196
197 ci_acl_type_t acl_http_resp_line = {
198 "http_resp_line",
199 get_http_resp_line,
200 free_http_resp_line,
201 &ci_regex_ops
202 };
203 #endif
204
205 ci_acl_type_t acl_http_req_method = {
206 "http_req_method",
207 get_http_req_method,
208 free_http_req_method,
209 &ci_str_ops
210 };
211
212 ci_acl_type_t acl_data_type = {
213 "data_type",
214 get_data_type,
215 free_data_type,
216 &ci_datatype_ops
217 };
218
219 struct acl_cmp_uint64_data {
220 uint64_t data;
221 int operator;
222 };
223
224 /**** Content-Length acl ****/
225
acl_cmp_uint64_dup(const char * str,ci_mem_allocator_t * allocator)226 void *acl_cmp_uint64_dup(const char *str, ci_mem_allocator_t *allocator)
227 {
228 return ci_uint64_ops.dup(str, allocator);
229 }
230
acl_cmp_uint64_equal(const void * key1,const void * key2)231 int acl_cmp_uint64_equal(const void *key1, const void *key2)
232 {
233 uint64_t k1 = *(uint64_t *)key1;
234 struct acl_cmp_uint64_data *data = (struct acl_cmp_uint64_data *)key2;
235 ci_debug_printf(8, "Acl content length check %llu %c %llu\n",
236 (long long int)data->data, data->operator == 1 ? '>' : data->operator == 2 ? '<' : '=', (long long int)k1);
237 if (data->operator == 1) { /* > */
238 return data->data > k1;
239 } else if (data->operator == 2) { /* < */
240 return data->data < k1;
241 } else { /* = */
242 return k1 == data->data;
243 }
244 }
245
acl_cmp_uint64_free(void * key,ci_mem_allocator_t * allocator)246 void acl_cmp_uint64_free(void *key, ci_mem_allocator_t *allocator)
247 {
248 ci_uint64_ops.free(key, allocator);
249 }
250
251 static const ci_type_ops_t acl_cmp_uint64_ops = {
252 acl_cmp_uint64_dup,
253 acl_cmp_uint64_free,
254 NULL, // compare, not used here
255 NULL, // length, not used here
256 acl_cmp_uint64_equal
257 };
258
259 void free_cmp_uint64_data(ci_request_t *req,void *param);
260 void *get_content_length(ci_request_t *req, char *param);
261 static ci_acl_type_t acl_content_length = {
262 "content_length",
263 get_content_length,
264 free_cmp_uint64_data,
265 &acl_cmp_uint64_ops
266 };
267
268 /**** Time acl ****/
269 /* Acl in the form:
270 [DAY[,DAY,[..]]][/][HH:MM-HH:MM]
271 DAY:
272 S - Sunday
273 M - Monday
274 T - Tuesday
275 W - Wednesday
276 H - Thursday
277 F - Friday
278 A - Saturday
279
280 acl time WorkingDays M,T,W,H,F/9:00-18:00
281 acl time ChildTime Saturday,Sunday/8:30-20:00
282 acl time ParentsTime 20:00-24:00 00:00-8:30
283 */
284
285 /*Acl ci_types_ops_t */
286 void *acl_time_dup(const char *str, ci_mem_allocator_t *allocator);
287 int acl_time_equal(const void *key1, const void *key2);
288 void acl_time_free(void *key, ci_mem_allocator_t *allocator);
289
290 static const ci_type_ops_t acl_time_ops = {
291 acl_time_dup,
292 acl_time_free,
293 NULL, // compare, not used here
294 NULL, // length, not used here
295 acl_time_equal
296 };
297
298 /*The acl type*/
299 void free_time_data(ci_request_t *req,void *param);
300 void *get_time_data(ci_request_t *req, char *param);
301 static ci_acl_type_t acl_time = {
302 "time",
303 get_time_data,
304 free_time_data,
305 &acl_time_ops
306 };
307
308 struct acl_time_data {
309 unsigned int days;
310 unsigned int start_time;
311 unsigned int end_time;
312 };
313
acl_time_dup(const char * str,ci_mem_allocator_t * allocator)314 void *acl_time_dup(const char *str, ci_mem_allocator_t *allocator)
315 {
316 struct {
317 const char *day;
318 int id;
319 } days[] = {
320 {"Sunday", 0},
321 {"Monday", 1},
322 {"Tuesday", 2},
323 {"Wednesday", 3},
324 {"Thursday", 4},
325 {"Friday", 5},
326 {"Saturday", 6},
327 {"S", 0},
328 {"M", 1},
329 {"T", 2},
330 {"W", 3},
331 {"H", 4},
332 {"F", 5},
333 {"A", 6},
334 {NULL, -1}
335 };
336 int h1, m1, h2, m2, i;
337 char *s, *e;
338 const char *error;
339 char buf[1024];
340 struct acl_time_data *tmd = allocator->alloc(allocator, sizeof(struct acl_time_data));
341 tmd->days = 0;
342 /*copy string in order to parse it*/
343 strncpy(buf, str, sizeof(buf));
344 buf[sizeof(buf) - 1] = '\0';
345 s = buf;
346 if (!isdigit(*s)) {
347 do {
348 if (*s == ',') ++s;
349 for (i = 0; days[i].day != NULL; ++i) {
350 if (strncasecmp(s, days[i].day, strlen(days[i].day)) == 0) {
351 tmd->days |= 1 << days[i].id;
352 break;
353 }
354 }
355 if (days[i].day == NULL) {
356 /*not found*/
357 error = s;
358 goto acl_time_dup_fail;
359 }
360 s += strlen(days[i].day);
361
362 } while (*s == ',');
363
364 if (*s != '/') {
365 error = s;
366 goto acl_time_dup_fail;
367 }
368 if (*s) ++s;
369 }
370
371 /* Time region specification*/
372 /*We are expecting hour region in the form 'HH:MM-HH:MM' */
373 if (!isdigit(*s)) {
374 error = s;
375 goto acl_time_dup_fail;
376 }
377
378 h1 = strtol(s, &e, 10);
379 if (h1 < 0 || h1 > 24) {
380 error = s;
381 goto acl_time_dup_fail;
382 }
383 if (*e != ':' || !isdigit(e[1])) {
384 error = e;
385 goto acl_time_dup_fail;
386 }
387 s = e + 1;
388 m1 = strtol(s, &e, 10);
389 if (m1 < 0 || m1 > 59) {
390 error = s;
391 goto acl_time_dup_fail;
392 }
393 if (*e != '-' || !isdigit(e[1])) {
394 error = e;
395 goto acl_time_dup_fail;
396 }
397
398 s = e + 1;
399 h2 = strtol(s, &e, 10);
400 if (h2 < 0 || h2 > 24) {
401 error = s;
402 goto acl_time_dup_fail;
403 }
404 if (*e != ':' || !isdigit(e[1])) {
405 error = e;
406 goto acl_time_dup_fail;
407 }
408 s = e + 1;
409 m2 = strtol(s, &e, 10);
410 if (m2 < 0 || m2 > 59) {
411 error = s;
412 goto acl_time_dup_fail;
413 }
414 tmd->start_time = h1 * 60 + m1;
415 tmd->end_time = h2 * 60 + m2;
416
417 if (tmd->start_time <= tmd->end_time) {
418 ci_debug_printf(5, "Acl time, adding days: %x, start time %d, end time: %d!\n", tmd->days, tmd->start_time, tmd->end_time);
419 return tmd;
420 }
421
422 ci_debug_printf(1, "Acl '%s': end time is smaller than the start time!\n", str);
423 error = str;
424
425 acl_time_dup_fail:
426 ci_debug_printf(1, "Failed to parse acl time: %s (error on pos '...%s')\n", str, error);
427 allocator->free(allocator, (void *)tmd);
428 return NULL;
429 }
430
acl_time_equal(const void * key1,const void * key2)431 int acl_time_equal(const void *key1, const void *key2)
432 {
433 struct acl_time_data *tmd_acl = (struct acl_time_data *)key1;
434 struct acl_time_data *tmd_request = (struct acl_time_data *)key2;
435 ci_debug_printf(9, "acl_time_equal(key1=%p, key2=%p)\n", key1, key2);
436 int matches = (tmd_acl->days & tmd_request->days) &&
437 (tmd_request->start_time >= tmd_acl->start_time) &&
438 (tmd_request->start_time <= tmd_acl->end_time);
439 ci_debug_printf(8, "acl_time_equal: %x/%d-%d <> %x/%d-%d -> %d\n",
440 tmd_acl->days, tmd_acl->start_time, tmd_acl->end_time,
441 tmd_request->days, tmd_request->start_time, tmd_request->end_time,
442 matches
443 );
444 return matches;
445 }
446
acl_time_free(void * tmd,ci_mem_allocator_t * allocator)447 void acl_time_free(void *tmd, ci_mem_allocator_t *allocator)
448 {
449 allocator->free(allocator, (void *)tmd);
450 }
451
free_time_data(ci_request_t * req,void * param)452 void free_time_data(ci_request_t *req,void *param)
453 {
454 /*Nothing to do*/
455 ci_debug_printf(5, "free_time_data(req=%p, param=%p)", req, param);
456 ci_buffer_free(param);
457 }
458
get_time_data(ci_request_t * req,char * param)459 void *get_time_data(ci_request_t *req, char *param)
460 {
461 struct acl_time_data *tmd_req = ci_buffer_alloc(sizeof(struct acl_time_data));
462 struct tm br_tm;
463 time_t tm;
464 time(&tm);
465 localtime_r(&tm, &br_tm);
466 tmd_req->days = 0;
467 tmd_req->days |= (1 << br_tm.tm_wday);
468 tmd_req->start_time = (br_tm.tm_hour) * 60 + br_tm.tm_min;
469 tmd_req->end_time = 0;
470 return (void *)tmd_req;
471 }
472
473
474 /********************************************************************************/
475 /* ci_access_entry api functions */
476
ci_access_entry_new(ci_access_entry_t ** list,int type)477 ci_access_entry_t *ci_access_entry_new(ci_access_entry_t **list, int type)
478 {
479 ci_access_entry_t *access_entry, *cur;
480
481 if (list == NULL)
482 return NULL;
483
484 if (!(access_entry = malloc(sizeof(ci_access_entry_t))))
485 return NULL;
486
487 access_entry->type = type;
488 access_entry->spec_list = NULL;
489 access_entry->next = NULL;
490
491 if (*list == NULL) {
492 *list = access_entry;
493 } else {
494 cur = *list;
495 while (cur->next != NULL)
496 cur = cur->next;
497 cur->next = access_entry;
498 }
499 return access_entry;
500 }
501
ci_access_entry_release(ci_access_entry_t * list)502 void ci_access_entry_release(ci_access_entry_t *list)
503 {
504 ci_access_entry_t *access_entry;
505 ci_specs_list_t *spec_list, *cur;
506 if (!list)
507 return;
508
509 while (list) {
510 access_entry = list;
511 list = list->next;
512 spec_list = access_entry->spec_list;
513
514 while (spec_list) {
515 cur = spec_list;
516 spec_list = spec_list->next;
517 free(cur);
518 }
519 free(access_entry);
520 }
521
522 }
523
ci_access_entry_add_acl(ci_access_entry_t * access_entry,const ci_acl_spec_t * acl,int negate)524 const ci_acl_spec_t *ci_access_entry_add_acl(ci_access_entry_t *access_entry, const ci_acl_spec_t *acl, int negate)
525 {
526 struct ci_specs_list *spec_list,*spec_entry;
527 if (access_entry == NULL)
528 return NULL;
529
530 spec_entry = malloc(sizeof(struct ci_specs_list));
531 if (spec_entry == NULL)
532 return NULL;
533
534 spec_entry->next = NULL;
535 spec_entry->negate = negate;
536 spec_entry->spec = acl;
537 if (access_entry->spec_list == NULL) {
538 access_entry->spec_list = spec_entry;
539 } else {
540 spec_list = access_entry->spec_list;
541 while (spec_list->next != NULL)
542 spec_list = spec_list->next;
543 spec_list->next = spec_entry;
544 }
545 return acl;
546 }
547
ci_access_entry_add_acl_by_name(ci_access_entry_t * access_entry,const char * acl_name)548 int ci_access_entry_add_acl_by_name(ci_access_entry_t *access_entry, const char *acl_name)
549 {
550 const ci_acl_spec_t *acl;
551 int negate = 0;
552 if (acl_name[0] == '!') {
553 negate = 1;
554 acl_name = acl_name + 1;
555 }
556 acl = ci_acl_search(acl_name);
557 if (!acl) {
558 ci_debug_printf(1, "The acl spec %s does not exists!\n", acl_name);
559 return 0;
560 }
561 if (ci_access_entry_add_acl(access_entry, acl, negate) == NULL) {
562 ci_debug_printf(1, "Error adding acl spec %s to the access list!\n", acl_name);
563 return 0;
564 }
565 return 1;
566 }
567
568 /*********************************************************************************/
569 /*ci_acl_spec functions */
570
ci_acl_spec_new(const char * name,const char * type,const char * param,struct ci_acl_type_list * list,ci_acl_spec_t ** spec_list)571 ci_acl_spec_t * ci_acl_spec_new(const char *name, const char *type, const char *param, struct ci_acl_type_list *list, ci_acl_spec_t **spec_list)
572 {
573 ci_acl_spec_t *spec,*cur;
574 const ci_acl_type_t *acl_type;
575 acl_type = ci_acl_typelist_search(list, type);
576 if (!acl_type)
577 return NULL;
578
579 if (!(spec = malloc(sizeof( ci_acl_spec_t))))
580 return NULL;
581
582 strncpy(spec->name, name, MAX_NAME_LEN);
583 spec->name[MAX_NAME_LEN] = '\0';
584 if (param) {
585 if (!(spec->parameter = strdup(param))) {
586 free(spec);
587 return NULL;
588 }
589 } else
590 spec->parameter = NULL;
591 spec->type = acl_type;
592 spec->data = NULL;
593 spec->next = NULL;
594
595 if (spec_list != NULL) {
596 if (*spec_list != NULL) {
597 cur = *spec_list;
598 while (cur->next != NULL)
599 cur = cur->next;
600 cur->next = spec;
601 } else
602 *spec_list = spec;
603 }
604 return spec;
605 }
606
ci_acl_spec_new_data(ci_acl_spec_t * spec,const char * val)607 ci_acl_data_t *ci_acl_spec_new_data(ci_acl_spec_t *spec, const char *val)
608 {
609 ci_acl_data_t *new_data, *list;
610 const ci_type_ops_t *ops;
611 void *data;
612
613 if (!spec)
614 return NULL;
615
616 ops = spec->type->type;
617 data = ops->dup(val, default_allocator);
618 if (!data)
619 return NULL;
620
621 new_data = malloc(sizeof(ci_acl_data_t));
622 if (!new_data) {
623 ops->free(data, default_allocator);
624 return NULL;
625 }
626 new_data->data = data;
627 new_data->next = NULL;
628 if ((list = spec->data) != NULL) {
629 while (list->next != NULL)
630 list = list->next;
631 list->next = new_data;
632 } else
633 spec->data = new_data;
634 return new_data;
635 }
636
ci_acl_spec_search(ci_acl_spec_t * list,const char * name)637 ci_acl_spec_t *ci_acl_spec_search(ci_acl_spec_t *list, const char *name)
638 {
639 ci_acl_spec_t *spec;
640 ci_debug_printf(9,"In search specs list %p,name %s\n", list, name);
641 if (!list || !name)
642 return NULL;
643 spec = list;
644 while (spec != NULL) {
645 ci_debug_printf(9,"Checking name:%s with specname %s\n", name, spec->name);
646 if (strcmp(spec->name, name) == 0 ) {
647 return spec;
648 }
649 spec = spec->next;
650 }
651 return NULL;
652 }
653
654
ci_acl_spec_release(ci_acl_spec_t * cur)655 void ci_acl_spec_release(ci_acl_spec_t *cur)
656 {
657 ci_acl_data_t *dhead, *dtmp;
658 const ci_type_ops_t *ops;
659 dhead = cur->data;
660 ops = cur->type->type;
661 while (dhead) {
662 dtmp = dhead;
663 dhead = dhead->next;
664 ops->free(dtmp->data, default_allocator);
665 free(dtmp);
666 }
667 }
668
ci_acl_spec_list_release(ci_acl_spec_t * spec)669 void ci_acl_spec_list_release(ci_acl_spec_t *spec)
670 {
671 ci_acl_spec_t *cur;
672 while (spec) {
673 cur = spec;
674 spec = spec->next;
675 ci_acl_spec_release(cur);
676 }
677 }
678
679
680 /*******************************************************************/
681 /* ci_acl_type functions */
682 #define STEP 32
683
ci_acl_typelist_init(struct ci_acl_type_list * list)684 int ci_acl_typelist_init(struct ci_acl_type_list *list)
685 {
686 list->acl_type_list = malloc(STEP*sizeof(ci_acl_type_t));
687 list->acl_type_list_size = STEP;
688 list->acl_type_list_num = 0;
689 return 1;
690 }
691
ci_acl_typelist_destroy(struct ci_acl_type_list * list)692 void ci_acl_typelist_destroy(struct ci_acl_type_list *list)
693 {
694 free(list->acl_type_list);
695 list->acl_type_list = NULL;
696 list->acl_type_list_size = 0;
697 list->acl_type_list_num = 0;
698 }
699
ci_acl_typelist_add(struct ci_acl_type_list * list,const ci_acl_type_t * type)700 int ci_acl_typelist_add(struct ci_acl_type_list *list, const ci_acl_type_t *type)
701 {
702 ci_acl_type_t *cur;
703 ci_acl_type_t *nl = NULL;
704
705 if (!type->name)
706 return 0;
707
708 if (ci_acl_typelist_search(list, type->name) != NULL) {
709 ci_debug_printf(3, "The acl type %s already defined\n", type->name);
710 return 0;
711 }
712
713 if (list->acl_type_list_num == list->acl_type_list_size) {
714 list->acl_type_list_size += STEP;
715 nl = realloc((void *)list->acl_type_list,
716 list->acl_type_list_size*sizeof(ci_acl_type_t));
717 if (!nl) {
718 ci_debug_printf(1, "Failed to allocate more space for new ci_acl_typr_t\n");
719 return 0;
720 }
721 list->acl_type_list = nl;
722 }
723
724 cur = &(list->acl_type_list[list->acl_type_list_num]);
725 strncpy(cur->name, type->name, MAX_NAME_LEN);
726 cur->name[MAX_NAME_LEN] = '\0';
727 cur->type = type->type;
728 cur->get_test_data = type->get_test_data;
729 cur->free_test_data = type->free_test_data;
730 list->acl_type_list_num++;
731 return 1;
732 }
733
ci_acl_typelist_search(struct ci_acl_type_list * list,const char * name)734 const ci_acl_type_t *ci_acl_typelist_search(struct ci_acl_type_list *list,const char *name)
735 {
736 int i;
737 for (i = 0; i < list->acl_type_list_num; i++) {
738 if (strcmp(list->acl_type_list[i].name,name) == 0)
739 return (const ci_acl_type_t *)&list->acl_type_list[i];
740 }
741 return NULL;
742 }
743
ci_acl_typelist_release(struct ci_acl_type_list * list)744 int ci_acl_typelist_release(struct ci_acl_type_list *list)
745 {
746 free(list->acl_type_list);
747 list->acl_type_list_size = 0;
748 list->acl_type_list_num = 0;
749 return 1;
750 }
751
ci_acl_typelist_reset(struct ci_acl_type_list * list)752 int ci_acl_typelist_reset(struct ci_acl_type_list *list)
753 {
754 list->acl_type_list_num = 0;
755 return 1;
756 }
757
758
759
760 /*********************************************************************************/
761
spec_data_check(const ci_acl_spec_t * spec,const void * req_raw_data)762 int spec_data_check(const ci_acl_spec_t *spec, const void *req_raw_data)
763 {
764 // int (*comp)(void *req_spec, void *acl_spec);
765 struct ci_acl_data *spec_data = spec->data;
766 const ci_type_ops_t *ops = spec->type->type;
767
768 ci_debug_printf(9,"Check request with ci_acl_spec_t:%s\n", spec->name);
769 while (spec_data != NULL) {
770 if (ops->equal(spec_data->data, (void *)req_raw_data)) {
771 ci_debug_printf(9,"The ci_acl_spec_t:%s matches\n", spec->name);
772 return 1;
773 }
774 spec_data = spec_data->next;
775 }
776 return 0;
777 }
778
request_match_specslist(ci_request_t * req,const struct ci_specs_list * spec_list)779 int request_match_specslist(ci_request_t *req, const struct ci_specs_list *spec_list)
780 {
781 const ci_acl_spec_t *spec;
782 const ci_acl_type_t *type;
783 int ret, negate, check_result;
784 void *test_data;
785
786 ret = 1;
787 while (spec_list != NULL) {
788 spec = spec_list->spec;
789 negate = spec_list->negate;
790 type = spec->type;
791 test_data = type->get_test_data(req, spec->parameter);
792 if (!test_data) {
793 ci_debug_printf(9,"No data to test for %s/%s, ignore\n", type->name, spec->parameter);
794 return 0;
795 }
796
797 check_result = spec_data_check(spec, test_data);
798 if (check_result == 0 && negate == 0)
799 ret = 0;
800 else if (check_result != 0 && negate != 0)
801 ret = 0;
802
803 if (type->free_test_data)
804 type->free_test_data(req, test_data);
805
806 if (ret == 0)
807 return 0;
808
809 spec_list = spec_list->next;
810 }
811 return 1;
812 }
813
ci_access_entry_match_request(ci_access_entry_t * access_entry,ci_request_t * req)814 int ci_access_entry_match_request(ci_access_entry_t *access_entry, ci_request_t *req)
815 {
816 struct ci_specs_list *spec_list;
817
818 if (!access_entry)
819 return CI_ACCESS_ALLOW;
820
821 while (access_entry) {
822 ci_debug_printf(9,"Check request with an access entry\n");
823 spec_list = access_entry->spec_list;
824 if (spec_list && spec_list->spec && request_match_specslist(req, spec_list))
825 return access_entry->type;
826
827 access_entry = access_entry->next;
828 }
829 return CI_ACCESS_UNKNOWN;
830 }
831
832
833 /**********************************************************************************/
834 /* acl library functions */
835
836 static struct ci_acl_type_list types_list;
837 static struct ci_acl_spec *specs_list;
838
acl_load_defaults()839 static int acl_load_defaults()
840 {
841 ci_acl_typelist_add(&types_list, &acl_tcp_port);
842 ci_acl_typelist_add(&types_list, &acl_service);
843 ci_acl_typelist_add(&types_list, &acl_req_type);
844 ci_acl_typelist_add(&types_list, &acl_user);
845 ci_acl_typelist_add(&types_list, &acl_tcp_src);
846 ci_acl_typelist_add(&types_list, &acl_tcp_srvip);
847 #if defined(USE_REGEX)
848 ci_acl_typelist_add(&types_list, &acl_icap_header);
849 ci_acl_typelist_add(&types_list, &acl_icap_resp_header);
850 ci_acl_typelist_add(&types_list, &acl_http_req_header);
851 ci_acl_typelist_add(&types_list, &acl_http_resp_header);
852 ci_acl_typelist_add(&types_list, &acl_http_req_url);
853 ci_acl_typelist_add(&types_list, &acl_http_req_line);
854 ci_acl_typelist_add(&types_list, &acl_http_resp_line);
855 #endif
856 ci_acl_typelist_add(&types_list, &acl_http_req_method);
857 ci_acl_typelist_add(&types_list, &acl_data_type);
858 ci_acl_typelist_add(&types_list, &acl_content_length);
859 ci_acl_typelist_add(&types_list, &acl_time);
860 ci_acl_typelist_add(&types_list, &acl_tcp_xclientip);
861
862 return 1;
863 }
864
ci_acl_init()865 void ci_acl_init()
866 {
867 ci_acl_typelist_init(&types_list);
868 acl_load_defaults();
869 specs_list = NULL;
870 }
871
ci_acl_reset()872 void ci_acl_reset()
873 {
874 ci_acl_spec_list_release(specs_list);
875 specs_list = NULL;
876 ci_acl_typelist_reset(&types_list);
877 acl_load_defaults();
878 }
879
ci_acl_destroy()880 void ci_acl_destroy()
881 {
882 ci_acl_typelist_destroy(&types_list);
883 }
884
ci_acl_search(const char * name)885 const ci_acl_spec_t *ci_acl_search(const char *name)
886 {
887 return (const ci_acl_spec_t *)ci_acl_spec_search(specs_list, name);
888 }
889
ci_acl_type_search(const char * name)890 const ci_acl_type_t *ci_acl_type_search(const char *name)
891 {
892 return ci_acl_typelist_search(&types_list, name);
893 }
894
ci_acl_type_add(const ci_acl_type_t * type)895 int ci_acl_type_add(const ci_acl_type_t *type)
896 {
897 return ci_acl_typelist_add(&types_list, type);
898 }
899
ci_acl_add_data(const char * name,const char * type,const char * data)900 int ci_acl_add_data(const char *name, const char *type, const char *data)
901 {
902 ci_acl_spec_t *spec;
903 const ci_acl_type_t *spec_type;
904 char *s, *param = NULL, *acl_type;
905
906 acl_type = strdup(type);
907 if (!acl_type) {
908 ci_debug_printf(1, "cfg_acl_add: error strduping!\n");
909 return 0;
910 }
911
912 s = acl_type;
913 if ((s = strchr(s,'{')) != NULL) {
914 *s = '\0';
915 param = s+1;
916 if ((s = strchr(param,'}')) != NULL)
917 *s = '\0';
918 }
919
920 if ((spec = ci_acl_spec_search(specs_list, name)) != NULL) {
921 spec_type = ci_acl_type_search(acl_type);
922 if (spec_type != spec->type) {
923 ci_debug_printf(1, "The acl type:%s does not match with type of existing acl \"%s\"",
924 acl_type, name);
925 free(acl_type);
926 return 0;
927 }
928 } else {
929 spec = ci_acl_spec_new(name, acl_type, param, &types_list, &specs_list);
930 }
931 free(acl_type);
932
933 if (!spec) {
934 ci_debug_printf(1, "Error in acl:%s! Maybe the acl type \"%s\" does not exists!\n",
935 name, type);
936 return 0;
937 }
938 ci_acl_spec_new_data(spec, data);
939
940 return 1;
941 }
942
943 /******************************************************/
944 /* Some acl_type methods implementation */
945 #if defined(USE_REGEX)
946
get_header(ci_headers_list_t * headers,char * head)947 const char *get_header(ci_headers_list_t *headers, char *head)
948 {
949 const char *val;
950 char *buf;
951 size_t value_size = 0;
952
953 if (!headers || !head)
954 return NULL;
955
956 if (!(val = ci_headers_value2(headers, head, &value_size)))
957 return NULL;
958
959 if (!headers->packed) /*The headers are not packed, so it is NULL terminated*/
960 return val;
961
962 /*assume that an 8k buffer is enough for a header value*/
963 if (!(buf = ci_buffer_alloc(value_size + 1)))
964 return NULL;
965
966 memcpy(buf, val, value_size);
967 buf[value_size] = '\0';
968
969 return buf;
970 }
971
release_header_value(ci_headers_list_t * headers,char * head)972 void release_header_value(ci_headers_list_t *headers, char *head)
973 {
974 if (headers && headers->packed && head) /*The headers are packed, we have allocated buffer*/
975 ci_buffer_free(head);
976 }
977
get_icap_header(ci_request_t * req,char * param)978 void *get_icap_header(ci_request_t *req, char *param)
979 {
980 ci_headers_list_t *heads;
981 heads = req->request_header;
982 return (void *)get_header(heads, param);
983 }
984
free_icap_header(ci_request_t * req,void * param)985 void free_icap_header(ci_request_t *req, void *param)
986 {
987 ci_headers_list_t *heads;
988 heads = req->request_header;
989 release_header_value(heads, param);
990 }
991
get_icap_response_header(ci_request_t * req,char * param)992 void *get_icap_response_header(ci_request_t *req, char *param)
993 {
994 ci_headers_list_t *heads;
995 heads = req->response_header;
996 return (void *)get_header(heads, param);
997 }
998
free_icap_response_header(ci_request_t * req,void * param)999 void free_icap_response_header(ci_request_t *req, void *param)
1000 {
1001 ci_headers_list_t *heads;
1002 heads = req->response_header;
1003 release_header_value(heads, param);
1004 }
1005
get_http_req_header(ci_request_t * req,char * param)1006 void *get_http_req_header(ci_request_t *req, char *param)
1007 {
1008 ci_headers_list_t *heads;
1009 heads = ci_http_request_headers(req);
1010 return (void *)get_header(heads, param);
1011 }
free_http_req_header(ci_request_t * req,void * param)1012 void free_http_req_header(ci_request_t *req, void *param)
1013 {
1014 ci_headers_list_t *heads;
1015 heads = ci_http_request_headers(req);
1016 release_header_value(heads, param);
1017 }
1018
get_http_resp_header(ci_request_t * req,char * param)1019 void *get_http_resp_header(ci_request_t *req, char *param)
1020 {
1021 ci_headers_list_t *heads;
1022 heads = ci_http_response_headers(req);
1023 return (void *)get_header(heads, param);
1024 }
1025
free_http_resp_header(ci_request_t * req,void * param)1026 void free_http_resp_header(ci_request_t *req, void *param)
1027 {
1028 ci_headers_list_t *heads;
1029 heads = ci_http_response_headers(req);
1030 release_header_value(heads, param);
1031 }
1032
get_http_req_url(ci_request_t * req,char * param)1033 void *get_http_req_url(ci_request_t *req, char *param)
1034 {
1035 char *buf;
1036 ci_headers_list_t *heads;
1037 heads = ci_http_request_headers(req);
1038 if (!heads)
1039 return NULL;
1040 buf = ci_buffer_alloc(8192);
1041 ci_http_request_url(req, buf, 8192);
1042 return buf;
1043 }
free_http_req_url(ci_request_t * req,void * data)1044 void free_http_req_url(ci_request_t *req, void *data)
1045 {
1046 ci_buffer_free((char *)data);
1047 }
1048
get_http_req_line(ci_request_t * req,char * param)1049 void *get_http_req_line(ci_request_t *req, char *param)
1050 {
1051 ci_headers_list_t *heads;
1052 size_t first_line_size;
1053 const char *first_line;
1054 char *buf;
1055 heads = ci_http_request_headers(req);
1056 if (!heads)
1057 return NULL;
1058
1059 first_line = ci_headers_first_line2(heads, &first_line_size);
1060
1061 if (!first_line || first_line_size == 0)
1062 return NULL;
1063
1064 if (!heads->packed) /*The headers are not packed, so it is NULL terminated*/
1065 return (void *)first_line;
1066
1067 buf = ci_buffer_alloc(first_line_size + 1);
1068 memcpy(buf, first_line, first_line_size);
1069 buf[first_line_size] = '\0';
1070 return buf;
1071 }
1072
free_http_req_line(ci_request_t * req,void * data)1073 void free_http_req_line(ci_request_t *req, void *data)
1074 {
1075 ci_headers_list_t *heads;
1076 heads = ci_http_request_headers(req);
1077 if (heads->packed)
1078 ci_buffer_free(data);
1079 }
1080
get_http_resp_line(ci_request_t * req,char * param)1081 void *get_http_resp_line(ci_request_t *req, char *param)
1082 {
1083 size_t first_line_size;
1084 const char *first_line;
1085 char *buf;
1086 ci_headers_list_t *heads;
1087 heads = ci_http_response_headers(req);
1088 if (!heads)
1089 return NULL;
1090
1091 first_line = ci_headers_first_line2(heads, &first_line_size);
1092
1093 if (!first_line || first_line_size == 0)
1094 return NULL;
1095
1096 if (!heads->packed) /*The headers are not packed, so it is NULL terminated*/
1097 return (void *)first_line;
1098
1099 buf = ci_buffer_alloc(first_line_size + 1);
1100 memcpy(buf, first_line, first_line_size);
1101 buf[first_line_size] = '\0';
1102 return buf;
1103 }
1104
free_http_resp_line(ci_request_t * req,void * data)1105 void free_http_resp_line(ci_request_t *req, void *data)
1106 {
1107 ci_headers_list_t *heads;
1108 heads = ci_http_response_headers(req);
1109 if (heads->packed)
1110 ci_buffer_free(data);
1111 }
1112 #endif
1113
get_http_req_method(ci_request_t * req,char * param)1114 void *get_http_req_method(ci_request_t *req, char *param)
1115 {
1116 ci_headers_list_t *heads;
1117 size_t found_size;
1118 const char *first_line, *e, *eol;
1119 char *buf;
1120 heads = ci_http_request_headers(req);
1121 if (!heads)
1122 return NULL;
1123
1124 first_line = ci_headers_first_line2(heads, &found_size);
1125 if (!first_line || found_size == 0)
1126 return NULL;
1127 eol = first_line + found_size;
1128
1129 for (e = first_line; e < eol && !isspace(*e); e++);
1130 if (e == eol) /*No method found*/
1131 return NULL;
1132 found_size = e - first_line;
1133 if ((buf = ci_buffer_alloc(found_size + 1))) {
1134 memcpy(buf, first_line, found_size);
1135 buf[found_size] = '\0';
1136 }
1137 return buf;
1138 }
1139
free_http_req_method(ci_request_t * req,void * data)1140 void free_http_req_method(ci_request_t *req, void *data)
1141 {
1142 if (data)
1143 ci_buffer_free(data);
1144 }
1145
get_data_type(ci_request_t * req,char * param)1146 void *get_data_type(ci_request_t *req, char *param)
1147 {
1148 int type, isenc;
1149 int *ret_type;
1150 type = ci_magic_req_data_type(req, &isenc);
1151 if (type < 0)
1152 return NULL;
1153
1154 ret_type = malloc(sizeof(int));
1155 if (!ret_type)
1156 return NULL;
1157
1158 *ret_type = type;
1159 return (void *)ret_type;
1160 }
1161
free_data_type(ci_request_t * req,void * param)1162 void free_data_type(ci_request_t *req,void *param)
1163 {
1164 free(param);
1165 }
1166
get_content_length(ci_request_t * req,char * param)1167 void *get_content_length(ci_request_t *req, char *param)
1168 {
1169 struct acl_cmp_uint64_data *clen_p = (struct acl_cmp_uint64_data *)ci_buffer_alloc(sizeof(struct acl_cmp_uint64_data));
1170 ci_off_t clen = ci_http_content_length(req);
1171 if (clen < 0)
1172 return NULL;
1173 clen_p->data = (uint64_t)clen;
1174 if (param[0] == '=') {
1175 clen_p->operator = 0;
1176 } else if (param[0] == '>') {
1177 clen_p->operator = 1;
1178 } else if (param[0] == '<') {
1179 clen_p->operator = 2;
1180 }
1181 return clen_p;
1182 }
1183
free_cmp_uint64_data(ci_request_t * req,void * param)1184 void free_cmp_uint64_data(ci_request_t *req, void *param)
1185 {
1186 ci_buffer_free(param);
1187 }
1188
1189