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