/* renattach 1.2.4 - Filter that renames/deletes dangerous email attachments Copyright (C) 2003-2006 Jem E. Berkes This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "renattach.h" #include "strings-en.h" #include "utility.h" #include #include #include #include #ifndef HAVE_STRCASECMP #define strcasecmp stricmp #endif #ifndef HAVE_STRNCASECMP #define strncasecmp strnicmp #endif /* Iterates through the list and returns the number of entries within. If verbose is specified, each entry is displayed. */ int tokenize_list(const char* thelist, int verbose) { char *tmpbuf, *token; int count=0; tmpbuf = malloc(strlen(thelist) + 1); strcpy(tmpbuf, thelist); token = strtok(tmpbuf, LIST_TOKENS); while (token) { if (verbose) { if (count) fprintf(stderr, "|%s", token); else fprintf(stderr, "%s", token); } count++; token = strtok(NULL, LIST_TOKENS); } free(tmpbuf); return count; } /* Parse the configuration file and fill in the options structure Any errors found are written to stderr. Returns CODE_OK or CODE_FAILURE */ int parse_conf(struct config_opts* options) { int linecount = 0; char confline[MAXFIELD]; char directive[MAXFIELD], parameter[MAXFIELD]; FILE* config = NULL; if (options->config_file == NULL) { fprintf(stderr, TXT_INFO_CONFIGFILE TXT_INFO_UNDEF "\n"); return CODE_FAILURE; } config = fopen(options->config_file, "r"); if (!config) { perror(options->config_file); return CODE_FAILURE; } while (fgets(confline, sizeof(confline), config)) { int syntax_error = 0; linecount++; trim_leading(confline); trim_trailing(confline); if ((*confline == '#') || (*confline == '\r') || (*confline == '\n')) continue; if (sscanf(confline, "%[^\t =]%*[\t =]%[^\r\n]", directive, parameter) == 2) { int state = OPTION_UNSET; if ( (strncasecmp(parameter, TAG_OPTENABLED, strlen(TAG_OPTENABLED))==0) || (*parameter=='1')) /* 'yes' or 1 */ state = OPTION_ENABLED; else if ( (strncasecmp(parameter, TAG_OPTDISABLED, strlen(TAG_OPTDISABLED))==0) || (*parameter=='0')) /* 'no' or 0 */ state = OPTION_DISABLED; if ((strcasecmp(directive, TAG_DELETE_EXE)==0) && state) options->delete_exe = state; else if ((strcasecmp(directive, TAG_KILL_EXE)==0) && state) options->kill_exe = state; else if ((strcasecmp(directive, TAG_SEARCH_ZIP)==0) && state) options->search_zip = state; else if ((strcasecmp(directive, TAG_PASS_CONTENTID)==0) && state) options->pass_contentid = state; else if ((strcasecmp(directive, TAG_FULL_RENAME)==0) && state) options->full_rename = state; else if ((strcasecmp(directive, TAG_USE_SYSLOG)==0) && state) options->use_syslog = state; else if (strcasecmp(directive, TAG_GENERIC_NAME) == 0) strcpy(options->generic_name, parameter); else if (strcasecmp(directive, TAG_NEW_EXTENSION) == 0) strcpy(options->new_extension, parameter); else if (strcasecmp(directive, TAG_NEW_MIME_TYPE) == 0) strcpy(options->new_mime_type, parameter); else if (strcasecmp(directive, TAG_SUBJ_BANNED) == 0) strcpy(options->subj_banned, parameter); else if (strcasecmp(directive, TAG_SUBJ_EXEC) == 0) strcpy(options->subj_exec, parameter); else if (strcasecmp(directive, TAG_SUBJ_DELETED) == 0) strcpy(options->subj_deleted, parameter); else if (strcasecmp(directive, TAG_SUBJ_RENAMED) == 0) strcpy(options->subj_renamed, parameter); else if (strcasecmp(directive, TAG_ADD_SUBJECT) == 0) strcpy(options->add_subject, parameter); else if (strcasecmp(directive, TAG_HTMLWARN_POS) == 0) strcpy(options->htmlwarn_pos, parameter); else if (strcasecmp(directive, TAG_WARNING_TEXT) == 0) expand_list(&options->warning_text, parameter, "\n"); else if (strcasecmp(directive, TAG_WARNING_HTML) == 0) expand_list(&options->warning_html, parameter, "\n"); else if (strcasecmp(directive, TAG_ADD_HEADER) == 0) expand_list(&options->add_header, parameter, "\n"); else if (strcasecmp(directive, TAG_BANNED_FILES) == 0) expand_list(&options->banned_files, parameter, "\n"); else if (strcasecmp(directive, TAG_BADLIST) == 0) expand_list(&options->badlist, parameter, "\n"); else if (strcasecmp(directive, TAG_GOODLIST) == 0) expand_list(&options->goodlist, parameter, "\n"); else syntax_error = 1; } else syntax_error = 1; if (syntax_error) { fprintf(stderr, TXT_ERR_CONFSYNTAX "%d: %s\n", linecount, confline); fclose(config); return CODE_FAILURE; } } fclose(config); return CODE_OK; } /* Check all configuration directives If any are unset, use defaults */ void directive_defaults(struct config_opts* options) { if (options->delete_exe == OPTION_UNSET) options->delete_exe = DEF_DELETE_EXE; if (options->kill_exe == OPTION_UNSET) options->kill_exe = DEF_KILL_EXE; if (options->search_zip == OPTION_UNSET) options->search_zip = DEF_SEARCH_ZIP; if (options->pass_contentid == OPTION_UNSET) options->pass_contentid = DEF_PASS_CONTENTID; if (options->full_rename == OPTION_UNSET) options->full_rename = DEF_FULL_RENAME; if (options->use_syslog == OPTION_UNSET) options->use_syslog = DEF_USE_SYSLOG; if (options->generic_name[0] == '\0') strcpy(options->generic_name, DEF_GENERIC_NAME); if (options->new_extension[0] == '\0') strcpy(options->new_extension, DEF_NEW_EXTENSION); if (options->new_mime_type[0] == '\0') strcpy(options->new_mime_type, DEF_NEW_MIME_TYPE); if (options->subj_banned[0] == '\0') strcpy(options->subj_banned, DEF_SUBJ_BANNED); if (options->subj_exec[0] == '\0') strcpy(options->subj_exec, DEF_SUBJ_EXEC); if (options->subj_deleted[0] == '\0') strcpy(options->subj_deleted, DEF_SUBJ_DELETED); if (options->subj_renamed[0] == '\0') strcpy(options->subj_renamed, DEF_SUBJ_RENAMED); if (options->add_subject[0] == '\0') strcpy(options->add_subject, DEF_ADD_SUBJECT); if (options->htmlwarn_pos[0] == '\0') strcpy(options->htmlwarn_pos, DEF_HTMLWARN_POS); if ( (options->warning_text == NULL) || (options->warning_text[0] == '\0')) expand_list(&options->warning_text, DEF_WARNING_TEXT, "\n"); if ( (options->warning_html == NULL) || (options->warning_html[0] == '\0')) expand_list(&options->warning_html, DEF_WARNING_HTML, "\n"); if ( (options->add_header == NULL) || (options->add_header[0] == '\0')) expand_list(&options->add_header, DEF_ADD_HEADER, "\n"); if ( (options->banned_files == NULL) || (tokenize_list(options->banned_files, 0)==0) ) expand_list(&options->banned_files, DEF_BANNED_FILES, "\n"); if ( (options->goodlist == NULL) || (tokenize_list(options->goodlist, 0)==0) ) expand_list(&options->goodlist, DEF_GOODLIST, "\n"); if ( (options->badlist == NULL) || (tokenize_list(options->badlist, 0)==0) ) expand_list(&options->badlist, DEF_BADLIST, "\n"); } /* Show current configuration; used in verbose mode */ void show_configuration(struct config_opts* options) { /* Where is our configuration file? */ fprintf(stderr, TXT_INFO_CONFIGFILE "\n "); if (options->config_file) fprintf(stderr, "%s\n", options->config_file); else fprintf(stderr, TXT_INFO_UNDEF "\n"); fprintf(stderr, TXT_INFO_OUTPUT "\n "); if (options->pipe_cmd) { int arg = 0; fprintf(stderr, "{"); while (options->pipe_cmd[arg]) { if (arg) fprintf(stderr, "|"); fprintf(stderr, "%s", options->pipe_cmd[arg++]); } fprintf(stderr, "}\n"); } else fprintf(stderr, TXT_INFO_STDOUT "\n"); /* What filtering mode are we using? */ fprintf(stderr, TXT_INFO_MODE "\n %s\n", mode2str(options->mode)); /* What filtering action are we using? */ fprintf(stderr, TXT_INFO_ACTION "\n %s\n", act2str(options->action)); fprintf(stderr, TXT_INFO_CONFOPTS "\n"); /* Show status of all settings from renattach.conf */ fprintf(stderr, " "TAG_DELETE_EXE ": %s\n", opt2str(options->delete_exe)); fprintf(stderr, " "TAG_KILL_EXE ": %s\n", opt2str(options->kill_exe)); fprintf(stderr, " "TAG_SEARCH_ZIP ": %s\n", opt2str(options->search_zip)); fprintf(stderr, " "TAG_PASS_CONTENTID ": %s\n", opt2str(options->pass_contentid)); fprintf(stderr, " "TAG_FULL_RENAME ": %s\n", opt2str(options->full_rename)); fprintf(stderr, " "TAG_USE_SYSLOG ": %s\n", opt2str(options->use_syslog)); fprintf(stderr, " "TAG_GENERIC_NAME ": \"%s\"\n", options->generic_name); fprintf(stderr, " "TAG_NEW_EXTENSION ": \"%s\"\n", options->new_extension); fprintf(stderr, " "TAG_NEW_MIME_TYPE ": \"%s\"\n", options->new_mime_type); fprintf(stderr, " "TAG_SUBJ_BANNED ": \"%s\"\n", options->subj_banned); fprintf(stderr, " "TAG_SUBJ_EXEC ": \"%s\"\n", options->subj_exec); fprintf(stderr, " "TAG_SUBJ_DELETED ": \"%s\"\n", options->subj_deleted); fprintf(stderr, " "TAG_SUBJ_RENAMED ": \"%s\"\n", options->subj_renamed); fprintf(stderr, " "TAG_ADD_SUBJECT ": \"%s\"\n", options->add_subject); fprintf(stderr, " "TAG_HTMLWARN_POS ": \"%s\"\n", options->htmlwarn_pos); fprintf(stderr, " "TAG_WARNING_TEXT ": %d bytes,\n%s\n", (int)strlen(options->warning_text), options->warning_text); fprintf(stderr, " "TAG_WARNING_HTML ": %d bytes,\n%s\n", (int)strlen(options->warning_html), options->warning_html); fprintf(stderr, " "TAG_ADD_HEADER ": %d bytes,\n%s\n", (int)strlen(options->add_header), options->add_header); fprintf(stderr, " "TAG_BANNED_FILES ": {"); tokenize_list(options->banned_files, 1); fprintf(stderr, "}\n "TAG_BADLIST ": {"); tokenize_list(options->badlist, 1); fprintf(stderr, "}\n " TAG_GOODLIST ": {"); tokenize_list(options->goodlist, 1); fprintf(stderr, "}\n"); } /* Return description of directive state */ const char* opt2str(int state) { if (state == OPTION_DISABLED) return TAG_OPTDISABLED; else if (state == OPTION_ENABLED) return TAG_OPTENABLED; else return TXT_INFO_UNDEF; } /* Return description of filter mode */ const char* mode2str(int mode) { if (mode == MODE_ALL) return TXT_INFO_MODEALL; else if (mode == MODE_BAD) return TXT_INFO_MODEBAD; else if (mode == MODE_GOOD) return TXT_INFO_MODEGOOD; else return TXT_INFO_UNDEF; } /* Return description of action type */ const char* act2str(int action) { switch (action) { case ACTION_RENAME: return TAG_ACTRENAME; case ACTION_DELETE: return TAG_ACTDELETE; case ACTION_KILL: return TAG_ACTKILL; case ACTION_SKIP: return TAG_ACTSKIP; default: return TXT_INFO_UNDEF; } }