-const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.57 2007/10/27 13:32:23 fabiankeil Exp $";
+const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.64 2009/03/01 18:43:09 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/cgiedit.c,v $
*
* Stick to the short names in this file for consistency.
*
- * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge
+ * Copyright : Written by and Copyright (C) 2001-2008 the SourceForge
* Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
*
* Revisions :
* $Log: cgiedit.c,v $
+ * Revision 1.64 2009/03/01 18:43:09 fabiankeil
+ * Fix cparser warnings.
+ *
+ * Revision 1.63 2008/12/04 18:15:38 fabiankeil
+ * Fix some cparser warnings.
+ *
+ * Revision 1.62 2008/08/31 15:59:02 fabiankeil
+ * There's no reason to let remote toggling support depend
+ * on FEATURE_CGI_EDIT_ACTIONS, so make sure it doesn't.
+ *
+ * Revision 1.61 2008/03/24 18:12:52 fabiankeil
+ * Use sizeof() more often.
+ *
+ * Revision 1.60 2008/03/15 14:52:35 fabiankeil
+ * Add CGI editor support for the "disable all filters of this type"
+ * directives "-client-header-filter", "-server-header-filter",
+ * "-client-header-tagger" and "-server-header-tagger".
+ *
+ * Revision 1.59 2008/03/08 16:25:56 fabiankeil
+ * After three file modification time mismatches, turn the CGI editor off.
+ *
+ * Revision 1.58 2007/11/28 17:57:01 fabiankeil
+ * Fix double free in cgi_edit_actions_list().
+ * Reported by adlab in BR#1840145.
+ *
* Revision 1.57 2007/10/27 13:32:23 fabiankeil
* Plug minor 5-year-old memory leak. Spotted by
* Valgrind and triggered by Privoxy-Regression-Test.
/** This file_line is in a {{description}} block. */
#define FILE_LINE_DESCRIPTION_ENTRY 10
+/*
+ * Number of file modification time mismatches
+ * before the CGI editor gets turned off.
+ */
+#define ACCEPTABLE_TIMESTAMP_MISMATCHES 3
/**
* A configuration file, in a format that can be edited and written back to
For example "content-filter-params" */
const char *type; /**< Name of the filter type,
for example "server-header-filter". */
+ /* XXX: check if these two can be combined. */
+ const char *disable_all_option; /**< Name of the catch-all radio option that has
+ to be checked or unchecked for this filter type. */
+ const char *disable_all_param; /**< Name of the parameter that causes all filters of
+ this type to be disabled. */
const char *abbr_type; /**< Abbreviation of the filter type, usually the
first or second character capitalized */
const char *anchor; /**< Anchor for the User Manual link,
{
ACTION_MULTI_FILTER,
"content-filter-params", "filter",
+ "filter-all", "filter_all",
"F", "FILTER"
},
{
ACTION_MULTI_CLIENT_HEADER_FILTER,
"client-header-filter-params", "client-header-filter",
+ "client-header-filter-all", "client_header_filter_all",
"C", "CLIENT-HEADER-FILTER"
},
{
ACTION_MULTI_SERVER_HEADER_FILTER,
"server-header-filter-params", "server-header-filter",
+ "server-header-filter-all", "server_header_filter_all",
"S", "SERVER-HEADER-FILTER"
},
{
ACTION_MULTI_CLIENT_HEADER_TAGGER,
"client-header-tagger-params", "client-header-tagger",
+ "client-header-tagger-all", "client_header_tagger_all",
"L", "CLIENT-HEADER-TAGGER"
},
{
ACTION_MULTI_SERVER_HEADER_TAGGER,
"server-header-tagger-params", "server-header-tagger",
+ "server-header-tagger-all", "server_header_tagger_all",
"E", "SERVER-HEADER-TAGGER"
},
};
{
char buf[30];
- snprintf(buf, 30, "#l%d", sectionid);
+ snprintf(buf, sizeof(buf), "#l%d", sectionid);
return(strdup(buf));
}
if ( (cur_line == NULL)
|| (line_number != patternid)
- || (patternid < 1)
+ || (patternid < 1U)
|| (cur_line->type != FILE_LINE_URL))
{
/* Invalid "patternid" parameter */
if ( (cur_line == NULL)
|| (line_number != patternid)
- || (patternid < 1)
+ || (patternid < 1U)
|| (cur_line->type != FILE_LINE_URL))
{
/* Invalid "patternid" parameter */
/* Correct file->version_str */
freez(file->version_str);
- snprintf(version_buf, 22, "%u", file->version);
- version_buf[21] = '\0';
+ snprintf(version_buf, sizeof(version_buf), "%u", file->version);
+ version_buf[sizeof(version_buf)-1] = '\0';
file->version_str = strdup(version_buf);
if (version_buf == NULL)
{
text++;
len--;
}
- while ( (len > 0)
+ while ( (len > (size_t)0)
&& ( (text[len - 1] == ' ')
|| (text[len - 1] == '\t') ) )
{
/* Correct file->version_str */
freez(file->version_str);
- snprintf(version_buf, 22, "%u", file->version);
- version_buf[21] = '\0';
+ snprintf(version_buf, sizeof(version_buf), "%u", file->version);
+ version_buf[sizeof(version_buf)-1] = '\0';
file->version_str = strdup(version_buf);
if (version_buf == NULL)
{
{
jb_err err;
struct editable_file *file;
+ static int acceptable_failures = ACCEPTABLE_TIMESTAMP_MISMATCHES - 1;
assert(csp);
assert(parameters);
}
else if (err == JB_ERR_MODIFIED)
{
+ assert(require_version);
err = cgi_error_modified(csp, rsp, lookup(parameters, "f"));
+ log_error(LOG_LEVEL_ERROR,
+ "Blocking CGI edit request due to modification time mismatch.");
+ if (acceptable_failures > 0)
+ {
+ log_error(LOG_LEVEL_INFO,
+ "The CGI editor will be turned off after another %d mismatche(s).",
+ acceptable_failures);
+ acceptable_failures--;
+ }
+ else
+ {
+ log_error(LOG_LEVEL_INFO,
+ "Timestamp mismatch limit reached, turning CGI editor off. "
+ "Reload the configuration file to reenable it.");
+ csp->config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
+ }
}
if (err == JB_ERR_OK)
{
struct http_response *rsp,
const struct map *parameters)
{
+ (void)parameters;
if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
{
*/
if (!err) err = map_conditional(exports, "all-urls-present", 1);
- snprintf(buf, 150, "%d", line_number);
+ snprintf(buf, sizeof(buf), "%d", line_number);
if (!err) err = map(exports, "all-urls-s", 1, buf, 1);
- snprintf(buf, 150, "%d", line_number + 2);
+ snprintf(buf, sizeof(buf), "%d", line_number + 2);
if (!err) err = map(exports, "all-urls-s-next", 1, buf, 1);
if (!err) err = map(exports, "all-urls-actions", 1,
actions_to_html(csp, cur_line->data.action), 0);
return JB_ERR_MEMORY;
}
- snprintf(buf, 150, "%d", line_number);
+ snprintf(buf, sizeof(buf), "%d", line_number);
err = map(section_exports, "s", 1, buf, 1);
if (!err) err = map(section_exports, "actions", 1,
actions_to_html(csp, cur_line->data.action), 0);
if (prev_section_line_number != ((unsigned)(-1)))
{
/* Not last section */
- snprintf(buf, 150, "%d", prev_section_line_number);
+ snprintf(buf, sizeof(buf), "%d", prev_section_line_number);
if (!err) err = map(section_exports, "s-prev", 1, buf, 1);
if (!err) err = map_block_keep(section_exports, "s-prev-exists");
}
return JB_ERR_MEMORY;
}
- snprintf(buf, 150, "%d", line_number);
+ snprintf(buf, sizeof(buf), "%d", line_number);
err = map(url_exports, "p", 1, buf, 1);
- snprintf(buf, 150, "%d", url_1_2);
+ snprintf(buf, sizeof(buf), "%d", url_1_2);
if (!err) err = map(url_exports, "url-1-2", 1, buf, 1);
if (!err) err = map(url_exports, "url-html", 1,
/* Could also do section-specific exports here, but it wouldn't be as fast */
- snprintf(buf, 150, "%d", line_number);
+ snprintf(buf, sizeof(buf), "%d", line_number);
if (!err) err = map(section_exports, "s-next", 1, buf, 1);
if ( (cur_line != NULL)
}
}
- if (!err) err = map_radio(exports, "filter-all", "nx",
- (cur_line->data.action->multi_remove_all[ACTION_MULTI_FILTER] ? 'n' : 'x'));
+ /* Check or uncheck the "disable all of this type" radio buttons. */
+ for (i = 0; i < MAX_FILTER_TYPES; i++)
+ {
+ const int a = filter_type_info[i].multi_action_index;
+ const int disable_all = cur_line->data.action->multi_remove_all[a];
+ if (err) break;
+ err = map_radio(exports, filter_type_info[i].disable_all_option, "nx", (disable_all ? 'n' : 'x'));
+ }
edit_free_file(file);
char target[1024];
jb_err err;
int filter_identifier;
+ int i;
const char * action_set_name;
- char ch;
struct file_list * fl;
struct url_actions * b;
{
if (!strncmp(b->url->spec, "standard.", 9) && !strcmp(b->url->spec + 9, action_set_name))
{
- copy_action(cur_line->data.action, b->action);
+ copy_action(cur_line->data.action, b->action);
goto found;
}
}
err = actions_from_radio(parameters, cur_line->data.action);
}
- if(err)
+ if (err)
{
/* Out of memory */
edit_free_file(file);
return err;
}
- ch = get_char_param(parameters, "filter_all");
- if (ch == 'N')
+ /* Check the "disable all of this type" parameters. */
+ for (i = 0; i < MAX_FILTER_TYPES; i++)
{
- list_remove_all(cur_line->data.action->multi_add[ACTION_MULTI_FILTER]);
- list_remove_all(cur_line->data.action->multi_remove[ACTION_MULTI_FILTER]);
- cur_line->data.action->multi_remove_all[ACTION_MULTI_FILTER] = 1;
- }
- else if (ch == 'X')
- {
- cur_line->data.action->multi_remove_all[ACTION_MULTI_FILTER] = 0;
+ const int multi_action_index = filter_type_info[i].multi_action_index;
+ const char ch = get_char_param(parameters, filter_type_info[i].disable_all_param);
+
+ if (ch == 'N')
+ {
+ list_remove_all(cur_line->data.action->multi_add[multi_action_index]);
+ list_remove_all(cur_line->data.action->multi_remove[multi_action_index]);
+ cur_line->data.action->multi_remove_all[multi_action_index] = 1;
+ }
+ else if (ch == 'X')
+ {
+ cur_line->data.action->multi_remove_all[multi_action_index] = 0;
+ }
}
for (filter_identifier = 0; !err; filter_identifier++)
return cgi_redirect(rsp, target);
}
-#ifdef FEATURE_TOGGLE
-/*********************************************************************
- *
- * Function : cgi_toggle
- *
- * Description : CGI function that adds a new empty section to
- * an actions file.
- *
- * Parameters :
- * 1 : csp = Current client state (buffers, headers, etc...)
- * 2 : rsp = http_response data structure for output
- * 3 : parameters = map of cgi parameters
- *
- * CGI Parameters :
- * set : If present, how to change toggle setting:
- * "enable", "disable", "toggle", or none (default).
- * mini : If present, use mini reply template.
- *
- * Returns : JB_ERR_OK on success
- * JB_ERR_MEMORY on out-of-memory
- *
- *********************************************************************/
-jb_err cgi_toggle(struct client_state *csp,
- struct http_response *rsp,
- const struct map *parameters)
-{
- struct map *exports;
- char mode;
- const char *template_name;
-
- assert(csp);
- assert(rsp);
- assert(parameters);
-
- if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_TOGGLE))
- {
- return cgi_error_disabled(csp, rsp);
- }
-
- mode = get_char_param(parameters, "set");
-
- if (mode == 'E')
- {
- /* Enable */
- global_toggle_state = 1;
- }
- else if (mode == 'D')
- {
- /* Disable */
- global_toggle_state = 0;
- }
- else if (mode == 'T')
- {
- /* Toggle */
- global_toggle_state = !global_toggle_state;
- }
-
- if (NULL == (exports = default_exports(csp, "toggle")))
- {
- return JB_ERR_MEMORY;
- }
-
- template_name = (get_char_param(parameters, "mini")
- ? "toggle-mini"
- : "toggle");
-
- return template_fill_for_cgi(csp, template_name, exports, rsp);
-}
-#endif /* def FEATURE_TOGGLE */
/*********************************************************************
*
static jb_err actions_to_radio(struct map * exports,
const struct action_spec *action)
{
- unsigned mask = action->mask;
- unsigned add = action->add;
+ unsigned long mask;
+ unsigned long add;
int mapped_param;
int checked;
char current_mode;
return err;
}
+#endif /* def FEATURE_CGI_EDIT_ACTIONS */
-#endif /* def FEATURE_CGI_EDIT_ACTIONS */
+#ifdef FEATURE_TOGGLE
+/*********************************************************************
+ *
+ * Function : cgi_toggle
+ *
+ * Description : CGI function that adds a new empty section to
+ * an actions file.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : rsp = http_response data structure for output
+ * 3 : parameters = map of cgi parameters
+ *
+ * CGI Parameters :
+ * set : If present, how to change toggle setting:
+ * "enable", "disable", "toggle", or none (default).
+ * mini : If present, use mini reply template.
+ *
+ * Returns : JB_ERR_OK on success
+ * JB_ERR_MEMORY on out-of-memory
+ *
+ *********************************************************************/
+jb_err cgi_toggle(struct client_state *csp,
+ struct http_response *rsp,
+ const struct map *parameters)
+{
+ struct map *exports;
+ char mode;
+ const char *template_name;
+
+ assert(csp);
+ assert(rsp);
+ assert(parameters);
+
+ if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_TOGGLE))
+ {
+ return cgi_error_disabled(csp, rsp);
+ }
+
+ mode = get_char_param(parameters, "set");
+
+ if (mode == 'E')
+ {
+ /* Enable */
+ global_toggle_state = 1;
+ }
+ else if (mode == 'D')
+ {
+ /* Disable */
+ global_toggle_state = 0;
+ }
+ else if (mode == 'T')
+ {
+ /* Toggle */
+ global_toggle_state = !global_toggle_state;
+ }
+
+ if (NULL == (exports = default_exports(csp, "toggle")))
+ {
+ return JB_ERR_MEMORY;
+ }
+
+ template_name = (get_char_param(parameters, "mini")
+ ? "toggle-mini"
+ : "toggle");
+
+ return template_fill_for_cgi(csp, template_name, exports, rsp);
+}
+#endif /* def FEATURE_TOGGLE */
/*