wolfSSL: Use LIBWOLFSSL_VERSION_HEX to decide whether or not to use WOLFSSL_X509_V_OK
[privoxy.git] / client-tags.c
1 /*********************************************************************
2  *
3  * File        :  $Source: /cvsroot/ijbswa/current/client-tags.c,v $
4  *
5  * Purpose     :  Functions related to client-specific tags.
6  *
7  * Copyright   :  Copyright (C) 2016-2017 Fabian Keil <fk@fabiankeil.de>
8  *
9  *                This program is free software; you can redistribute it
10  *                and/or modify it under the terms of the GNU General
11  *                Public License as published by the Free Software
12  *                Foundation; either version 2 of the License, or (at
13  *                your option) any later version.
14  *
15  *                This program is distributed in the hope that it will
16  *                be useful, but WITHOUT ANY WARRANTY; without even the
17  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
18  *                PARTICULAR PURPOSE.  See the GNU General Public
19  *                License for more details.
20  *
21  *                The GNU General Public License should be included with
22  *                this file.  If not, you can view it at
23  *                http://www.gnu.org/copyleft/gpl.html
24  *                or write to the Free Software Foundation, Inc., 59
25  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  *
27  **********************************************************************/
28
29 #include "config.h"
30
31 #ifdef FEATURE_CLIENT_TAGS
32
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <assert.h>
39
40 #include "project.h"
41 #include "list.h"
42 #include "jcc.h"
43 #include "miscutil.h"
44 #include "errlog.h"
45 #include "parsers.h"
46 #include "urlmatch.h"
47
48 struct client_specific_tag
49 {
50    char *name;
51
52    time_t end_of_life;
53
54    struct client_specific_tag *next;
55    struct client_specific_tag *prev;
56 };
57
58 /**
59  * This struct represents tags that have been requested by clients
60  */
61 struct requested_tags
62 {
63    char *client; /**< The IP address of the client that requested the tag */
64
65    /**< List of tags the client requested .... */
66    struct client_specific_tag *tags;
67
68    struct requested_tags *next;
69    struct requested_tags *prev;
70 };
71
72 struct requested_tags *requested_tags;
73 static void remove_tag_for_client(const char *client_address, const char *tag);
74
75 /*********************************************************************
76  *
77  * Function    :  validate_tag_list
78  *
79  * Description :  Validates the given tag list
80  *
81  * Parameters  :
82  *          1  :  enabled_tags = The tags to validate
83  *
84  * Returns     :  void
85  *
86  *********************************************************************/
87 static void validate_tag_list(struct client_specific_tag *enabled_tags)
88 {
89    while (enabled_tags != NULL)
90    {
91       if (enabled_tags->name == NULL)
92       {
93          assert(enabled_tags->name != NULL);
94          log_error(LOG_LEVEL_FATAL, "validate_tag_list(): Tag without name detected");
95       }
96       if (enabled_tags->next != NULL)
97       {
98          if (enabled_tags->next->prev != enabled_tags)
99          {
100             assert(enabled_tags->next->prev == enabled_tags);
101             log_error(LOG_LEVEL_FATAL, "validate_tag_list(): Invalid backlink detected");
102          }
103       }
104       enabled_tags = enabled_tags->next;
105    }
106 }
107
108 /*********************************************************************
109  *
110  * Function    :  validate_requested_tags
111  *
112  * Description :  Validates the requested_tags list
113  *
114  * Parameters  : N/A
115  *
116  * Returns     :  void
117  *
118  *********************************************************************/
119 static jb_err validate_requested_tags()
120 {
121    struct requested_tags *requested_tag;
122
123    for (requested_tag = requested_tags; requested_tag != NULL;
124         requested_tag = requested_tag->next)
125    {
126       if (requested_tag->client == NULL)
127       {
128          assert(requested_tag->client != NULL);
129          log_error(LOG_LEVEL_FATAL, "validate_tag_list(): Client not registered");
130       }
131       validate_tag_list(requested_tag->tags);
132       if (requested_tag->next != NULL)
133       {
134          if (requested_tag->next->prev != requested_tag)
135          {
136             assert(requested_tag->next->prev == requested_tag);
137             log_error(LOG_LEVEL_FATAL, "validate_requested_tags(): Invalid backlink detected");
138          }
139       }
140    }
141
142    return TRUE;
143 }
144
145
146 /*********************************************************************
147  *
148  * Function    :  get_client_specific_tag
149  *
150  * Description :  Returns the data for a client-specific-tag specified
151  *                by name.
152  *
153  * Parameters  :
154  *          1  :  tag_list = The tag list to check
155  *          2  :  name =     The tag name to look up
156  *
157  * Returns     :  Pointer to tag structure or NULL on error.
158  *
159  *********************************************************************/
160 static struct client_tag_spec *get_client_specific_tag(
161    struct client_tag_spec *tag_list, const char *name)
162 {
163    struct client_tag_spec *tag;
164
165    for (tag = tag_list; tag != NULL; tag = tag->next)
166    {
167       if (tag->name != NULL && !strcmp(tag->name, name))
168       {
169          return tag;
170       }
171    }
172
173    log_error(LOG_LEVEL_ERROR, "No such tag: '%s'", name);
174
175    return NULL;
176
177 }
178
179
180 /*********************************************************************
181  *
182  * Function    :  get_tags_for_client
183  *
184  * Description :  Returns the list of tags the client opted-in.
185  *
186  * Parameters  :
187  *          1  :  client_address = Address of the client
188  *
189  * Returns     :  Pointer to tag structure or NULL on error.
190  *
191  *********************************************************************/
192 static struct client_specific_tag *get_tags_for_client(const char *client_address)
193 {
194    struct requested_tags *requested_tag;
195
196    for (requested_tag = requested_tags; requested_tag != NULL;
197         requested_tag = requested_tag->next)
198    {
199       if (!strcmp(requested_tag->client, client_address))
200       {
201          return requested_tag->tags;
202       }
203    }
204
205    return NULL;
206 }
207
208
209 /*********************************************************************
210  *
211  * Function    :  get_tag_list_for_client
212  *
213  * Description :  Provides a list of tag names the client opted-in.
214  *                Other tag attributes are not part of the list.
215  *
216  * Parameters  :
217  *          1  :  tag_list = The list to fill in.
218  *          2  :  client_address = Address of the client
219  *
220  * Returns     :  Pointer to tag list.
221  *
222  *********************************************************************/
223 void get_tag_list_for_client(struct list *tag_list,
224                              const char *client_address)
225 {
226    struct client_specific_tag *enabled_tags;
227    const time_t now = time(NULL);
228
229    privoxy_mutex_lock(&client_tags_mutex);
230
231    enabled_tags = get_tags_for_client(client_address);
232    while (enabled_tags != NULL)
233    {
234       if (enabled_tags->end_of_life && (enabled_tags->end_of_life < now))
235       {
236          struct client_specific_tag *next_tag = enabled_tags->next;
237          log_error(LOG_LEVEL_TAGGING,
238             "Tag '%s' for client %s expired %ld seconds ago. Deleting it.",
239             enabled_tags->name, client_address,
240             (now - enabled_tags->end_of_life));
241          remove_tag_for_client(client_address, enabled_tags->name);
242          enabled_tags = next_tag;
243          continue;
244       }
245       else
246       {
247          log_error(LOG_LEVEL_TAGGING, "Enlisting tag '%s' for client %s.",
248             enabled_tags->name, client_address);
249          enlist(tag_list, enabled_tags->name);
250       }
251       enabled_tags = enabled_tags->next;
252    }
253
254    privoxy_mutex_unlock(&client_tags_mutex);
255 }
256
257
258 /*********************************************************************
259  *
260  * Function    :  get_next_tag_timeout_for_client
261  *
262  * Description :  Figures out when the next temporarily enabled tag
263  *                for the client will have timed out.
264  *
265  * Parameters  :
266  *          1  :  client_address = Address of the client
267  *
268  * Returns     :  Lowest timeout in seconds
269  *
270  *********************************************************************/
271 time_t get_next_tag_timeout_for_client(const char *client_address)
272 {
273    struct client_specific_tag *enabled_tags;
274    time_t next_timeout = 0;
275    const time_t now = time(NULL);
276
277    privoxy_mutex_lock(&client_tags_mutex);
278
279    enabled_tags = get_tags_for_client(client_address);
280    while (enabled_tags != NULL)
281    {
282       log_error(LOG_LEVEL_TAGGING,
283          "Evaluating tag '%s' for client %s. End of life %ld.",
284          enabled_tags->name, client_address, enabled_tags->end_of_life);
285       if (enabled_tags->end_of_life)
286       {
287           time_t time_left = enabled_tags->end_of_life - now;
288           /* Add a second to make sure the tag will have expired */
289           time_left++;
290           log_error(LOG_LEVEL_CGI, "%ld > %ld?", next_timeout, time_left);
291           if (next_timeout == 0 || next_timeout > time_left)
292           {
293              next_timeout = time_left;
294           }
295        }
296        enabled_tags = enabled_tags->next;
297    }
298
299    privoxy_mutex_unlock(&client_tags_mutex);
300
301    log_error(LOG_LEVEL_CGI, "Next timeout in %ld seconds", next_timeout);
302
303    return next_timeout;
304
305 }
306
307
308 /*********************************************************************
309  *
310  * Function    :  create_client_specific_tag
311  *
312  * Description :  Allocates memory for a client specific tag
313  *                and populates it.
314  *
315  * Parameters  :
316  *          1  :  name = The name of the tag to create.
317  *          2  :  time_to_live = 0, or the number of seconds
318  *                               the tag remains activated.
319  *
320  * Returns     :  Pointer to populated tag
321  *
322  *********************************************************************/
323 static struct client_specific_tag *create_client_specific_tag(const char *name,
324    const time_t time_to_live)
325 {
326    struct client_specific_tag *tag;
327
328    tag = zalloc_or_die(sizeof(struct client_specific_tag));
329    tag->name = strdup_or_die(name);
330    tag->end_of_life = time_to_live ? (time(NULL) + time_to_live) : 0;
331
332    return tag;
333
334 }
335
336 /*********************************************************************
337  *
338  * Function    :  add_tag_for_client
339  *
340  * Description :  Adds the tag for the client.
341  *
342  * Parameters  :
343  *          1  :  client_address = Address of the client
344  *          2  :  tag = The tag to add.
345  *          3  :  time_to_live = 0, or the number of seconds
346  *                               the tag remains activated.
347  *
348  * Returns     :  void
349  *
350  *********************************************************************/
351 static void add_tag_for_client(const char *client_address,
352    const char *tag, const time_t time_to_live)
353 {
354    struct requested_tags *clients_with_tags;
355    struct client_specific_tag *enabled_tags;
356
357    validate_requested_tags();
358
359    if (requested_tags == NULL)
360    {
361       /* XXX: Code duplication. */
362       requested_tags = zalloc_or_die(sizeof(struct requested_tags));
363       requested_tags->client = strdup_or_die(client_address);
364       requested_tags->tags = create_client_specific_tag(tag, time_to_live);
365
366       validate_requested_tags();
367       return;
368    }
369    else
370    {
371       clients_with_tags = requested_tags;
372       while (clients_with_tags->next != NULL)
373       {
374          if (!strcmp(clients_with_tags->client, client_address))
375          {
376             break;
377          }
378          clients_with_tags = clients_with_tags->next;
379       }
380       if (strcmp(clients_with_tags->client, client_address))
381       {
382          /* Client does not have tags yet, add new structure */
383          clients_with_tags->next = zalloc_or_die(sizeof(struct requested_tags));
384          clients_with_tags->next->prev = clients_with_tags;
385          clients_with_tags = clients_with_tags->next;
386          clients_with_tags->client = strdup_or_die(client_address);
387          clients_with_tags->tags = create_client_specific_tag(tag, time_to_live);
388
389          validate_requested_tags();
390
391          return;
392       }
393    }
394
395    enabled_tags = clients_with_tags->tags;
396    while (enabled_tags != NULL)
397    {
398       if (enabled_tags->next == NULL)
399       {
400          enabled_tags->next = create_client_specific_tag(tag, time_to_live);
401          enabled_tags->next->prev = enabled_tags;
402          break;
403       }
404       enabled_tags = enabled_tags->next;
405    }
406
407    validate_requested_tags();
408 }
409
410
411 /*********************************************************************
412  *
413  * Function    :  remove_tag_for_client
414  *
415  * Description :  Removes the tag for the client.
416  *
417  * Parameters  :
418  *          1  :  client_address = Address of the client
419  *          2  :  tag = The tag to remove.
420  *
421  * Returns     :  void
422  *
423  *********************************************************************/
424 static void remove_tag_for_client(const char *client_address, const char *tag)
425 {
426    struct requested_tags *clients_with_tags;
427    struct client_specific_tag *enabled_tags;
428
429    validate_requested_tags();
430
431    clients_with_tags = requested_tags;
432    while (clients_with_tags != NULL && clients_with_tags->client != NULL)
433    {
434       if (!strcmp(clients_with_tags->client, client_address))
435       {
436          break;
437       }
438       clients_with_tags = clients_with_tags->next;
439    }
440
441    assert(clients_with_tags != NULL);
442    if (clients_with_tags == NULL)
443    {
444       log_error(LOG_LEVEL_ERROR,
445          "Tried to remove tag %s for tag-less client %s",
446          tag, client_address);
447    }
448    enabled_tags = clients_with_tags->tags;
449    while (enabled_tags != NULL)
450    {
451       if (!strcmp(enabled_tags->name, tag))
452       {
453          if (enabled_tags->next != NULL)
454          {
455             enabled_tags->next->prev = enabled_tags->prev;
456             if (enabled_tags == clients_with_tags->tags)
457             {
458                /* Tag is first in line */
459                clients_with_tags->tags = enabled_tags->next;
460             }
461          }
462          if (enabled_tags->prev != NULL)
463          {
464             /* Tag has preceding tag */
465             enabled_tags->prev->next = enabled_tags->next;
466          }
467          if (enabled_tags->prev == NULL && enabled_tags->next == NULL)
468          {
469             /* Tag is the only one */
470             if (clients_with_tags->next != NULL)
471             {
472                /* Client has following client */
473                clients_with_tags->next->prev = clients_with_tags->prev;
474             }
475             if (clients_with_tags->prev != NULL)
476             {
477                /* Client has preceding client */
478                clients_with_tags->prev->next = clients_with_tags->next;
479             }
480             if (clients_with_tags == requested_tags)
481             {
482                /*
483                 * We're in the process of removing the last tag,
484                 * mark the global list as empty.
485                 */
486                requested_tags = NULL;
487             }
488             freez(clients_with_tags->client);
489             freez(clients_with_tags);
490          }
491          freez(enabled_tags->name);
492          freez(enabled_tags);
493          break;
494       }
495
496       enabled_tags = enabled_tags->next;
497    }
498
499    validate_requested_tags();
500
501 }
502
503
504 /*********************************************************************
505  *
506  * Function    :  client_has_requested_tag
507  *
508  * Description :  Checks whether or not the given client requested
509  *                the tag.
510  *
511  * Parameters  :
512  *          1  :  client_address = Address of the client
513  *          2  :  tag = Tag to check.
514  *
515  * Returns     :  TRUE or FALSE.
516  *
517  *********************************************************************/
518 int client_has_requested_tag(const char *client_address, const char *tag)
519 {
520    struct client_specific_tag *enabled_tags;
521
522    enabled_tags = get_tags_for_client(client_address);
523
524    while (enabled_tags != NULL)
525    {
526       if (!strcmp(enabled_tags->name, tag))
527       {
528          return TRUE;
529       }
530       enabled_tags = enabled_tags->next;
531    }
532
533    return FALSE;
534
535 }
536
537 /*********************************************************************
538  *
539  * Function    :  enable_client_specific_tag
540  *
541  * Description :  Enables a client-specific-tag for the client
542  *
543  * Parameters  :
544  *          1  :  csp = Current client state (buffers, headers, etc...)
545  *          2  :  tag_name = The name of the tag to enable
546  *          3  :  time_to_live = If not 0, the number of seconds the
547  *                               tag should stay enabled.
548  *
549  * Returns     :  JB_ERR_OK on success, JB_ERR_MEMORY or JB_ERR_PARSE.
550  *
551  *********************************************************************/
552 jb_err enable_client_specific_tag(struct client_state *csp,
553    const char *tag_name, const time_t time_to_live)
554 {
555    struct client_tag_spec *tag;
556
557    privoxy_mutex_lock(&client_tags_mutex);
558
559    tag = get_client_specific_tag(csp->config->client_tags, tag_name);
560    if (tag == NULL)
561    {
562       privoxy_mutex_unlock(&client_tags_mutex);
563       return JB_ERR_PARSE;
564    }
565
566    if (client_has_requested_tag(csp->client_address, tag_name))
567    {
568       log_error(LOG_LEVEL_TAGGING,
569          "Tag '%s' already enabled for client '%s'.",
570          tag->name, csp->client_address);
571    }
572    else
573    {
574       add_tag_for_client(csp->client_address, tag_name, time_to_live);
575       log_error(LOG_LEVEL_TAGGING,
576          "Tag '%s' enabled for client '%s'. TTL: %ld.",
577          tag->name, csp->client_address, time_to_live);
578    }
579
580    privoxy_mutex_unlock(&client_tags_mutex);
581
582    return JB_ERR_OK;
583
584 }
585
586 /*********************************************************************
587  *
588  * Function    :  disable_client_specific_tag
589  *
590  * Description :  Disables a client-specific-tag for the client
591  *
592  * Parameters  :
593  *          1  :  csp = Current client state (buffers, headers, etc...)
594  *          2  :  tag_name = The name of the tag to disable
595  *
596  * Returns     :  JB_ERR_OK on success, JB_ERR_MEMORY or JB_ERR_PARSE.
597  *
598  *********************************************************************/
599 jb_err disable_client_specific_tag(struct client_state *csp, const char *tag_name)
600 {
601    struct client_tag_spec *tag;
602
603    privoxy_mutex_lock(&client_tags_mutex);
604
605    tag = get_client_specific_tag(csp->config->client_tags, tag_name);
606    if (tag == NULL)
607    {
608       privoxy_mutex_unlock(&client_tags_mutex);
609       return JB_ERR_PARSE;
610    }
611
612    if (client_has_requested_tag(csp->client_address, tag_name))
613    {
614       remove_tag_for_client(csp->client_address, tag_name);
615       log_error(LOG_LEVEL_TAGGING,
616          "Tag '%s' disabled for client '%s'.", tag->name, csp->client_address);
617    }
618    else
619    {
620       log_error(LOG_LEVEL_TAGGING,
621          "Tag '%s' currently not set for client '%s'.",
622          tag->name, csp->client_address);
623    }
624
625    privoxy_mutex_unlock(&client_tags_mutex);
626    return JB_ERR_OK;
627
628 }
629
630
631 /*********************************************************************
632  *
633  * Function    :  client_tag_match
634  *
635  * Description :  Compare a client tag against a client tag pattern.
636  *
637  * Parameters  :
638  *          1  :  pattern = a TAG pattern
639  *          2  :  tag = Client tag to match
640  *
641  * Returns     :  Nonzero if the tag matches the pattern, else 0.
642  *
643  *********************************************************************/
644 int client_tag_match(const struct pattern_spec *pattern,
645                      const struct list *tags)
646 {
647    struct list_entry *tag;
648
649    if (!(pattern->flags & PATTERN_SPEC_CLIENT_TAG_PATTERN))
650    {
651       /*
652        * It's not a client pattern and thus shouldn't
653        * be matched against client tags.
654        */
655       return 0;
656    }
657
658    assert(tags);
659
660    for (tag = tags->first; tag != NULL; tag = tag->next)
661    {
662       if (regex_matches(pattern->pattern.tag_regex, tag->str))
663       {
664          log_error(LOG_LEVEL_TAGGING, "Client tag '%s' matches.", tag->str);
665          return 1;
666       }
667    }
668
669    return 0;
670
671 }
672
673
674 /*********************************************************************
675  *
676  * Function    :  set_client_address
677  *
678  * Description :  Sets the client address that will be used to enable,
679  *                disable, or apply client tags.
680  *
681  * Parameters  :
682  *          1  :  csp = Current client state (buffers, headers, etc...)
683  *          2  :  headers = Client headers
684  *
685  * Returns     :  void.
686  *
687  *********************************************************************/
688 void set_client_address(struct client_state *csp, const struct list *headers)
689 {
690    if (csp->config->trust_x_forwarded_for)
691    {
692       const char *client_address;
693
694       client_address = get_header_value(headers, "X-Forwarded-For:");
695       if (client_address != NULL)
696       {
697          csp->client_address = strdup_or_die(client_address);
698          log_error(LOG_LEVEL_HEADER,
699             "Got client address %s from X-Forwarded-For header",
700             csp->client_address);
701       }
702    }
703
704    if (csp->client_address == NULL)
705    {
706       csp->client_address = strdup_or_die(csp->ip_addr_str);
707    }
708 }
709
710 #else
711 #error Compiling client-tags.c without FEATURE_CLIENT_TAGS
712 #endif /* def FEATURE_CLIENT_TAGS */