X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=cgiedit.c;h=6d742b7cb3c0a1192b175b17278117585f8db62b;hp=2fb01eef808aa0b5562268fb7170886c24f18a13;hb=25364012f3b93349a1978e58e7f0b412a58d6faf;hpb=9115704d9decdf66f3bc822a76f2df1c38333ae1 diff --git a/cgiedit.c b/cgiedit.c index 2fb01eef..6d742b7c 100644 --- a/cgiedit.c +++ b/cgiedit.c @@ -1,4 +1,4 @@ -const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.50 2007/03/29 11:40:34 fabiankeil Exp $"; +const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.61 2008/03/24 18:12:52 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgiedit.c,v $ @@ -15,7 +15,7 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.50 2007/03/29 11:40:34 fabiankeil * * 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 @@ -42,6 +42,55 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.50 2007/03/29 11:40:34 fabiankeil * * Revisions : * $Log: cgiedit.c,v $ + * 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. + * + * Revision 1.56 2007/08/05 13:47:03 fabiankeil + * #1763173 from Stefan Huehner: s@const static@static const@. + * + * Revision 1.55 2007/05/31 11:50:20 fabiankeil + * Re-enable support for old-school URLs like + * http://config.privoxy.org/edit-actions-list?f=default + * in the action editor. + * + * They are no longer used by the CGI pages, but make it easier + * to reach the editor directly, without knowing the requested + * file's index in csp->config->actions_file[]. + * + * Revision 1.54 2007/05/14 10:33:51 fabiankeil + * - Use strlcpy() and strlcat() instead of strcpy() and strcat(). + * + * Revision 1.53 2007/04/15 16:39:20 fabiankeil + * Introduce tags as alternative way to specify which + * actions apply to a request. At the moment tags can be + * created based on client and server headers. + * + * Revision 1.52 2007/04/12 10:41:23 fabiankeil + * - Don't mistake VC++'s _snprintf() for a snprintf() replacement. + * - Move some cgi_edit_actions_for_url() variables into structs. + * - Remove bogus comment. + * + * Revision 1.51 2007/04/08 13:21:05 fabiankeil + * Reference action files in CGI URLs by id instead + * of using the first part of the file name. + * Fixes BR 1694250 and BR 1590556. + * * Revision 1.50 2007/03/29 11:40:34 fabiankeil * Divide @filter-params@ into @client-header-filter-params@ * @content-filter-params@ and @server-header-filter-params@. @@ -347,10 +396,6 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.50 2007/03/29 11:40:34 fabiankeil #include #include -#ifdef _WIN32 -#define snprintf _snprintf -#endif /* def _WIN32 */ - #include "project.h" #include "cgi.h" #include "cgiedit.h" @@ -465,6 +510,11 @@ struct file_line /** 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 @@ -474,7 +524,7 @@ struct editable_file { struct file_line * lines; /**< The contents of the file. A linked list of lines. */ const char * filename; /**< Full pathname - e.g. "/etc/privoxy/wibble.action". */ - int identifier; /**< The file name's position in csp->config->actions_file[]. */ + unsigned identifier; /**< The file name's position in csp->config->actions_file[]. */ const char * version_str; /**< Last modification time, as a string. For CGI param. */ /**< Can be used in URL without using url_param(). */ unsigned version; /**< Last modification time - prevents chaos with @@ -491,6 +541,64 @@ struct editable_file (Statically allocated) */ }; +/** + * Information about the filter types. + * Used for macro replacement in cgi_edit_actions_for_url. + */ +struct filter_type_info +{ + const int multi_action_index; /**< The multi action index as defined in project.h */ + const char *macro_name; /**< Name of the macro that has to be replaced + with the prepared templates. + 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, + for example "SERVER-HEADER-FILTER" */ +}; + +/* Accessed by index, keep the order in the way the FT_ macros are defined. */ +static const struct filter_type_info filter_type_info[] = +{ + { + 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" + }, +}; + /* FIXME: Following non-static functions should be prototyped in .h or made static */ /* Functions to read and write arbitrary config files */ @@ -558,6 +666,11 @@ static jb_err map_copy_parameter_url(struct map *out, const char *name); #endif /* unused function */ +static jb_err get_file_name_param(struct client_state *csp, + const struct map *parameters, + const char *param_name, + const char **pfilename); + /* Internal convenience functions */ static char *section_target(const unsigned sectionid); @@ -584,7 +697,7 @@ static char *section_target(const unsigned sectionid) { char buf[30]; - snprintf(buf, 30, "#l%d", sectionid); + snprintf(buf, sizeof(buf), "#l%d", sectionid); return(strdup(buf)); } @@ -602,7 +715,7 @@ static char *section_target(const unsigned sectionid) * Returns : String with link target, or NULL if out of memory * *********************************************************************/ -static char *stringify(const int number) +static char *stringify(const unsigned number) { char buf[6]; @@ -1134,8 +1247,8 @@ jb_err edit_write_file(struct editable_file * file) /* 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) { @@ -1789,13 +1902,13 @@ jb_err edit_read_file(struct client_state *csp, struct file_line * lines; FILE * fp; jb_err err; - const char * filename = NULL; + const char *filename = NULL; struct editable_file * file; unsigned version = 0; struct stat statbuf[1]; char version_buf[22]; int newline = NEWLINE_UNKNOWN; - int i; + unsigned i; assert(csp); assert(parameters); @@ -1803,22 +1916,21 @@ jb_err edit_read_file(struct client_state *csp, *pfile = NULL; - if ((JB_ERR_OK == get_number_param(csp, parameters, "f", &i)) - && (i < MAX_AF_FILES) && (NULL != csp->config->actions_file[i])) + err = get_number_param(csp, parameters, "f", &i); + if ((JB_ERR_OK == err) && (i < MAX_AF_FILES) && (NULL != csp->config->actions_file[i])) + { + filename = csp->config->actions_file[i]; + } + else if (JB_ERR_CGI_PARAMS == err) { /* - * i is guaranteed to be non-negative because - * get_number_param returned JB_ERR_OK. - * - * XXX: This comment wouldn't be necessary if - * get_number_param's fourth parameter would simply - * be changed to unsigned. I don't see the point of - * overloading its meaning to signal problems. + * Probably an old-school URL like + * http://config.privoxy.org/edit-actions-list?f=default */ - filename = csp->config->actions_file[i]; + err = get_file_name_param(csp, parameters, "f", &filename); } - if (filename == NULL || stat(filename, statbuf) < 0) + if (NULL == filename || stat(filename, statbuf) < 0) { /* Error, probably file not found. */ return JB_ERR_FILE; @@ -1869,8 +1981,8 @@ jb_err edit_read_file(struct client_state *csp, /* 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) { @@ -1928,6 +2040,7 @@ jb_err edit_read_actions_file(struct client_state *csp, { jb_err err; struct editable_file *file; + static int acceptable_failures = ACCEPTABLE_TIMESTAMP_MISMATCHES - 1; assert(csp); assert(parameters); @@ -1945,7 +2058,24 @@ jb_err edit_read_actions_file(struct client_state *csp, } 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) { @@ -1982,41 +2112,21 @@ jb_err edit_read_actions_file(struct client_state *csp, } -#if 0 -/* - * Currently not needed, but may become useful again in the future. - */ /********************************************************************* * * Function : get_file_name_param * * Description : Get the name of the file to edit from the parameters - * passed to a CGI function. This function handles - * security checks such as blocking urls containing - * "/" or ".", prepending the config file directory, - * and adding the specified suffix. - * - * (This is an essential security check, otherwise - * users may be able to pass "../../../etc/passwd" - * and overwrite the password file [linux], "prn:" - * and print random data [Windows], etc...) - * - * This function only allows filenames contining the - * characters '-', '_', 'A'-'Z', 'a'-'z', and '0'-'9'. - * That's probably too restrictive but at least it's - * secure. + * passed to a CGI function using the old syntax. + * This function handles security checks and only + * accepts files that Privoxy already knows. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : parameters = map of cgi parameters * 3 : param_name = The name of the parameter to read - * 4 : suffix = File extension, e.g. ".actions" - * 5 : pfilename = destination for full filename. Caller - * free()s. Set to NULL on error. - * 6 : pparam = destination for partial filename, - * suitable for use in another URL. Allocated as part - * of the map "parameters", so don't free it. - * Set to NULL if not specified. + * 4 : pfilename = pointer to the filename in + * csp->config->actions_file[] if found. Set to NULL on error. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory @@ -2027,25 +2137,23 @@ jb_err edit_read_actions_file(struct client_state *csp, static jb_err get_file_name_param(struct client_state *csp, const struct map *parameters, const char *param_name, - const char *suffix, - char **pfilename, - const char **pparam) + const char **pfilename) { const char *param; + const char suffix[] = ".action"; const char *s; char *name; char *fullpath; char ch; size_t len; + size_t name_size; + int i; assert(csp); assert(parameters); - assert(suffix); assert(pfilename); - assert(pparam); *pfilename = NULL; - *pparam = NULL; param = lookup(parameters, param_name); if (!*param) @@ -2053,8 +2161,6 @@ static jb_err get_file_name_param(struct client_state *csp, return JB_ERR_CGI_PARAMS; } - *pparam = param; - len = strlen(param); if (len >= FILENAME_MAX) { @@ -2062,7 +2168,10 @@ static jb_err get_file_name_param(struct client_state *csp, return JB_ERR_CGI_PARAMS; } - /* Check every character to see if it's legal */ + /* + * Check every character to see if it's legal. + * Totally unnecessary but we do it anyway. + */ s = param; while ((ch = *s++) != '\0') { @@ -2078,13 +2187,14 @@ static jb_err get_file_name_param(struct client_state *csp, } /* Append extension */ - name = malloc(len + strlen(suffix) + 1); + name_size = len + strlen(suffix) + 1; + name = malloc(name_size); if (name == NULL) { return JB_ERR_MEMORY; } - strcpy(name, param); - strcpy(name + len, suffix); + strlcpy(name, param, name_size); + strlcat(name, suffix, name_size); /* Prepend path */ fullpath = make_path(csp->config->confdir, name); @@ -2095,12 +2205,23 @@ static jb_err get_file_name_param(struct client_state *csp, return JB_ERR_MEMORY; } - /* Success */ - *pfilename = fullpath; + /* Check if the file is known */ + for (i = 0; i < MAX_AF_FILES; i++) + { + if (NULL != csp->config->actions_file[i] && + !strcmp(fullpath, csp->config->actions_file[i])) + { + /* Success */ + *pfilename = csp->config->actions_file[i]; + freez(fullpath); - return JB_ERR_OK; + return JB_ERR_OK; + } + } + freez(fullpath); + + return JB_ERR_CGI_PARAMS; } -#endif /*0*/ /********************************************************************* @@ -2261,23 +2382,25 @@ static jb_err map_radio(struct map * exports, const char * values, int value) { - size_t len; char * buf; char * p; char c; + const size_t len = strlen(optionname); + const size_t buf_size = len + 3; assert(exports); assert(optionname); assert(values); - len = strlen(optionname); - buf = malloc(len + 3); + buf = malloc(buf_size); if (buf == NULL) { return JB_ERR_MEMORY; } - strcpy(buf, optionname); + strlcpy(buf, optionname, buf_size); + + /* XXX: this looks ... interesting */ p = buf + len; *p++ = '-'; p[1] = '\0'; @@ -2583,6 +2706,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp, if (err) { /* No filename specified, can't read file, or out of memory. */ + free_map(exports); return (err == JB_ERR_FILE ? JB_ERR_OK : err); } @@ -2683,9 +2807,9 @@ jb_err cgi_edit_actions_list(struct client_state *csp, */ 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); @@ -2763,7 +2887,6 @@ jb_err cgi_edit_actions_list(struct client_state *csp, free(url_template); edit_free_file(file); free_map(exports); - free(url_template); return err; } @@ -2797,7 +2920,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp, 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); @@ -2817,7 +2940,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp, 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"); } @@ -2871,10 +2994,10 @@ jb_err cgi_edit_actions_list(struct client_state *csp, 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, @@ -2937,7 +3060,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp, /* 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) @@ -3142,11 +3265,14 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, /* * List available filters and their settings. */ - char *content_filter_params; - char *server_header_filter_params; - char *client_header_filter_params; char *filter_template; int filter_identifier = 0; + char *prepared_templates[MAX_FILTER_TYPES]; + + for (i = 0; i < MAX_FILTER_TYPES; i++) + { + prepared_templates[i] = strdup(""); + } err = template_load(csp, &filter_template, "edit-actions-for-url-filter", 0); if (err) @@ -3162,10 +3288,6 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, err = template_fill(&filter_template, exports); - content_filter_params = strdup(""); - server_header_filter_params = strdup(""); - client_header_filter_params = strdup(""); - for (i = 0; i < MAX_AF_FILES; i++) { if ((csp->rlist[i] != NULL) && (csp->rlist[i]->f != NULL)) @@ -3175,46 +3297,12 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, { char current_mode = 'x'; char number[20]; - int multi_action_index = 0; struct list_entry *filter_name; struct map *line_exports; - char *this_line; - char *filter_type; - char *abbr_filter_type; - char *anchor; - char **current_params; + const int type = filter_group->type; + const int multi_action_index = filter_type_info[type].multi_action_index; - switch (filter_group->type) - { - case FT_CONTENT_FILTER: - /* XXX: Should we call it content-filter instead? */ - filter_type = "filter"; - abbr_filter_type = "F"; - multi_action_index = ACTION_MULTI_FILTER; - anchor = "FILTER"; - current_params = &content_filter_params; - break; - case FT_SERVER_HEADER_FILTER: - filter_type = "server-header-filter"; - abbr_filter_type = "S"; - multi_action_index = ACTION_MULTI_SERVER_HEADER_FILTER; - current_params = &server_header_filter_params; - anchor = "SERVER-HEADER-FILTER"; /* XXX: no documentation available yet */ - break; - case FT_CLIENT_HEADER_FILTER: - filter_type = "client-header-filter"; - abbr_filter_type = "C"; - multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER; - current_params = &client_header_filter_params; - anchor = "CLIENT-HEADER-FILTER"; /* XXX: no documentation available yet */ - break; - default: - log_error(LOG_LEVEL_FATAL, - "cgi_edit_actions_for_url: Unknown filter type: %u for filter %s.", - filter_group->type, filter_group->name); - /* Not reached. */ - } - assert(multi_action_index); + assert(type < MAX_FILTER_TYPES); filter_name = cur_line->data.action->multi_add[multi_action_index]->first; while ((filter_name != NULL) @@ -3249,26 +3337,26 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, if (line_exports == NULL) { err = JB_ERR_MEMORY; - freez(*current_params); /* XXX: really necessary? */ } else { + char *filter_line; + if (!err) err = map(line_exports, "index", 1, number, 1); if (!err) err = map(line_exports, "name", 1, filter_group->name, 1); if (!err) err = map(line_exports, "description", 1, filter_group->description, 1); if (!err) err = map_radio(line_exports, "this-filter", "ynx", current_mode); - if (!err) err = map(line_exports, "filter-type", 1, filter_type, 1); - if (!err) err = map(line_exports, "abbr-filter-type", 1, abbr_filter_type, 1); - if (!err) err = map(line_exports, "anchor", 1, anchor, 1); + if (!err) err = map(line_exports, "filter-type", 1, filter_type_info[type].type, 1); + if (!err) err = map(line_exports, "abbr-filter-type", 1, filter_type_info[type].abbr_type, 1); + if (!err) err = map(line_exports, "anchor", 1, filter_type_info[type].anchor, 1); - this_line = NULL; if (!err) { - this_line = strdup(filter_template); - if (this_line == NULL) err = JB_ERR_MEMORY; + filter_line = strdup(filter_template); + if (filter_line == NULL) err = JB_ERR_MEMORY; } - if (!err) err = template_fill(&this_line, line_exports); - string_join(current_params, this_line); + if (!err) err = template_fill(&filter_line, line_exports); + string_join(&prepared_templates[type], filter_line); free_map(line_exports); } @@ -3277,19 +3365,31 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, } freez(filter_template); - if (!err) err = map(exports, "content-filter-params", 1, content_filter_params, 0); - if (!err) err = map(exports, "server-header-filter-params", 1, server_header_filter_params, 0); - if (!err) err = map(exports, "client-header-filter-params", 1, client_header_filter_params, 0); + /* Replace all filter macros with the aggregated templates */ + for (i = 0; i < MAX_FILTER_TYPES; i++) + { + if (err) break; + err = map(exports, filter_type_info[i].macro_name, 1, prepared_templates[i], 0); + } + if (err) { - freez(content_filter_params); - freez(server_header_filter_params); - freez(client_header_filter_params); + /* Free aggregated templates */ + for (i = 0; i < MAX_FILTER_TYPES; i++) + { + freez(prepared_templates[i]); + } } } - 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); @@ -3329,6 +3429,7 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, unsigned sectionid; char * actiontext; char * newtext; + size_t newtext_size; size_t len; struct editable_file * file; struct file_line * cur_line; @@ -3336,8 +3437,8 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, 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; @@ -3387,7 +3488,7 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, { 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; } } @@ -3403,23 +3504,29 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, 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++) @@ -3467,6 +3574,12 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, case 'C': multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER; break; + case 'L': + multi_action_index = ACTION_MULTI_CLIENT_HEADER_TAGGER; + break; + case 'E': + multi_action_index = ACTION_MULTI_SERVER_HEADER_TAGGER; + break; default: log_error(LOG_LEVEL_ERROR, "Unknown filter type: %c for filter %s. Filter ignored.", type, name); @@ -3521,14 +3634,15 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, len = 1; } - if (NULL == (newtext = malloc(len + 2))) + newtext_size = len + 2; + if (NULL == (newtext = malloc(newtext_size))) { /* Out of memory */ free(actiontext); edit_free_file(file); return JB_ERR_MEMORY; } - strcpy(newtext, actiontext); + strlcpy(newtext, actiontext, newtext_size); free(actiontext); newtext[0] = '{'; newtext[len] = '}'; @@ -4400,75 +4514,6 @@ jb_err cgi_edit_actions_section_swap(struct client_state *csp, 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 */ /********************************************************************* * @@ -4783,9 +4828,78 @@ static jb_err actions_from_radio(const struct map * parameters, 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 */ /*