Line data Source code
1 : /*********************************************************************
2 : *
3 : * File : $Source: /cvsroot/ijbswa/current/cgisimple.c,v $
4 : *
5 : * Purpose : Simple CGIs to get information about Privoxy's
6 : * status.
7 : *
8 : * Copyright : Written by and Copyright (C) 2001-2020 the
9 : * Privoxy team. https://www.privoxy.org/
10 : *
11 : * Based on the Internet Junkbuster originally written
12 : * by and Copyright (C) 1997 Anonymous Coders and
13 : * Junkbusters Corporation. http://www.junkbusters.com
14 : *
15 : * This program is free software; you can redistribute it
16 : * and/or modify it under the terms of the GNU General
17 : * Public License as published by the Free Software
18 : * Foundation; either version 2 of the License, or (at
19 : * your option) any later version.
20 : *
21 : * This program is distributed in the hope that it will
22 : * be useful, but WITHOUT ANY WARRANTY; without even the
23 : * implied warranty of MERCHANTABILITY or FITNESS FOR A
24 : * PARTICULAR PURPOSE. See the GNU General Public
25 : * License for more details.
26 : *
27 : * The GNU General Public License should be included with
28 : * this file. If not, you can view it at
29 : * http://www.gnu.org/copyleft/gpl.html
30 : * or write to the Free Software Foundation, Inc., 59
31 : * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 : *
33 : **********************************************************************/
34 :
35 :
36 : #include "config.h"
37 :
38 : #include <stdio.h>
39 : #include <sys/types.h>
40 : #include <stdlib.h>
41 : #include <ctype.h>
42 : #include <string.h>
43 : #include <assert.h>
44 :
45 : #if defined (HAVE_ACCESS) && defined (HAVE_UNISTD_H)
46 : #include <unistd.h>
47 : #endif /* def HAVE_ACCESS && HAVE_UNISTD_H */
48 :
49 : #include "project.h"
50 : #include "cgi.h"
51 : #include "cgisimple.h"
52 : #include "list.h"
53 : #include "encode.h"
54 : #include "jcc.h"
55 : #include "filters.h"
56 : #include "actions.h"
57 : #include "miscutil.h"
58 : #include "loadcfg.h"
59 : #include "parsers.h"
60 : #include "urlmatch.h"
61 : #include "errlog.h"
62 : #ifdef FEATURE_CLIENT_TAGS
63 : #include "client-tags.h"
64 : #endif
65 :
66 : static jb_err show_defines(struct map *exports);
67 : static jb_err cgi_show_file(struct client_state *csp,
68 : struct http_response *rsp,
69 : const struct map *parameters);
70 : static jb_err load_file(const char *filename, char **buffer, size_t *length);
71 :
72 : /*********************************************************************
73 : *
74 : * Function : cgi_default
75 : *
76 : * Description : CGI function that is called for the CGI_SITE_1_HOST
77 : * and CGI_SITE_2_HOST/CGI_SITE_2_PATH base URLs.
78 : * Boring - only exports the default exports.
79 : *
80 : * Parameters :
81 : * 1 : csp = Current client state (buffers, headers, etc...)
82 : * 2 : rsp = http_response data structure for output
83 : * 3 : parameters = map of cgi parameters
84 : *
85 : * CGI Parameters : none
86 : *
87 : * Returns : JB_ERR_OK on success
88 : * JB_ERR_MEMORY on out-of-memory
89 : *
90 : *********************************************************************/
91 4320 : jb_err cgi_default(struct client_state *csp,
92 : struct http_response *rsp,
93 : const struct map *parameters)
94 : {
95 : struct map *exports;
96 :
97 : (void)parameters;
98 :
99 4320 : assert(csp);
100 4320 : assert(rsp);
101 :
102 4320 : if (NULL == (exports = default_exports(csp, "")))
103 : {
104 0 : return JB_ERR_MEMORY;
105 : }
106 :
107 4320 : return template_fill_for_cgi(csp, "default", exports, rsp);
108 : }
109 :
110 :
111 : /*********************************************************************
112 : *
113 : * Function : cgi_error_404
114 : *
115 : * Description : CGI function that is called if an unknown action was
116 : * given.
117 : *
118 : * Parameters :
119 : * 1 : csp = Current client state (buffers, headers, etc...)
120 : * 2 : rsp = http_response data structure for output
121 : * 3 : parameters = map of cgi parameters
122 : *
123 : * CGI Parameters : none
124 : *
125 : * Returns : JB_ERR_OK on success
126 : * JB_ERR_MEMORY on out-of-memory error.
127 : *
128 : *********************************************************************/
129 2108 : jb_err cgi_error_404(struct client_state *csp,
130 : struct http_response *rsp,
131 : const struct map *parameters)
132 : {
133 : struct map *exports;
134 :
135 2108 : assert(csp);
136 2108 : assert(rsp);
137 2108 : assert(parameters);
138 :
139 2108 : if (NULL == (exports = default_exports(csp, NULL)))
140 : {
141 0 : return JB_ERR_MEMORY;
142 : }
143 :
144 2108 : rsp->status = strdup_or_die("404 Privoxy configuration page not found");
145 :
146 2108 : return template_fill_for_cgi(csp, "cgi-error-404", exports, rsp);
147 : }
148 :
149 :
150 : #ifdef FEATURE_GRACEFUL_TERMINATION
151 : /*********************************************************************
152 : *
153 : * Function : cgi_die
154 : *
155 : * Description : CGI function to shut down Privoxy.
156 : * NOTE: Turning this on in a production build
157 : * would be a BAD idea. An EXTREMELY BAD idea.
158 : * In short, don't do it.
159 : *
160 : * Parameters :
161 : * 1 : csp = Current client state (buffers, headers, etc...)
162 : * 2 : rsp = http_response data structure for output
163 : * 3 : parameters = map of cgi parameters
164 : *
165 : * CGI Parameters : none
166 : *
167 : * Returns : JB_ERR_OK on success
168 : *
169 : *********************************************************************/
170 : jb_err cgi_die (struct client_state *csp,
171 : struct http_response *rsp,
172 : const struct map *parameters)
173 : {
174 : static const char status[] = "200 OK Privoxy shutdown request received";
175 : static const char body[] =
176 : "<html>\n"
177 : "<head>\n"
178 : " <title>Privoxy shutdown request received</title>\n"
179 : " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">\n"
180 : " <link rel=\"stylesheet\" type=\"text/css\" href=\"" CGI_PREFIX "send-stylesheet\">\n"
181 : "</head>\n"
182 : "<body>\n"
183 : "<h1>Privoxy shutdown request received</h1>\n"
184 : "<p>Privoxy is going to shut down after the next request.</p>\n"
185 : "</body>\n"
186 : "</html>\n";
187 :
188 : assert(csp);
189 : assert(rsp);
190 : assert(parameters);
191 :
192 : /* quit */
193 : g_terminate = 1;
194 :
195 : csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
196 :
197 : rsp->content_length = 0;
198 : rsp->head_length = 0;
199 : rsp->is_static = 0;
200 :
201 : rsp->body = strdup_or_die(body);
202 : rsp->status = strdup_or_die(status);
203 :
204 : return JB_ERR_OK;
205 : }
206 : #endif /* def FEATURE_GRACEFUL_TERMINATION */
207 :
208 :
209 : /*********************************************************************
210 : *
211 : * Function : cgi_show_request
212 : *
213 : * Description : Show the client's request and what sed() would have
214 : * made of it.
215 : *
216 : * Parameters :
217 : * 1 : csp = Current client state (buffers, headers, etc...)
218 : * 2 : rsp = http_response data structure for output
219 : * 3 : parameters = map of cgi parameters
220 : *
221 : * CGI Parameters : none
222 : *
223 : * Returns : JB_ERR_OK on success
224 : * JB_ERR_MEMORY on out-of-memory error.
225 : *
226 : *********************************************************************/
227 134 : jb_err cgi_show_request(struct client_state *csp,
228 : struct http_response *rsp,
229 : const struct map *parameters)
230 : {
231 : char *p;
232 : struct map *exports;
233 :
234 134 : assert(csp);
235 134 : assert(rsp);
236 134 : assert(parameters);
237 :
238 134 : if (NULL == (exports = default_exports(csp, "show-request")))
239 : {
240 0 : return JB_ERR_MEMORY;
241 : }
242 :
243 : /*
244 : * Repair the damage done to the IOB by get_header()
245 : */
246 89557 : for (p = csp->client_iob->buf; p < csp->client_iob->cur; p++)
247 : {
248 89423 : if (*p == '\0') *p = '\n';
249 : }
250 :
251 : /*
252 : * Export the original client's request and the one we would
253 : * be sending to the server if this wasn't a CGI call
254 : */
255 :
256 134 : if (map(exports, "client-request", 1, html_encode(csp->client_iob->buf), 0))
257 : {
258 0 : free_map(exports);
259 0 : return JB_ERR_MEMORY;
260 : }
261 :
262 134 : if (map(exports, "processed-request", 1,
263 268 : html_encode_and_free_original(
264 : #ifdef FEATURE_HTTPS_INSPECTION
265 134 : csp->http->ssl ?
266 3 : list_to_text(csp->https_headers) :
267 : #endif
268 131 : list_to_text(csp->headers)
269 : ), 0))
270 : {
271 0 : free_map(exports);
272 0 : return JB_ERR_MEMORY;
273 : }
274 :
275 134 : return template_fill_for_cgi(csp, "show-request", exports, rsp);
276 : }
277 :
278 :
279 : #ifdef FEATURE_CLIENT_TAGS
280 : /*********************************************************************
281 : *
282 : * Function : cgi_create_client_tag_form
283 : *
284 : * Description : Creates a HTML form to enable or disable a given
285 : * client tag.
286 : * XXX: Could use a template.
287 : *
288 : * Parameters :
289 : * 1 : form = Buffer to fill with the generated form
290 : * 2 : size = Size of the form buffer
291 : * 3 : tag = Name of the tag this form should affect
292 : * 4 : toggle_state = Desired state after the button pressed 0
293 : * 5 : expires = Whether or not the tag should be enabled.
294 : * Only checked if toggle_state is 1.
295 : *
296 : * Returns : void
297 : *
298 : *********************************************************************/
299 1781 : static void cgi_create_client_tag_form(char *form, size_t size,
300 : const char *tag, int toggle_state, int expires)
301 : {
302 : char *button_name;
303 :
304 1781 : if (toggle_state == 1)
305 : {
306 1698 : button_name = (expires == 1) ? "Enable" : "Enable temporarily";
307 : }
308 : else
309 : {
310 83 : assert(toggle_state == 0);
311 83 : button_name = "Disable";
312 : }
313 :
314 1781 : snprintf(form, size,
315 : "<form method=\"GET\" action=\""CGI_PREFIX"toggle-client-tag\" style=\"display: inline\">\n"
316 : " <input type=\"hidden\" name=\"tag\" value=\"%s\">\n"
317 : " <input type=\"hidden\" name=\"toggle-state\" value=\"%i\">\n"
318 : " <input type=\"hidden\" name=\"expires\" value=\"%u\">\n"
319 : " <input type=\"submit\" value=\"%s\">\n"
320 : "</form>", tag, toggle_state, !expires, button_name);
321 1781 : }
322 :
323 : /*********************************************************************
324 : *
325 : * Function : cgi_show_client_tags
326 : *
327 : * Description : Shows the tags that can be set based on the client
328 : * address (opt-in).
329 : *
330 : * Parameters :
331 : * 1 : csp = Current client state (buffers, headers, etc...)
332 : * 2 : rsp = http_response data structure for output
333 : * 3 : parameters = map of cgi parameters
334 : *
335 : * CGI Parameters : none
336 : *
337 : * Returns : JB_ERR_OK on success
338 : * JB_ERR_MEMORY on out-of-memory error.
339 : *
340 : *********************************************************************/
341 233 : jb_err cgi_show_client_tags(struct client_state *csp,
342 : struct http_response *rsp,
343 : const struct map *parameters)
344 : {
345 : struct map *exports;
346 : struct client_tag_spec *this_tag;
347 233 : jb_err err = JB_ERR_OK;
348 : char *client_tag_status;
349 : char buf[1000];
350 : time_t refresh_delay;
351 :
352 233 : assert(csp);
353 233 : assert(rsp);
354 233 : assert(parameters);
355 :
356 233 : if (NULL == (exports = default_exports(csp, "client-tags")))
357 : {
358 0 : return JB_ERR_MEMORY;
359 : }
360 233 : assert(csp->client_address != NULL);
361 :
362 233 : this_tag = csp->config->client_tags;
363 233 : if (this_tag->name == NULL)
364 : {
365 0 : client_tag_status = strdup_or_die("<p>No tags have been configured.</p>\n");
366 : }
367 : else
368 : {
369 233 : client_tag_status = strdup_or_die("<table border=\"1\">\n"
370 : "<tr><th>Tag name</th>\n"
371 : "<th>Current state</th><th>Change state</th><th>Description</th></tr>\n");
372 1165 : while ((this_tag != NULL) && (this_tag->name != NULL))
373 : {
374 : int tag_state;
375 :
376 932 : privoxy_mutex_lock(&client_tags_mutex);
377 932 : tag_state = client_has_requested_tag(csp->client_address, this_tag->name);
378 932 : privoxy_mutex_unlock(&client_tags_mutex);
379 932 : if (!err) err = string_append(&client_tag_status, "<tr><td>");
380 932 : if (!err) err = string_append(&client_tag_status, this_tag->name);
381 932 : if (!err) err = string_append(&client_tag_status, "</td><td>");
382 932 : if (!err) err = string_append(&client_tag_status, tag_state == 1 ? "Enabled" : "Disabled");
383 932 : if (!err) err = string_append(&client_tag_status, "</td><td>");
384 932 : cgi_create_client_tag_form(buf, sizeof(buf), this_tag->name, !tag_state, 1);
385 932 : if (!err) err = string_append(&client_tag_status, buf);
386 932 : if (tag_state == 0)
387 : {
388 849 : cgi_create_client_tag_form(buf, sizeof(buf), this_tag->name, !tag_state, 0);
389 849 : if (!err) err = string_append(&client_tag_status, buf);
390 : }
391 932 : if (!err) err = string_append(&client_tag_status, "</td><td>");
392 932 : if (!err) err = string_append(&client_tag_status, this_tag->description);
393 932 : if (!err) err = string_append(&client_tag_status, "</td></tr>\n");
394 932 : if (err)
395 : {
396 0 : break;
397 : }
398 932 : this_tag = this_tag->next;
399 : }
400 233 : if (!err) err = string_append(&client_tag_status, "</table>\n");
401 233 : if (err)
402 : {
403 0 : free_map(exports);
404 0 : return JB_ERR_MEMORY;
405 : }
406 : }
407 233 : refresh_delay = get_next_tag_timeout_for_client(csp->client_address);
408 233 : if (refresh_delay != 0)
409 : {
410 47 : snprintf(buf, sizeof(buf), "%u", csp->config->client_tag_lifetime);
411 47 : if (map(exports, "refresh-delay", 1, buf, 1))
412 : {
413 0 : freez(client_tag_status);
414 0 : free_map(exports);
415 0 : return JB_ERR_MEMORY;
416 : }
417 : }
418 : else
419 : {
420 186 : err = map_block_killer(exports, "tags-expire");
421 186 : if (err != JB_ERR_OK)
422 : {
423 0 : freez(client_tag_status);
424 0 : return err;
425 : }
426 : }
427 :
428 233 : if (map(exports, "client-tags", 1, client_tag_status, 0))
429 : {
430 0 : free_map(exports);
431 0 : return JB_ERR_MEMORY;
432 : }
433 :
434 233 : if (map(exports, "client-ip-addr", 1, csp->client_address, 1))
435 : {
436 0 : free_map(exports);
437 0 : return JB_ERR_MEMORY;
438 : }
439 :
440 233 : return template_fill_for_cgi(csp, "client-tags", exports, rsp);
441 : }
442 :
443 :
444 : /*********************************************************************
445 : *
446 : * Function : cgi_toggle_client_tag
447 : *
448 : * Description : Toggles a client tag and redirects to the show-tags
449 : * page
450 : *
451 : * Parameters :
452 : * 1 : csp = Current client state (buffers, headers, etc...)
453 : * 2 : rsp = http_response data structure for output
454 : * 3 : parameters = map of cgi parameters
455 : *
456 : * CGI Parameters : none
457 : * 1 : tag = Name of the tag to enable or disable
458 : * 2 : toggle-state = How to toggle the tag (0/1)
459 : * 3 : expires = Set to 1 if the tag should be enabled
460 : * temporarily, otherwise set to 0
461 : *
462 : * Returns : JB_ERR_OK on success
463 : * JB_ERR_MEMORY on out-of-memory error.
464 : *
465 : *********************************************************************/
466 909 : jb_err cgi_toggle_client_tag(struct client_state *csp,
467 : struct http_response *rsp,
468 : const struct map *parameters)
469 : {
470 : const char *toggled_tag;
471 : const char *toggle_state;
472 : const char *tag_expires;
473 : time_t time_to_live;
474 :
475 909 : assert(csp);
476 909 : assert(rsp);
477 909 : assert(parameters);
478 :
479 909 : toggled_tag = lookup(parameters, "tag");
480 909 : if (*toggled_tag == '\0')
481 : {
482 104 : log_error(LOG_LEVEL_ERROR, "Received tag toggle request without tag");
483 : }
484 : else
485 : {
486 805 : tag_expires = lookup(parameters, "expires");
487 805 : if (*tag_expires == '0')
488 : {
489 79 : time_to_live = 0;
490 : }
491 : else
492 : {
493 726 : time_to_live = csp->config->client_tag_lifetime;
494 : }
495 805 : toggle_state = lookup(parameters, "toggle-state");
496 805 : if (*toggle_state == '1')
497 : {
498 511 : enable_client_specific_tag(csp, toggled_tag, time_to_live);
499 : }
500 : else
501 : {
502 294 : disable_client_specific_tag(csp, toggled_tag);
503 : }
504 : }
505 909 : rsp->status = strdup_or_die("302 Done dealing with toggle request");
506 909 : if (enlist_unique_header(rsp->headers,
507 : "Location", CGI_PREFIX "client-tags"))
508 : {
509 0 : return JB_ERR_MEMORY;
510 : }
511 909 : return JB_ERR_OK;
512 :
513 : }
514 : #endif /* def FEATURE_CLIENT_TAGS */
515 :
516 :
517 : /*********************************************************************
518 : *
519 : * Function : cgi_send_banner
520 : *
521 : * Description : CGI function that returns a banner.
522 : *
523 : * Parameters :
524 : * 1 : csp = Current client state (buffers, headers, etc...)
525 : * 2 : rsp = http_response data structure for output
526 : * 3 : parameters = map of cgi parameters
527 : *
528 : * CGI Parameters :
529 : * type : Selects the type of banner between "trans", "logo",
530 : * and "auto". Defaults to "logo" if absent or invalid.
531 : * "auto" means to select as if we were image-blocking.
532 : * (Only the first character really counts; b and t are
533 : * equivalent).
534 : *
535 : * Returns : JB_ERR_OK on success
536 : * JB_ERR_MEMORY on out-of-memory error.
537 : *
538 : *********************************************************************/
539 733 : jb_err cgi_send_banner(struct client_state *csp,
540 : struct http_response *rsp,
541 : const struct map *parameters)
542 : {
543 733 : char imagetype = lookup(parameters, "type")[0];
544 :
545 733 : if (imagetype != 'a' && imagetype != 'b' &&
546 594 : imagetype != 'p' && imagetype != 't')
547 : {
548 555 : log_error(LOG_LEVEL_ERROR, "Overruling invalid image type '%c'.",
549 : imagetype);
550 555 : imagetype = 'p';
551 : }
552 :
553 : /*
554 : * If type is auto, then determine the right thing
555 : * to do from the set-image-blocker action
556 : */
557 733 : if (imagetype == 'a')
558 : {
559 : /*
560 : * Default to pattern
561 : */
562 82 : imagetype = 'p';
563 :
564 : #ifdef FEATURE_IMAGE_BLOCKING
565 82 : if ((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0)
566 : {
567 : static const char prefix1[] = CGI_PREFIX "send-banner?type=";
568 : static const char prefix2[] = "http://" CGI_SITE_1_HOST "/send-banner?type=";
569 0 : const char *p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER];
570 :
571 0 : if (p == NULL)
572 : {
573 : /* Use default - nothing to do here. */
574 : }
575 0 : else if (0 == strcmpic(p, "blank"))
576 : {
577 0 : imagetype = 'b';
578 : }
579 0 : else if (0 == strcmpic(p, "pattern"))
580 : {
581 0 : imagetype = 'p';
582 : }
583 :
584 : /*
585 : * If the action is to call this CGI, determine
586 : * the argument:
587 : */
588 0 : else if (0 == strncmpic(p, prefix1, sizeof(prefix1) - 1))
589 : {
590 0 : imagetype = p[sizeof(prefix1) - 1];
591 : }
592 0 : else if (0 == strncmpic(p, prefix2, sizeof(prefix2) - 1))
593 : {
594 0 : imagetype = p[sizeof(prefix2) - 1];
595 : }
596 :
597 : /*
598 : * Everything else must (should) be a URL to
599 : * redirect to.
600 : */
601 : else
602 : {
603 0 : imagetype = 'r';
604 : }
605 : }
606 : #endif /* def FEATURE_IMAGE_BLOCKING */
607 : }
608 :
609 : /*
610 : * Now imagetype is either the non-auto type we were called with,
611 : * or it was auto and has since been determined. In any case, we
612 : * can proceed to actually answering the request by sending a redirect
613 : * or an image as appropriate:
614 : */
615 733 : if (imagetype == 'r')
616 : {
617 0 : rsp->status = strdup_or_die("302 Local Redirect from Privoxy");
618 0 : if (enlist_unique_header(rsp->headers, "Location",
619 0 : csp->action->string[ACTION_STRING_IMAGE_BLOCKER]))
620 : {
621 0 : return JB_ERR_MEMORY;
622 : }
623 : }
624 : else
625 : {
626 733 : if ((imagetype == 'b') || (imagetype == 't'))
627 : {
628 73 : rsp->body = bindup(image_blank_data, image_blank_length);
629 73 : rsp->content_length = image_blank_length;
630 : }
631 : else
632 : {
633 660 : rsp->body = bindup(image_pattern_data, image_pattern_length);
634 660 : rsp->content_length = image_pattern_length;
635 : }
636 :
637 733 : if (rsp->body == NULL)
638 : {
639 0 : return JB_ERR_MEMORY;
640 : }
641 733 : if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
642 : {
643 0 : return JB_ERR_MEMORY;
644 : }
645 :
646 733 : rsp->is_static = 1;
647 : }
648 :
649 733 : return JB_ERR_OK;
650 :
651 : }
652 :
653 :
654 : /*********************************************************************
655 : *
656 : * Function : cgi_transparent_image
657 : *
658 : * Description : CGI function that sends a 1x1 transparent image.
659 : *
660 : * Parameters :
661 : * 1 : csp = Current client state (buffers, headers, etc...)
662 : * 2 : rsp = http_response data structure for output
663 : * 3 : parameters = map of cgi parameters
664 : *
665 : * CGI Parameters : None
666 : *
667 : * Returns : JB_ERR_OK on success
668 : * JB_ERR_MEMORY on out-of-memory error.
669 : *
670 : *********************************************************************/
671 80 : jb_err cgi_transparent_image(struct client_state *csp,
672 : struct http_response *rsp,
673 : const struct map *parameters)
674 : {
675 : (void)csp;
676 : (void)parameters;
677 :
678 80 : rsp->body = bindup(image_blank_data, image_blank_length);
679 80 : rsp->content_length = image_blank_length;
680 :
681 80 : if (rsp->body == NULL)
682 : {
683 0 : return JB_ERR_MEMORY;
684 : }
685 :
686 80 : if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
687 : {
688 0 : return JB_ERR_MEMORY;
689 : }
690 :
691 80 : rsp->is_static = 1;
692 :
693 80 : return JB_ERR_OK;
694 :
695 : }
696 :
697 :
698 : /*********************************************************************
699 : *
700 : * Function : cgi_send_default_favicon
701 : *
702 : * Description : CGI function that sends the standard favicon.
703 : *
704 : * Parameters :
705 : * 1 : csp = Current client state (buffers, headers, etc...)
706 : * 2 : rsp = http_response data structure for output
707 : * 3 : parameters = map of cgi parameters
708 : *
709 : * CGI Parameters : None
710 : *
711 : * Returns : JB_ERR_OK on success
712 : * JB_ERR_MEMORY on out-of-memory error.
713 : *
714 : *********************************************************************/
715 496 : jb_err cgi_send_default_favicon(struct client_state *csp,
716 : struct http_response *rsp,
717 : const struct map *parameters)
718 : {
719 : static const char default_favicon_data[] =
720 : "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
721 : "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
722 : "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
723 : "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
724 : "\000\000\377\377\377\000\377\000\052\000\017\360\000\000\077"
725 : "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
726 : "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
727 : "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
728 : "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
729 : "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
730 : "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
731 : "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
732 : "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
733 : "\017\000\000";
734 : static const size_t favicon_length = sizeof(default_favicon_data) - 1;
735 :
736 : (void)csp;
737 : (void)parameters;
738 :
739 496 : rsp->body = bindup(default_favicon_data, favicon_length);
740 496 : rsp->content_length = favicon_length;
741 :
742 496 : if (rsp->body == NULL)
743 : {
744 0 : return JB_ERR_MEMORY;
745 : }
746 :
747 496 : if (enlist(rsp->headers, "Content-Type: image/x-icon"))
748 : {
749 0 : return JB_ERR_MEMORY;
750 : }
751 :
752 496 : rsp->is_static = 1;
753 :
754 496 : return JB_ERR_OK;
755 :
756 : }
757 :
758 :
759 : /*********************************************************************
760 : *
761 : * Function : cgi_send_error_favicon
762 : *
763 : * Description : CGI function that sends the favicon for error pages.
764 : *
765 : * Parameters :
766 : * 1 : csp = Current client state (buffers, headers, etc...)
767 : * 2 : rsp = http_response data structure for output
768 : * 3 : parameters = map of cgi parameters
769 : *
770 : * CGI Parameters : None
771 : *
772 : * Returns : JB_ERR_OK on success
773 : * JB_ERR_MEMORY on out-of-memory error.
774 : *
775 : *********************************************************************/
776 68 : jb_err cgi_send_error_favicon(struct client_state *csp,
777 : struct http_response *rsp,
778 : const struct map *parameters)
779 : {
780 : static const char error_favicon_data[] =
781 : "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
782 : "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
783 : "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
784 : "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
785 : "\000\000\377\377\377\000\000\000\377\000\017\360\000\000\077"
786 : "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
787 : "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
788 : "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
789 : "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
790 : "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
791 : "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
792 : "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
793 : "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
794 : "\017\000\000";
795 : static const size_t favicon_length = sizeof(error_favicon_data) - 1;
796 :
797 : (void)csp;
798 : (void)parameters;
799 :
800 68 : rsp->body = bindup(error_favicon_data, favicon_length);
801 68 : rsp->content_length = favicon_length;
802 :
803 68 : if (rsp->body == NULL)
804 : {
805 0 : return JB_ERR_MEMORY;
806 : }
807 :
808 68 : if (enlist(rsp->headers, "Content-Type: image/x-icon"))
809 : {
810 0 : return JB_ERR_MEMORY;
811 : }
812 :
813 68 : rsp->is_static = 1;
814 :
815 68 : return JB_ERR_OK;
816 :
817 : }
818 :
819 :
820 : /*********************************************************************
821 : *
822 : * Function : cgi_send_stylesheet
823 : *
824 : * Description : CGI function that sends a css stylesheet found
825 : * in the cgi-style.css template
826 : *
827 : * Parameters :
828 : * 1 : csp = Current client state (buffers, headers, etc...)
829 : * 2 : rsp = http_response data structure for output
830 : * 3 : parameters = map of cgi parameters
831 : *
832 : * CGI Parameters : None
833 : *
834 : * Returns : JB_ERR_OK on success
835 : * JB_ERR_MEMORY on out-of-memory error.
836 : *
837 : *********************************************************************/
838 47 : jb_err cgi_send_stylesheet(struct client_state *csp,
839 : struct http_response *rsp,
840 : const struct map *parameters)
841 : {
842 : jb_err err;
843 :
844 47 : assert(csp);
845 47 : assert(rsp);
846 :
847 : (void)parameters;
848 :
849 47 : err = template_load(csp, &rsp->body, "cgi-style.css", 0);
850 :
851 47 : if (err == JB_ERR_FILE)
852 : {
853 : /*
854 : * No way to tell user; send empty stylesheet
855 : */
856 0 : log_error(LOG_LEVEL_ERROR, "Could not find cgi-style.css template");
857 : }
858 47 : else if (err)
859 : {
860 0 : return err; /* JB_ERR_MEMORY */
861 : }
862 :
863 47 : if (enlist(rsp->headers, "Content-Type: text/css"))
864 : {
865 0 : return JB_ERR_MEMORY;
866 : }
867 :
868 47 : return JB_ERR_OK;
869 :
870 : }
871 :
872 :
873 : /*********************************************************************
874 : *
875 : * Function : cgi_send_url_info_osd
876 : *
877 : * Description : CGI function that sends the OpenSearch Description
878 : * template for the show-url-info page. It allows to
879 : * access the page through "search engine plugins".
880 : *
881 : * Parameters :
882 : * 1 : csp = Current client state (buffers, headers, etc...)
883 : * 2 : rsp = http_response data structure for output
884 : * 3 : parameters = map of cgi parameters
885 : *
886 : * CGI Parameters : None
887 : *
888 : * Returns : JB_ERR_OK on success
889 : * JB_ERR_MEMORY on out-of-memory error.
890 : *
891 : *********************************************************************/
892 88 : jb_err cgi_send_url_info_osd(struct client_state *csp,
893 : struct http_response *rsp,
894 : const struct map *parameters)
895 : {
896 88 : jb_err err = JB_ERR_MEMORY;
897 88 : struct map *exports = default_exports(csp, NULL);
898 :
899 : (void)csp;
900 : (void)parameters;
901 :
902 88 : if (NULL != exports)
903 : {
904 88 : err = template_fill_for_cgi(csp, "url-info-osd.xml", exports, rsp);
905 88 : if (JB_ERR_OK == err)
906 : {
907 88 : err = enlist(rsp->headers,
908 : "Content-Type: application/opensearchdescription+xml");
909 : }
910 : }
911 :
912 88 : return err;
913 :
914 : }
915 :
916 :
917 : /*********************************************************************
918 : *
919 : * Function : get_content_type
920 : *
921 : * Description : Use the file extension to guess the content type
922 : * header we should use to serve the file.
923 : *
924 : * Parameters :
925 : * 1 : filename = Name of the file whose content type
926 : * we care about
927 : *
928 : * Returns : The guessed content type.
929 : *
930 : *********************************************************************/
931 0 : static const char *get_content_type(const char *filename)
932 : {
933 : int i;
934 : struct content_type
935 : {
936 : const char extension[6];
937 : const char content_type[11];
938 : };
939 : static const struct content_type content_types[] =
940 : {
941 : {".css", "text/css"},
942 : {".jpg", "image/jpeg"},
943 : {".jpeg", "image/jpeg"},
944 : {".png", "image/png"},
945 : };
946 :
947 0 : for (i = 0; i < SZ(content_types); i++)
948 : {
949 0 : if (strstr(filename, content_types[i].extension))
950 : {
951 0 : return content_types[i].content_type;
952 : }
953 : }
954 :
955 : /* No match by extension, default to html */
956 0 : return "text/html";
957 : }
958 :
959 : /*********************************************************************
960 : *
961 : * Function : cgi_send_user_manual
962 : *
963 : * Description : CGI function that sends a file in the user
964 : * manual directory.
965 : *
966 : * Parameters :
967 : * 1 : csp = Current client state (buffers, headers, etc...)
968 : * 2 : rsp = http_response data structure for output
969 : * 3 : parameters = map of cgi parameters
970 : *
971 : * CGI Parameters : file=name.html, the name of the HTML file
972 : * (relative to user-manual from config)
973 : *
974 : * Returns : JB_ERR_OK on success
975 : * JB_ERR_MEMORY on out-of-memory error.
976 : *
977 : *********************************************************************/
978 1904 : jb_err cgi_send_user_manual(struct client_state *csp,
979 : struct http_response *rsp,
980 : const struct map *parameters)
981 : {
982 : const char *filename;
983 : char *full_path;
984 1904 : jb_err err = JB_ERR_OK;
985 : const char *content_type;
986 :
987 1904 : assert(csp);
988 1904 : assert(rsp);
989 1904 : assert(parameters);
990 :
991 1904 : if (0 == strncmpic(csp->config->usermanual, "http://", 7))
992 : {
993 0 : log_error(LOG_LEVEL_CGI, "Request for local user-manual "
994 : "received while user-manual delivery is disabled.");
995 0 : return cgi_error_404(csp, rsp, parameters);
996 : }
997 :
998 1904 : if (!parameters->first)
999 : {
1000 : /* requested http://p.p/user-manual (without trailing slash) */
1001 1509 : return cgi_redirect(rsp, CGI_PREFIX "user-manual/");
1002 : }
1003 :
1004 395 : get_string_param(parameters, "file", &filename);
1005 395 : if (filename == NULL)
1006 : {
1007 : /* It's '/' so serve the index.html if there is one. */
1008 263 : filename = "index.html";
1009 : }
1010 132 : else if (NULL != strchr(filename, '/') || NULL != strstr(filename, ".."))
1011 : {
1012 : /*
1013 : * We currently only support a flat file
1014 : * hierarchy for the documentation.
1015 : */
1016 60 : log_error(LOG_LEVEL_ERROR,
1017 : "Rejecting the request to serve '%s' as it contains '/' or '..'",
1018 : filename);
1019 60 : return JB_ERR_CGI_PARAMS;
1020 : }
1021 :
1022 335 : full_path = make_path(csp->config->usermanual, filename);
1023 335 : if (full_path == NULL)
1024 : {
1025 0 : return JB_ERR_MEMORY;
1026 : }
1027 :
1028 335 : err = load_file(full_path, &rsp->body, &rsp->content_length);
1029 335 : if (JB_ERR_OK != err)
1030 : {
1031 335 : assert((JB_ERR_FILE == err) || (JB_ERR_MEMORY == err));
1032 335 : if (JB_ERR_FILE == err)
1033 : {
1034 335 : err = cgi_error_no_template(csp, rsp, full_path);
1035 : }
1036 335 : freez(full_path);
1037 335 : return err;
1038 : }
1039 0 : freez(full_path);
1040 :
1041 0 : content_type = get_content_type(filename);
1042 0 : log_error(LOG_LEVEL_CGI,
1043 : "Content-Type guessed for %s: %s", filename, content_type);
1044 :
1045 0 : return enlist_unique_header(rsp->headers, "Content-Type", content_type);
1046 :
1047 : }
1048 :
1049 :
1050 : #ifdef FEATURE_EXTENDED_STATISTICS
1051 : /*********************************************************************
1052 : *
1053 : * Function : get_block_reason_statistics_table
1054 : *
1055 : * Description : Produces the block reason statistic table content.
1056 : *
1057 : * Parameters :
1058 : * 1 : csp = Current client state (buffers, headers, etc...)
1059 : *
1060 : * Returns : Pointer to the HTML statistic table content or
1061 : * NULL on out of memory
1062 : *
1063 : *********************************************************************/
1064 500 : static char *get_block_reason_statistics_table(const struct client_state *csp)
1065 : {
1066 : char buf[BUFFER_SIZE];
1067 : char *statistics;
1068 : int i;
1069 : struct file_list *fl;
1070 500 : jb_err err = JB_ERR_OK;
1071 :
1072 500 : statistics = strdup_or_die("");
1073 :
1074 : /* Run through all action files. */
1075 50500 : for (i = 0; i < MAX_AF_FILES; i++)
1076 : {
1077 : struct url_actions *b;
1078 50000 : struct action_spec *last_action = NULL;
1079 :
1080 50000 : if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL))
1081 : {
1082 : /* Skip empty files */
1083 49000 : continue;
1084 : }
1085 :
1086 : /* Go through all the actions. */
1087 11500 : for (b = b->next; NULL != b; b = b->next)
1088 : {
1089 10500 : if (last_action == b->action)
1090 : {
1091 500 : continue;
1092 : }
1093 10000 : if ((b->action->add & ACTION_BLOCK))
1094 : {
1095 : unsigned long long count;
1096 1500 : const char *block_reason = b->action->string[ACTION_STRING_BLOCK];
1097 1500 : const char *encoded_block_reason = html_encode(block_reason);
1098 :
1099 1500 : if (encoded_block_reason == NULL)
1100 : {
1101 0 : freez(statistics);
1102 0 : return NULL;
1103 : }
1104 1500 : get_block_reason_count(block_reason, &count);
1105 1500 : snprintf(buf, sizeof(buf),
1106 : "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>\n",
1107 : encoded_block_reason, count);
1108 1500 : freez(encoded_block_reason);
1109 :
1110 1500 : if (!err) err = string_append(&statistics, buf);
1111 : }
1112 10000 : last_action = b->action;
1113 : }
1114 : }
1115 :
1116 500 : return statistics;
1117 :
1118 : }
1119 :
1120 :
1121 : /*********************************************************************
1122 : *
1123 : * Function : get_filter_statistics_table
1124 : *
1125 : * Description : Produces the filter statistic table content.
1126 : *
1127 : * Parameters :
1128 : * 1 : csp = Current client state (buffers, headers, etc...)
1129 : *
1130 : * Returns : Pointer to the HTML statistic table content or
1131 : * NULL on out of memory
1132 : *
1133 : *********************************************************************/
1134 500 : static char *get_filter_statistics_table(const struct client_state *csp)
1135 : {
1136 : char buf[BUFFER_SIZE];
1137 : char *statistics;
1138 : int i;
1139 : struct file_list *fl;
1140 : struct re_filterfile_spec *b;
1141 500 : jb_err err = JB_ERR_OK;
1142 :
1143 500 : statistics = strdup_or_die("");
1144 :
1145 50500 : for (i = 0; i < MAX_AF_FILES; i++)
1146 : {
1147 50000 : fl = csp->rlist[i];
1148 50000 : if ((NULL == fl) || (NULL == fl->f))
1149 : {
1150 : /*
1151 : * Either there are no filter files left or this
1152 : * filter file just contains no valid filters.
1153 : *
1154 : * Continue to be sure we don't miss valid filter
1155 : * files that are chained after empty or invalid ones.
1156 : */
1157 49500 : continue;
1158 : }
1159 :
1160 6500 : for (b = fl->f; b != NULL; b = b->next)
1161 : {
1162 6000 : if (b->type == FT_CONTENT_FILTER)
1163 : {
1164 : unsigned long long executions;
1165 : unsigned long long response_bodies_modified;
1166 : unsigned long long hits;
1167 :
1168 2000 : get_filter_statistics(b->name, &executions, &response_bodies_modified, &hits);
1169 2000 : snprintf(buf, sizeof(buf),
1170 : "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>"
1171 : "<td style=\"text-align: right\">%llu</td>"
1172 : "<td style=\"text-align: right\">%llu</td><tr>\n",
1173 : b->name, executions, response_bodies_modified, hits);
1174 :
1175 2000 : if (!err) err = string_append(&statistics, buf);
1176 : }
1177 : }
1178 : }
1179 :
1180 500 : return statistics;
1181 :
1182 : }
1183 : #endif /* def FEATURE_EXTENDED_STATISTICS */
1184 :
1185 :
1186 : /*********************************************************************
1187 : *
1188 : * Function : cgi_show_status
1189 : *
1190 : * Description : CGI function that returns a web page describing the
1191 : * current status of Privoxy.
1192 : *
1193 : * Parameters :
1194 : * 1 : csp = Current client state (buffers, headers, etc...)
1195 : * 2 : rsp = http_response data structure for output
1196 : * 3 : parameters = map of cgi parameters
1197 : *
1198 : * CGI Parameters :
1199 : * file : Which file to show. Only first letter is checked,
1200 : * valid values are:
1201 : * - "a"ction file
1202 : * - "r"egex
1203 : * - "t"rust
1204 : * Default is to show menu and other information.
1205 : *
1206 : * Returns : JB_ERR_OK on success
1207 : * JB_ERR_MEMORY on out-of-memory error.
1208 : *
1209 : *********************************************************************/
1210 948 : jb_err cgi_show_status(struct client_state *csp,
1211 : struct http_response *rsp,
1212 : const struct map *parameters)
1213 : {
1214 948 : char *s = NULL;
1215 : unsigned i;
1216 : int j;
1217 :
1218 : char buf[BUFFER_SIZE];
1219 : #ifdef FEATURE_STATISTICS
1220 : float perc_rej; /* Percentage of http requests rejected */
1221 : int local_urls_read;
1222 : int local_urls_rejected;
1223 : #endif /* ndef FEATURE_STATISTICS */
1224 948 : jb_err err = JB_ERR_OK;
1225 :
1226 : struct map *exports;
1227 :
1228 948 : assert(csp);
1229 948 : assert(rsp);
1230 948 : assert(parameters);
1231 :
1232 948 : if ('\0' != *(lookup(parameters, "file")))
1233 : {
1234 448 : return cgi_show_file(csp, rsp, parameters);
1235 : }
1236 :
1237 500 : if (NULL == (exports = default_exports(csp, "show-status")))
1238 : {
1239 0 : return JB_ERR_MEMORY;
1240 : }
1241 :
1242 500 : s = strdup("");
1243 3000 : for (j = 0; (s != NULL) && (j < Argc); j++)
1244 : {
1245 2500 : if (!err) err = string_join (&s, html_encode(Argv[j]));
1246 2500 : if (!err) err = string_append(&s, " ");
1247 : }
1248 500 : if (!err) err = map(exports, "invocation", 1, s, 0);
1249 :
1250 500 : if (!err) err = map(exports, "options", 1, csp->config->proxy_args, 1);
1251 500 : if (!err) err = show_defines(exports);
1252 :
1253 500 : if (err)
1254 : {
1255 0 : free_map(exports);
1256 0 : return JB_ERR_MEMORY;
1257 : }
1258 :
1259 : #ifdef FEATURE_STATISTICS
1260 500 : local_urls_read = urls_read;
1261 500 : local_urls_rejected = urls_rejected;
1262 :
1263 : /*
1264 : * Need to alter the stats not to include the fetch of this
1265 : * page.
1266 : *
1267 : * Can't do following thread safely! doh!
1268 : *
1269 : * urls_read--;
1270 : * urls_rejected--; * This will be incremented subsequently *
1271 : */
1272 :
1273 500 : if (local_urls_read == 0)
1274 : {
1275 500 : if (!err) err = map_block_killer(exports, "have-stats");
1276 : }
1277 : else
1278 : {
1279 0 : if (!err) err = map_block_killer(exports, "have-no-stats");
1280 :
1281 0 : perc_rej = (float)local_urls_rejected * 100.0F /
1282 0 : (float)local_urls_read;
1283 :
1284 0 : snprintf(buf, sizeof(buf), "%d", local_urls_read);
1285 0 : if (!err) err = map(exports, "requests-received", 1, buf, 1);
1286 :
1287 0 : snprintf(buf, sizeof(buf), "%d", local_urls_rejected);
1288 0 : if (!err) err = map(exports, "requests-blocked", 1, buf, 1);
1289 :
1290 0 : snprintf(buf, sizeof(buf), "%6.2f", perc_rej);
1291 0 : if (!err) err = map(exports, "percent-blocked", 1, buf, 1);
1292 : }
1293 :
1294 : #else /* ndef FEATURE_STATISTICS */
1295 : if (!err) err = map_block_killer(exports, "statistics");
1296 : #endif /* ndef FEATURE_STATISTICS */
1297 :
1298 : #ifdef FEATURE_EXTENDED_STATISTICS
1299 500 : if (!err)
1300 : {
1301 500 : char *block_reason_statistics = get_block_reason_statistics_table(csp);
1302 500 : if (block_reason_statistics != NULL)
1303 : {
1304 500 : err = map(exports, "block-reason-statistics", 1, block_reason_statistics, 0);
1305 : }
1306 : else
1307 : {
1308 0 : err = map_block_killer(exports, "extended-statistics");
1309 : }
1310 : }
1311 500 : if (!err)
1312 : {
1313 500 : char *filter_statistics = get_filter_statistics_table(csp);
1314 500 : if (filter_statistics != NULL)
1315 : {
1316 500 : err = map(exports, "filter-statistics", 1, filter_statistics, 0);
1317 : }
1318 : else
1319 : {
1320 0 : err = map_block_killer(exports, "extended-statistics");
1321 : }
1322 : }
1323 : #else /* ndef FEATURE_EXTENDED_STATISTICS */
1324 : if (!err) err = map_block_killer(exports, "extended-statistics");
1325 : #endif /* def FEATURE_EXTENDED_STATISTICS */
1326 :
1327 : /*
1328 : * List all action files in use, together with view and edit links,
1329 : * except for standard.action, which should only be viewable. (Not
1330 : * enforced in the editor itself)
1331 : * FIXME: Shouldn't include hardwired HTML here, use line template instead!
1332 : */
1333 500 : s = strdup("");
1334 50500 : for (i = 0; i < MAX_AF_FILES; i++)
1335 : {
1336 50000 : if (csp->actions_list[i] != NULL)
1337 : {
1338 1000 : if (!err) err = string_append(&s, "<tr><td>");
1339 1000 : if (!err) err = string_join(&s, html_encode(csp->actions_list[i]->filename));
1340 1000 : snprintf(buf, sizeof(buf),
1341 : "</td><td class=\"buttons\"><a href=\"/show-status?file=actions&index=%u\">View</a>", i);
1342 1000 : if (!err) err = string_append(&s, buf);
1343 :
1344 : #ifdef FEATURE_CGI_EDIT_ACTIONS
1345 1000 : if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)
1346 1000 : && (NULL != csp->config->actions_file_short[i]))
1347 : {
1348 : #ifdef HAVE_ACCESS
1349 1000 : if (access(csp->config->actions_file[i], W_OK) == 0)
1350 : {
1351 : #endif /* def HAVE_ACCESS */
1352 1000 : snprintf(buf, sizeof(buf), " <a href=\"/edit-actions-list?f=%u\">Edit</a>", i);
1353 1000 : if (!err) err = string_append(&s, buf);
1354 : #ifdef HAVE_ACCESS
1355 : }
1356 : else
1357 : {
1358 0 : if (!err) err = string_append(&s, " <strong>No write access.</strong>");
1359 : }
1360 : #endif /* def HAVE_ACCESS */
1361 : }
1362 : #endif
1363 :
1364 1000 : if (!err) err = string_append(&s, "</td></tr>\n");
1365 : }
1366 : }
1367 500 : if (!err && *s != '\0')
1368 : {
1369 500 : err = map(exports, "actions-filenames", 1, s, 0);
1370 : }
1371 : else
1372 : {
1373 0 : if (!err) err = map(exports, "actions-filenames", 1, "<tr><td>None specified</td></tr>", 1);
1374 0 : freez(s);
1375 : }
1376 :
1377 : /*
1378 : * List all re_filterfiles in use, together with view options.
1379 : * FIXME: Shouldn't include hardwired HTML here, use line template instead!
1380 : */
1381 500 : s = strdup("");
1382 50500 : for (i = 0; i < MAX_AF_FILES; i++)
1383 : {
1384 50000 : if (csp->rlist[i] != NULL)
1385 : {
1386 1000 : if (!err) err = string_append(&s, "<tr><td>");
1387 1000 : if (!err) err = string_join(&s, html_encode(csp->rlist[i]->filename));
1388 1000 : snprintf(buf, sizeof(buf),
1389 : "</td><td class=\"buttons\"><a href=\"/show-status?file=filter&index=%u\">View</a>", i);
1390 1000 : if (!err) err = string_append(&s, buf);
1391 1000 : if (!err) err = string_append(&s, "</td></tr>\n");
1392 : }
1393 : }
1394 500 : if (!err && *s != '\0')
1395 : {
1396 500 : err = map(exports, "re-filter-filenames", 1, s, 0);
1397 : }
1398 : else
1399 : {
1400 0 : if (!err) err = map(exports, "re-filter-filenames", 1, "<tr><td>None specified</td></tr>", 1);
1401 0 : if (!err) err = map_block_killer(exports, "have-filterfile");
1402 0 : freez(s);
1403 : }
1404 :
1405 : #ifdef FEATURE_TRUST
1406 500 : if (csp->tlist)
1407 : {
1408 0 : if (!err) err = map(exports, "trust-filename", 1, html_encode(csp->tlist->filename), 0);
1409 : }
1410 : else
1411 : {
1412 500 : if (!err) err = map(exports, "trust-filename", 1, "None specified", 1);
1413 500 : if (!err) err = map_block_killer(exports, "have-trustfile");
1414 : }
1415 : #else
1416 : if (!err) err = map_block_killer(exports, "trust-support");
1417 : #endif /* ndef FEATURE_TRUST */
1418 :
1419 : #ifdef FEATURE_CGI_EDIT_ACTIONS
1420 500 : if (!err && (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
1421 : {
1422 500 : err = map_block_killer(exports, "cgi-editor-is-disabled");
1423 : }
1424 : #endif /* ndef CGI_EDIT_ACTIONS */
1425 :
1426 500 : if (!err) err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1);
1427 :
1428 500 : if (err)
1429 : {
1430 0 : free_map(exports);
1431 0 : return JB_ERR_MEMORY;
1432 : }
1433 :
1434 500 : return template_fill_for_cgi(csp, "show-status", exports, rsp);
1435 : }
1436 :
1437 :
1438 : /*********************************************************************
1439 : *
1440 : * Function : cgi_show_url_info
1441 : *
1442 : * Description : CGI function that determines and shows which actions
1443 : * Privoxy will perform for a given url, and which
1444 : * matches starting from the defaults have lead to that.
1445 : *
1446 : * Parameters :
1447 : * 1 : csp = Current client state (buffers, headers, etc...)
1448 : * 2 : rsp = http_response data structure for output
1449 : * 3 : parameters = map of cgi parameters
1450 : *
1451 : * CGI Parameters :
1452 : * url : The url whose actions are to be determined.
1453 : * If url is unset, the url-given conditional will be
1454 : * set, so that all but the form can be suppressed in
1455 : * the template.
1456 : *
1457 : * Returns : JB_ERR_OK on success
1458 : * JB_ERR_MEMORY on out-of-memory error.
1459 : *
1460 : *********************************************************************/
1461 1691 : jb_err cgi_show_url_info(struct client_state *csp,
1462 : struct http_response *rsp,
1463 : const struct map *parameters)
1464 : {
1465 : char *url_param;
1466 : struct map *exports;
1467 : char buf[150];
1468 :
1469 1691 : assert(csp);
1470 1691 : assert(rsp);
1471 1691 : assert(parameters);
1472 :
1473 1691 : if (NULL == (exports = default_exports(csp, "show-url-info")))
1474 : {
1475 0 : return JB_ERR_MEMORY;
1476 : }
1477 :
1478 : /*
1479 : * Get the url= parameter (if present) and remove any leading/trailing spaces.
1480 : */
1481 1691 : url_param = strdup_or_die(lookup(parameters, "url"));
1482 1691 : chomp(url_param);
1483 :
1484 : /*
1485 : * Handle prefixes. 4 possibilities:
1486 : * 1) "http://" or "https://" prefix present and followed by URL - OK
1487 : * 2) Only the "http://" or "https://" part is present, no URL - change
1488 : * to empty string so it will be detected later as "no URL".
1489 : * 3) Parameter specified but doesn't start with "http(s?)://" - add a
1490 : * "http://" prefix.
1491 : * 4) Parameter not specified or is empty string - let this fall through
1492 : * for now, next block of code will handle it.
1493 : */
1494 1691 : if (0 == strncmp(url_param, "http://", 7))
1495 : {
1496 64 : if (url_param[7] == '\0')
1497 : {
1498 : /*
1499 : * Empty URL (just prefix).
1500 : * Make it totally empty so it's caught by the next if ()
1501 : */
1502 10 : url_param[0] = '\0';
1503 : }
1504 : }
1505 1627 : else if (0 == strncmp(url_param, "https://", 8))
1506 : {
1507 51 : if (url_param[8] == '\0')
1508 : {
1509 : /*
1510 : * Empty URL (just prefix).
1511 : * Make it totally empty so it's caught by the next if ()
1512 : */
1513 1 : url_param[0] = '\0';
1514 : }
1515 : }
1516 1576 : else if ((url_param[0] != '\0')
1517 1313 : && ((NULL == strstr(url_param, "://")
1518 105 : || (strstr(url_param, "://") > strstr(url_param, "/")))))
1519 : {
1520 : /*
1521 : * No prefix or at least no prefix before
1522 : * the first slash - assume http://
1523 : */
1524 1244 : char *url_param_prefixed = strdup_or_die("http://");
1525 :
1526 1244 : if (JB_ERR_OK != string_join(&url_param_prefixed, url_param))
1527 : {
1528 0 : free_map(exports);
1529 0 : return JB_ERR_MEMORY;
1530 : }
1531 1244 : url_param = url_param_prefixed;
1532 : }
1533 :
1534 : /*
1535 : * Hide "toggle off" warning if Privoxy is toggled on.
1536 : */
1537 1691 : if (
1538 : #ifdef FEATURE_TOGGLE
1539 3344 : (global_toggle_state == 1) &&
1540 : #endif /* def FEATURE_TOGGLE */
1541 1653 : map_block_killer(exports, "privoxy-is-toggled-off")
1542 : )
1543 : {
1544 0 : freez(url_param);
1545 0 : free_map(exports);
1546 0 : return JB_ERR_MEMORY;
1547 : }
1548 :
1549 1691 : if (url_param[0] == '\0')
1550 : {
1551 : /* URL parameter not specified, display query form only. */
1552 274 : free(url_param);
1553 274 : if (map_block_killer(exports, "url-given")
1554 274 : || map(exports, "url", 1, "", 1))
1555 : {
1556 0 : free_map(exports);
1557 0 : return JB_ERR_MEMORY;
1558 : }
1559 : }
1560 : else
1561 : {
1562 : /* Given a URL, so query it. */
1563 : jb_err err;
1564 : char *matches;
1565 : char *s;
1566 1417 : int hits = 0;
1567 : struct file_list *fl;
1568 : struct url_actions *b;
1569 : struct http_request url_to_query[1];
1570 : struct current_action_spec action[1];
1571 : int i;
1572 :
1573 1417 : if (map(exports, "url", 1, html_encode(url_param), 0))
1574 : {
1575 0 : free(url_param);
1576 0 : free_map(exports);
1577 156 : return JB_ERR_MEMORY;
1578 : }
1579 :
1580 1417 : init_current_action(action);
1581 :
1582 1417 : if (map(exports, "default", 1, current_action_to_html(csp, action), 0))
1583 : {
1584 0 : free_current_action(action);
1585 0 : free(url_param);
1586 0 : free_map(exports);
1587 0 : return JB_ERR_MEMORY;
1588 : }
1589 :
1590 1417 : memset(url_to_query, '\0', sizeof(url_to_query));
1591 1417 : err = parse_http_url(url_param, url_to_query, REQUIRE_PROTOCOL);
1592 1417 : assert((err != JB_ERR_OK) || (url_to_query->ssl == !strncmpic(url_param, "https://", 8)));
1593 :
1594 1417 : free(url_param);
1595 :
1596 1417 : if (err == JB_ERR_MEMORY)
1597 : {
1598 0 : free_http_request(url_to_query);
1599 0 : free_current_action(action);
1600 0 : free_map(exports);
1601 0 : return JB_ERR_MEMORY;
1602 : }
1603 1417 : else if (err)
1604 : {
1605 : /* Invalid URL */
1606 :
1607 156 : err = map(exports, "matches", 1, "<b>[Invalid URL specified!]</b>" , 1);
1608 156 : if (!err) err = map(exports, "final", 1, lookup(exports, "default"), 1);
1609 156 : if (!err) err = map_block_killer(exports, "valid-url");
1610 :
1611 156 : free_current_action(action);
1612 156 : free_http_request(url_to_query);
1613 :
1614 156 : if (err)
1615 : {
1616 0 : free_map(exports);
1617 0 : return JB_ERR_MEMORY;
1618 : }
1619 :
1620 156 : return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
1621 : }
1622 :
1623 : /*
1624 : * We have a warning about SSL paths. Hide it for unencrypted sites
1625 : * and unconditionally if https inspection is enabled.
1626 : */
1627 : #ifndef FEATURE_HTTPS_INSPECTION
1628 : if (!url_to_query->ssl)
1629 : #endif
1630 : {
1631 1261 : if (map_block_killer(exports, "https-and-no-https-inspection"))
1632 : {
1633 0 : free_current_action(action);
1634 0 : free_map(exports);
1635 0 : free_http_request(url_to_query);
1636 0 : return JB_ERR_MEMORY;
1637 : }
1638 : }
1639 :
1640 1261 : matches = strdup_or_die("<table summary=\"\" class=\"transparent\">");
1641 :
1642 127361 : for (i = 0; i < MAX_AF_FILES; i++)
1643 : {
1644 126100 : if (NULL == csp->config->actions_file_short[i]
1645 126100 : || !strcmp(csp->config->actions_file_short[i], "standard.action")) continue;
1646 :
1647 2522 : b = NULL;
1648 2522 : hits = 1;
1649 2522 : if ((fl = csp->actions_list[i]) != NULL)
1650 : {
1651 2522 : if ((b = fl->f) != NULL)
1652 : {
1653 : /* FIXME: Hardcoded HTML! */
1654 2522 : string_append(&matches, "<tr><th>In file: ");
1655 2522 : string_join (&matches, html_encode(csp->config->actions_file_short[i]));
1656 2522 : snprintf(buf, sizeof(buf), " <a class=\"cmd\" href=\"/show-status?file=actions&index=%d\">", i);
1657 2522 : string_append(&matches, buf);
1658 2522 : string_append(&matches, "View</a>");
1659 : #ifdef FEATURE_CGI_EDIT_ACTIONS
1660 2522 : if (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)
1661 : {
1662 : #ifdef HAVE_ACCESS
1663 2522 : if (access(csp->config->actions_file[i], W_OK) == 0)
1664 : {
1665 : #endif /* def HAVE_ACCESS */
1666 2522 : snprintf(buf, sizeof(buf),
1667 : " <a class=\"cmd\" href=\"/edit-actions-list?f=%d\">", i);
1668 2522 : string_append(&matches, buf);
1669 2522 : string_append(&matches, "Edit</a>");
1670 : #ifdef HAVE_ACCESS
1671 : }
1672 : else
1673 : {
1674 0 : string_append(&matches, " <strong>No write access.</strong>");
1675 : }
1676 : #endif /* def HAVE_ACCESS */
1677 : }
1678 : #endif /* FEATURE_CGI_EDIT_ACTIONS */
1679 :
1680 2522 : string_append(&matches, "</th></tr>\n");
1681 :
1682 2522 : hits = 0;
1683 2522 : b = b->next;
1684 : }
1685 : }
1686 :
1687 29003 : for (; (b != NULL) && (matches != NULL); b = b->next)
1688 : {
1689 26481 : if (url_match(b->url, url_to_query))
1690 : {
1691 2188 : string_append(&matches, "<tr><td>{");
1692 2188 : string_join (&matches, actions_to_html(csp, b->action));
1693 2188 : string_append(&matches, " }<br>\n<code>");
1694 2188 : string_join (&matches, html_encode(b->url->spec));
1695 2188 : string_append(&matches, "</code></td></tr>\n");
1696 :
1697 2188 : if (merge_current_action(action, b->action))
1698 : {
1699 0 : freez(matches);
1700 0 : free_http_request(url_to_query);
1701 0 : free_current_action(action);
1702 0 : free_map(exports);
1703 0 : return JB_ERR_MEMORY;
1704 : }
1705 2188 : hits++;
1706 : }
1707 : }
1708 :
1709 2522 : if (!hits)
1710 : {
1711 766 : string_append(&matches, "<tr><td>(no matches in this file)</td></tr>\n");
1712 : }
1713 : }
1714 1261 : string_append(&matches, "</table>\n");
1715 :
1716 : /*
1717 : * XXX: Kludge to make sure the "Forward settings" section
1718 : * shows what forward-override{} would do with the requested URL.
1719 : * No one really cares how the CGI request would be forwarded
1720 : * if it wasn't intercepted as CGI request in the first place.
1721 : *
1722 : * From here on the action bitmask will no longer reflect
1723 : * the real url (http://config.privoxy.org/show-url-info?url=.*),
1724 : * but luckily it's no longer required later on anyway.
1725 : */
1726 1261 : free_current_action(csp->action);
1727 1261 : get_url_actions(csp, url_to_query);
1728 :
1729 : /*
1730 : * Fill in forwarding settings.
1731 : *
1732 : * The possibilities are:
1733 : * - no forwarding
1734 : * - http forwarding only
1735 : * - socks4(a) forwarding only
1736 : * - socks4(a) and http forwarding.
1737 : *
1738 : * XXX: Parts of this code could be reused for the
1739 : * "forwarding-failed" template which currently doesn't
1740 : * display the proxy port and an eventual second forwarder.
1741 : */
1742 : {
1743 1261 : const struct forward_spec *fwd = forward_url(csp, url_to_query);
1744 :
1745 1261 : if ((fwd->gateway_host == NULL) && (fwd->forward_host == NULL))
1746 : {
1747 1261 : if (!err) err = map_block_killer(exports, "socks-forwarder");
1748 1261 : if (!err) err = map_block_killer(exports, "http-forwarder");
1749 : }
1750 : else
1751 : {
1752 : char port[10]; /* We save proxy ports as int but need a string here */
1753 :
1754 0 : if (!err) err = map_block_killer(exports, "no-forwarder");
1755 :
1756 0 : if (fwd->gateway_host != NULL)
1757 : {
1758 0 : char *socks_type = NULL;
1759 :
1760 0 : switch (fwd->type)
1761 : {
1762 0 : case SOCKS_4:
1763 0 : socks_type = "socks4";
1764 0 : break;
1765 0 : case SOCKS_4A:
1766 0 : socks_type = "socks4a";
1767 0 : break;
1768 0 : case SOCKS_5:
1769 0 : socks_type = "socks5";
1770 0 : break;
1771 0 : case SOCKS_5T:
1772 0 : socks_type = "socks5t";
1773 0 : break;
1774 0 : default:
1775 0 : log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
1776 : }
1777 :
1778 0 : if (!err) err = map(exports, "socks-type", 1, socks_type, 1);
1779 0 : if (!err) err = map(exports, "gateway-host", 1, fwd->gateway_host, 1);
1780 0 : snprintf(port, sizeof(port), "%d", fwd->gateway_port);
1781 0 : if (!err) err = map(exports, "gateway-port", 1, port, 1);
1782 : }
1783 : else
1784 : {
1785 0 : if (!err) err = map_block_killer(exports, "socks-forwarder");
1786 : }
1787 :
1788 0 : if (fwd->forward_host != NULL)
1789 : {
1790 0 : if (!err) err = map(exports, "forward-host", 1, fwd->forward_host, 1);
1791 0 : snprintf(port, sizeof(port), "%d", fwd->forward_port);
1792 0 : if (!err) err = map(exports, "forward-port", 1, port, 1);
1793 : }
1794 : else
1795 : {
1796 0 : if (!err) err = map_block_killer(exports, "http-forwarder");
1797 : }
1798 : }
1799 : }
1800 :
1801 1261 : free_http_request(url_to_query);
1802 :
1803 1261 : if (err || matches == NULL)
1804 : {
1805 0 : free_current_action(action);
1806 0 : free_map(exports);
1807 0 : return JB_ERR_MEMORY;
1808 : }
1809 :
1810 : #ifdef FEATURE_CGI_EDIT_ACTIONS
1811 1261 : if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
1812 : {
1813 1261 : err = map_block_killer(exports, "cgi-editor-is-disabled");
1814 : }
1815 : #endif /* FEATURE_CGI_EDIT_ACTIONS */
1816 :
1817 : /*
1818 : * If zlib support is available, if no content filters
1819 : * are enabled or if the prevent-compression action is enabled,
1820 : * suppress the "compression could prevent filtering" warning.
1821 : */
1822 : #ifndef FEATURE_ZLIB
1823 : if (!content_filters_enabled(action) ||
1824 : (action->flags & ACTION_NO_COMPRESSION))
1825 : #endif
1826 : {
1827 1261 : if (!err) err = map_block_killer(exports, "filters-might-be-ineffective");
1828 : }
1829 :
1830 1261 : if (err || map(exports, "matches", 1, matches , 0))
1831 : {
1832 0 : free_current_action(action);
1833 0 : free_map(exports);
1834 0 : return JB_ERR_MEMORY;
1835 : }
1836 :
1837 1261 : s = current_action_to_html(csp, action);
1838 :
1839 1261 : free_current_action(action);
1840 :
1841 1261 : if (map(exports, "final", 1, s, 0))
1842 : {
1843 0 : free_map(exports);
1844 0 : return JB_ERR_MEMORY;
1845 : }
1846 : }
1847 :
1848 1535 : return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
1849 : }
1850 :
1851 :
1852 : /*********************************************************************
1853 : *
1854 : * Function : cgi_robots_txt
1855 : *
1856 : * Description : CGI function to return "/robots.txt".
1857 : *
1858 : * Parameters :
1859 : * 1 : csp = Current client state (buffers, headers, etc...)
1860 : * 2 : rsp = http_response data structure for output
1861 : * 3 : parameters = map of cgi parameters
1862 : *
1863 : * CGI Parameters : None
1864 : *
1865 : * Returns : JB_ERR_OK on success
1866 : * JB_ERR_MEMORY on out-of-memory error.
1867 : *
1868 : *********************************************************************/
1869 74 : jb_err cgi_robots_txt(struct client_state *csp,
1870 : struct http_response *rsp,
1871 : const struct map *parameters)
1872 : {
1873 : char buf[100];
1874 : jb_err err;
1875 :
1876 : (void)csp;
1877 : (void)parameters;
1878 :
1879 74 : rsp->body = strdup_or_die(
1880 : "# This is the Privoxy control interface.\n"
1881 : "# It isn't very useful to index it, and you're likely to break stuff.\n"
1882 : "# So go away!\n"
1883 : "\n"
1884 : "User-agent: *\n"
1885 : "Disallow: /\n"
1886 : "\n");
1887 :
1888 74 : err = enlist_unique(rsp->headers, "Content-Type: text/plain", 13);
1889 :
1890 74 : rsp->is_static = 1;
1891 :
1892 74 : get_http_time(7 * 24 * 60 * 60, buf, sizeof(buf)); /* 7 days into future */
1893 74 : if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf);
1894 :
1895 74 : return (err ? JB_ERR_MEMORY : JB_ERR_OK);
1896 : }
1897 :
1898 :
1899 : /*********************************************************************
1900 : *
1901 : * Function : show_defines
1902 : *
1903 : * Description : Add to a map the state of all conditional #defines
1904 : * used when building
1905 : *
1906 : * Parameters :
1907 : * 1 : exports = map to extend
1908 : *
1909 : * Returns : JB_ERR_OK on success
1910 : * JB_ERR_MEMORY on out-of-memory error.
1911 : *
1912 : *********************************************************************/
1913 500 : static jb_err show_defines(struct map *exports)
1914 : {
1915 500 : jb_err err = JB_ERR_OK;
1916 : int i;
1917 : struct feature {
1918 : const char name[31];
1919 : const unsigned char is_available;
1920 : };
1921 :
1922 : static const struct feature features[] = {
1923 : {
1924 : "FEATURE_64_BIT_TIME_T",
1925 : #if (SIZEOF_TIME_T == 8)
1926 : 1,
1927 : #else
1928 : 0,
1929 : #endif
1930 : },
1931 : {
1932 : "FEATURE_ACCEPT_FILTER",
1933 : #ifdef FEATURE_ACCEPT_FILTER
1934 : 1,
1935 : #else
1936 : 0,
1937 : #endif
1938 : },
1939 : {
1940 : "FEATURE_ACL",
1941 : #ifdef FEATURE_ACL
1942 : 1,
1943 : #else
1944 : 0,
1945 : #endif
1946 : },
1947 : {
1948 : "FEATURE_BROTLI",
1949 : #ifdef FEATURE_BROTLI
1950 : 1,
1951 : #else
1952 : 0,
1953 : #endif
1954 : },
1955 : {
1956 : "FEATURE_CGI_EDIT_ACTIONS",
1957 : #ifdef FEATURE_CGI_EDIT_ACTIONS
1958 : 1,
1959 : #else
1960 : 0,
1961 : #endif
1962 : },
1963 : {
1964 : "FEATURE_CLIENT_TAGS",
1965 : #ifdef FEATURE_CLIENT_TAGS
1966 : 1,
1967 : #else
1968 : 0,
1969 : #endif
1970 : },
1971 : {
1972 : "FEATURE_COMPRESSION",
1973 : #ifdef FEATURE_COMPRESSION
1974 : 1,
1975 : #else
1976 : 0,
1977 : #endif
1978 : },
1979 : {
1980 : "FEATURE_CONNECTION_KEEP_ALIVE",
1981 : #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1982 : 1,
1983 : #else
1984 : 0,
1985 : #endif
1986 : },
1987 : {
1988 : "FEATURE_CONNECTION_SHARING",
1989 : #ifdef FEATURE_CONNECTION_SHARING
1990 : 1,
1991 : #else
1992 : 0,
1993 : #endif
1994 : },
1995 : {
1996 : "FEATURE_EXTERNAL_FILTERS",
1997 : #ifdef FEATURE_EXTERNAL_FILTERS
1998 : 1,
1999 : #else
2000 : 0,
2001 : #endif
2002 : },
2003 : {
2004 : "FEATURE_FAST_REDIRECTS",
2005 : #ifdef FEATURE_FAST_REDIRECTS
2006 : 1,
2007 : #else
2008 : 0,
2009 : #endif
2010 : },
2011 : {
2012 : "FEATURE_FORCE_LOAD",
2013 : #ifdef FEATURE_FORCE_LOAD
2014 : 1,
2015 : #else
2016 : 0,
2017 : #endif
2018 : },
2019 : {
2020 : "FEATURE_GRACEFUL_TERMINATION",
2021 : #ifdef FEATURE_GRACEFUL_TERMINATION
2022 : 1,
2023 : #else
2024 : 0,
2025 : #endif
2026 : },
2027 : {
2028 : "FEATURE_HTTPS_INSPECTION",
2029 : #ifdef FEATURE_HTTPS_INSPECTION
2030 : 1,
2031 : #else
2032 : 0,
2033 : #endif
2034 : },
2035 : {
2036 : "FEATURE_IMAGE_BLOCKING",
2037 : #ifdef FEATURE_IMAGE_BLOCKING
2038 : 1,
2039 : #else
2040 : 0,
2041 : #endif
2042 : },
2043 : {
2044 : "FEATURE_IPV6_SUPPORT",
2045 : #ifdef HAVE_RFC2553
2046 : 1,
2047 : #else
2048 : 0,
2049 : #endif
2050 : },
2051 : {
2052 : "FEATURE_NO_GIFS",
2053 : #ifdef FEATURE_NO_GIFS
2054 : 1,
2055 : #else
2056 : 0,
2057 : #endif
2058 : },
2059 : {
2060 : "FEATURE_PTHREAD",
2061 : #ifdef FEATURE_PTHREAD
2062 : 1,
2063 : #else
2064 : 0,
2065 : #endif
2066 : },
2067 : {
2068 : "FEATURE_STATISTICS",
2069 : #ifdef FEATURE_STATISTICS
2070 : 1,
2071 : #else
2072 : 0,
2073 : #endif
2074 : },
2075 : {
2076 : "FEATURE_STRPTIME_SANITY_CHECKS",
2077 : #ifdef FEATURE_STRPTIME_SANITY_CHECKS
2078 : 1,
2079 : #else
2080 : 0,
2081 : #endif
2082 : },
2083 : {
2084 : "FEATURE_TOGGLE",
2085 : #ifdef FEATURE_TOGGLE
2086 : 1,
2087 : #else
2088 : 0,
2089 : #endif
2090 : },
2091 : {
2092 : "FEATURE_TRUST",
2093 : #ifdef FEATURE_TRUST
2094 : 1,
2095 : #else
2096 : 0,
2097 : #endif
2098 : },
2099 : {
2100 : "FEATURE_ZLIB",
2101 : #ifdef FEATURE_ZLIB
2102 : 1,
2103 : #else
2104 : 0,
2105 : #endif
2106 : },
2107 : {
2108 : "FEATURE_DYNAMIC_PCRE",
2109 : #ifdef FEATURE_DYNAMIC_PCRE
2110 : 1,
2111 : #else
2112 : 0,
2113 : #endif
2114 : },
2115 : {
2116 : "FEATURE_EXTENDED_STATISTICS",
2117 : #ifdef FEATURE_EXTENDED_STATISTICS
2118 : 1,
2119 : #else
2120 : 0,
2121 : #endif
2122 : },
2123 : {
2124 : "FEATURE_PCRE_HOST_PATTERNS",
2125 : #ifdef FEATURE_PCRE_HOST_PATTERNS
2126 : 1,
2127 : #else
2128 : 0,
2129 : #endif
2130 : }
2131 : };
2132 :
2133 13500 : for (i = 0; i < SZ(features); i++)
2134 : {
2135 13000 : err = map_conditional(exports, features[i].name, features[i].is_available);
2136 13000 : if (err)
2137 : {
2138 0 : break;
2139 : }
2140 : }
2141 :
2142 500 : return err;
2143 :
2144 : }
2145 :
2146 :
2147 : /*********************************************************************
2148 : *
2149 : * Function : cgi_show_file
2150 : *
2151 : * Description : CGI function that shows the content of a
2152 : * configuration file.
2153 : *
2154 : * Parameters :
2155 : * 1 : csp = Current client state (buffers, headers, etc...)
2156 : * 2 : rsp = http_response data structure for output
2157 : * 3 : parameters = map of cgi parameters
2158 : *
2159 : * CGI Parameters :
2160 : * file : Which file to show. Only first letter is checked,
2161 : * valid values are:
2162 : * - "a"ction file
2163 : * - "r"egex
2164 : * - "t"rust
2165 : * Default is to show menu and other information.
2166 : *
2167 : * Returns : JB_ERR_OK on success
2168 : * JB_ERR_MEMORY on out-of-memory error.
2169 : *
2170 : *********************************************************************/
2171 448 : static jb_err cgi_show_file(struct client_state *csp,
2172 : struct http_response *rsp,
2173 : const struct map *parameters)
2174 : {
2175 : unsigned i;
2176 448 : const char * filename = NULL;
2177 448 : char * file_description = NULL;
2178 :
2179 448 : assert(csp);
2180 448 : assert(rsp);
2181 448 : assert(parameters);
2182 :
2183 448 : switch (*(lookup(parameters, "file")))
2184 : {
2185 169 : case 'a':
2186 169 : if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->actions_list[i])
2187 : {
2188 44 : filename = csp->actions_list[i]->filename;
2189 44 : file_description = "Actions File";
2190 : }
2191 169 : break;
2192 :
2193 172 : case 'f':
2194 172 : if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->rlist[i])
2195 : {
2196 51 : filename = csp->rlist[i]->filename;
2197 51 : file_description = "Filter File";
2198 : }
2199 172 : break;
2200 :
2201 : #ifdef FEATURE_TRUST
2202 65 : case 't':
2203 65 : if (csp->tlist)
2204 : {
2205 0 : filename = csp->tlist->filename;
2206 0 : file_description = "Trust File";
2207 : }
2208 65 : break;
2209 : #endif /* def FEATURE_TRUST */
2210 : }
2211 :
2212 448 : if (NULL != filename)
2213 : {
2214 : struct map *exports;
2215 : char *s;
2216 : jb_err err;
2217 : size_t length;
2218 :
2219 95 : exports = default_exports(csp, "show-status");
2220 95 : if (NULL == exports)
2221 : {
2222 0 : return JB_ERR_MEMORY;
2223 : }
2224 :
2225 95 : if (map(exports, "file-description", 1, file_description, 1)
2226 95 : || map(exports, "filepath", 1, html_encode(filename), 0))
2227 : {
2228 0 : free_map(exports);
2229 0 : return JB_ERR_MEMORY;
2230 : }
2231 :
2232 95 : err = load_file(filename, &s, &length);
2233 95 : if (JB_ERR_OK != err)
2234 : {
2235 0 : if (map(exports, "contents", 1, "<h1>ERROR OPENING FILE!</h1>", 1))
2236 : {
2237 0 : free_map(exports);
2238 0 : return JB_ERR_MEMORY;
2239 : }
2240 : }
2241 : else
2242 : {
2243 95 : s = html_encode_and_free_original(s);
2244 95 : if (NULL == s)
2245 : {
2246 0 : free_map(exports);
2247 0 : return JB_ERR_MEMORY;
2248 : }
2249 :
2250 95 : if (map(exports, "contents", 1, s, 0))
2251 : {
2252 0 : free_map(exports);
2253 0 : return JB_ERR_MEMORY;
2254 : }
2255 : }
2256 :
2257 95 : return template_fill_for_cgi(csp, "show-status-file", exports, rsp);
2258 : }
2259 :
2260 353 : return JB_ERR_CGI_PARAMS;
2261 : }
2262 :
2263 :
2264 : /*********************************************************************
2265 : *
2266 : * Function : load_file
2267 : *
2268 : * Description : Loads a file into a buffer.
2269 : *
2270 : * Parameters :
2271 : * 1 : filename = Name of the file to be loaded.
2272 : * 2 : buffer = Used to return the file's content.
2273 : * 3 : length = Used to return the size of the file.
2274 : *
2275 : * Returns : JB_ERR_OK in case of success,
2276 : * JB_ERR_FILE in case of ordinary file loading errors
2277 : * (fseek() and ftell() errors are fatal)
2278 : * JB_ERR_MEMORY in case of out-of-memory.
2279 : *
2280 : *********************************************************************/
2281 430 : static jb_err load_file(const char *filename, char **buffer, size_t *length)
2282 : {
2283 : FILE *fp;
2284 : long ret;
2285 430 : jb_err err = JB_ERR_OK;
2286 :
2287 430 : fp = fopen(filename, "rb");
2288 430 : if (NULL == fp)
2289 : {
2290 335 : log_error(LOG_LEVEL_ERROR, "Failed to open %s: %E", filename);
2291 335 : return JB_ERR_FILE;
2292 : }
2293 :
2294 : /* Get file length */
2295 95 : if (fseek(fp, 0, SEEK_END))
2296 : {
2297 0 : log_error(LOG_LEVEL_FATAL,
2298 : "Unexpected error while fseek()ing to the end of %s: %E",
2299 : filename);
2300 : }
2301 95 : ret = ftell(fp);
2302 95 : if (-1 == ret)
2303 : {
2304 0 : log_error(LOG_LEVEL_FATAL,
2305 : "Unexpected ftell() error while loading %s: %E",
2306 : filename);
2307 : }
2308 95 : *length = (size_t)ret;
2309 :
2310 : /* Go back to the beginning. */
2311 95 : if (fseek(fp, 0, SEEK_SET))
2312 : {
2313 0 : log_error(LOG_LEVEL_FATAL,
2314 : "Unexpected error while fseek()ing to the beginning of %s: %E",
2315 : filename);
2316 : }
2317 :
2318 95 : *buffer = zalloc_or_die(*length + 1);
2319 :
2320 95 : if (1 != fread(*buffer, *length, 1, fp))
2321 : {
2322 : /*
2323 : * May theoretically happen if the file size changes between
2324 : * fseek() and fread() because it's edited in-place. Privoxy
2325 : * and common text editors don't do that, thus we just fail.
2326 : */
2327 0 : log_error(LOG_LEVEL_ERROR,
2328 : "Couldn't completely read file %s.", filename);
2329 0 : freez(*buffer);
2330 0 : err = JB_ERR_FILE;
2331 : }
2332 :
2333 95 : fclose(fp);
2334 :
2335 95 : return err;
2336 :
2337 : }
2338 :
2339 :
2340 : /*
2341 : Local Variables:
2342 : tab-width: 3
2343 : end:
2344 : */
|