1 /*
2  renattach 1.2.4 - Filter that renames/deletes dangerous email attachments
3  Copyright (C) 2003-2006  Jem E. Berkes <jberkes@pc-tools.net>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19 */
20 
21 #include "config.h"
22 #include "renattach.h"
23 #include "strings-en.h"
24 #include "utility.h"
25 #include <memory.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #ifndef HAVE_STRCASECMP
31 #define strcasecmp stricmp
32 #endif
33 
34 #ifndef HAVE_STRNCASECMP
35 #define strncasecmp strnicmp
36 #endif
37 
38 
39 
40 /*
41 	Iterates through the list and returns the number of entries within.
42 	If verbose is specified, each entry is displayed.
43 */
tokenize_list(const char * thelist,int verbose)44 int tokenize_list(const char* thelist, int verbose)
45 {
46 	char *tmpbuf, *token;
47 	int count=0;
48 
49 	tmpbuf = malloc(strlen(thelist) + 1);
50 	strcpy(tmpbuf, thelist);
51 	token = strtok(tmpbuf, LIST_TOKENS);
52 	while (token)
53 	{
54 		if (verbose)
55 		{
56 			if (count)
57 				fprintf(stderr, "|%s", token);
58 			else
59 				fprintf(stderr, "%s", token);
60 		}
61 		count++;
62 		token = strtok(NULL, LIST_TOKENS);
63 	}
64 	free(tmpbuf);
65 	return count;
66 }
67 
68 
69 /*
70 	Parse the configuration file and fill in the options structure
71 	Any errors found are written to stderr. Returns CODE_OK or CODE_FAILURE
72 */
parse_conf(struct config_opts * options)73 int parse_conf(struct config_opts* options)
74 {
75 	int linecount = 0;
76 	char confline[MAXFIELD];
77 	char directive[MAXFIELD], parameter[MAXFIELD];
78 	FILE* config = NULL;
79 
80 	if (options->config_file == NULL)
81 	{
82 		fprintf(stderr, TXT_INFO_CONFIGFILE TXT_INFO_UNDEF "\n");
83 		return CODE_FAILURE;
84 	}
85 
86 	config = fopen(options->config_file, "r");
87 	if (!config)
88 	{
89 		perror(options->config_file);
90 		return CODE_FAILURE;
91 	}
92 
93 	while (fgets(confline, sizeof(confline), config))
94 	{
95 		int syntax_error = 0;
96 		linecount++;
97 
98 		trim_leading(confline);
99 		trim_trailing(confline);
100 
101 		if ((*confline == '#') || (*confline == '\r') || (*confline == '\n'))
102 			continue;
103 		if (sscanf(confline, "%[^\t =]%*[\t =]%[^\r\n]", directive, parameter) == 2)
104 		{
105 			int state = OPTION_UNSET;
106 			if ( (strncasecmp(parameter, TAG_OPTENABLED, strlen(TAG_OPTENABLED))==0)
107 				|| (*parameter=='1'))	/* 'yes' or 1 */
108 				state = OPTION_ENABLED;
109 			else if ( (strncasecmp(parameter, TAG_OPTDISABLED, strlen(TAG_OPTDISABLED))==0)
110 				|| (*parameter=='0'))	/* 'no' or 0 */
111 				state = OPTION_DISABLED;
112 
113 			if ((strcasecmp(directive, TAG_DELETE_EXE)==0) && state)
114 				options->delete_exe = state;
115 			else if ((strcasecmp(directive, TAG_KILL_EXE)==0) && state)
116 				options->kill_exe = state;
117 			else if ((strcasecmp(directive, TAG_SEARCH_ZIP)==0) && state)
118 				options->search_zip = state;
119 			else if ((strcasecmp(directive, TAG_PASS_CONTENTID)==0) && state)
120 				options->pass_contentid = state;
121 			else if ((strcasecmp(directive, TAG_FULL_RENAME)==0) && state)
122 				options->full_rename = state;
123 			else if ((strcasecmp(directive, TAG_USE_SYSLOG)==0) && state)
124 				options->use_syslog = state;
125 			else if (strcasecmp(directive, TAG_GENERIC_NAME) == 0)
126 				strcpy(options->generic_name, parameter);
127 			else if (strcasecmp(directive, TAG_NEW_EXTENSION) == 0)
128 				strcpy(options->new_extension, parameter);
129 			else if (strcasecmp(directive, TAG_NEW_MIME_TYPE) == 0)
130 				strcpy(options->new_mime_type, parameter);
131 			else if (strcasecmp(directive, TAG_SUBJ_BANNED) == 0)
132 				strcpy(options->subj_banned, parameter);
133 			else if (strcasecmp(directive, TAG_SUBJ_EXEC) == 0)
134 				strcpy(options->subj_exec, parameter);
135 			else if (strcasecmp(directive, TAG_SUBJ_DELETED) == 0)
136 				strcpy(options->subj_deleted, parameter);
137 			else if (strcasecmp(directive, TAG_SUBJ_RENAMED) == 0)
138 				strcpy(options->subj_renamed, parameter);
139 			else if (strcasecmp(directive, TAG_ADD_SUBJECT) == 0)
140 				strcpy(options->add_subject, parameter);
141 			else if (strcasecmp(directive, TAG_HTMLWARN_POS) == 0)
142 				strcpy(options->htmlwarn_pos, parameter);
143 			else if (strcasecmp(directive, TAG_WARNING_TEXT) == 0)
144 				expand_list(&options->warning_text, parameter, "\n");
145 			else if (strcasecmp(directive, TAG_WARNING_HTML) == 0)
146 				expand_list(&options->warning_html, parameter, "\n");
147 			else if (strcasecmp(directive, TAG_ADD_HEADER) == 0)
148 				expand_list(&options->add_header, parameter, "\n");
149 			else if (strcasecmp(directive, TAG_BANNED_FILES) == 0)
150 				expand_list(&options->banned_files, parameter, "\n");
151 			else if (strcasecmp(directive, TAG_BADLIST) == 0)
152 				expand_list(&options->badlist, parameter, "\n");
153 			else if (strcasecmp(directive, TAG_GOODLIST) == 0)
154 				expand_list(&options->goodlist, parameter, "\n");
155 			else
156 				syntax_error = 1;
157 		}
158 		else
159 			syntax_error = 1;
160 
161 		if (syntax_error)
162 		{
163 			fprintf(stderr, TXT_ERR_CONFSYNTAX "%d: %s\n", linecount, confline);
164 			fclose(config);
165 			return CODE_FAILURE;
166 		}
167 	}
168 
169 	fclose(config);
170 	return CODE_OK;
171 }
172 
173 
174 /*
175 	Check all configuration directives
176 	If any are unset, use defaults
177 */
directive_defaults(struct config_opts * options)178 void directive_defaults(struct config_opts* options)
179 {
180 	if (options->delete_exe == OPTION_UNSET)
181 		options->delete_exe = DEF_DELETE_EXE;
182 	if (options->kill_exe == OPTION_UNSET)
183 		options->kill_exe = DEF_KILL_EXE;
184 	if (options->search_zip == OPTION_UNSET)
185 		options->search_zip = DEF_SEARCH_ZIP;
186 	if (options->pass_contentid == OPTION_UNSET)
187 		options->pass_contentid = DEF_PASS_CONTENTID;
188 	if (options->full_rename == OPTION_UNSET)
189 		options->full_rename = DEF_FULL_RENAME;
190 	if (options->use_syslog == OPTION_UNSET)
191 		options->use_syslog = DEF_USE_SYSLOG;
192 	if (options->generic_name[0] == '\0')
193 		strcpy(options->generic_name, DEF_GENERIC_NAME);
194 	if (options->new_extension[0] == '\0')
195 		strcpy(options->new_extension, DEF_NEW_EXTENSION);
196 	if (options->new_mime_type[0] == '\0')
197 		strcpy(options->new_mime_type, DEF_NEW_MIME_TYPE);
198 	if (options->subj_banned[0] == '\0')
199 		strcpy(options->subj_banned, DEF_SUBJ_BANNED);
200 	if (options->subj_exec[0] == '\0')
201 		strcpy(options->subj_exec, DEF_SUBJ_EXEC);
202 	if (options->subj_deleted[0] == '\0')
203 		strcpy(options->subj_deleted, DEF_SUBJ_DELETED);
204 	if (options->subj_renamed[0] == '\0')
205 		strcpy(options->subj_renamed, DEF_SUBJ_RENAMED);
206 	if (options->add_subject[0] == '\0')
207 		strcpy(options->add_subject, DEF_ADD_SUBJECT);
208 	if (options->htmlwarn_pos[0] == '\0')
209 		strcpy(options->htmlwarn_pos, DEF_HTMLWARN_POS);
210 	if ( (options->warning_text == NULL) || (options->warning_text[0] == '\0'))
211 		expand_list(&options->warning_text, DEF_WARNING_TEXT, "\n");
212 	if ( (options->warning_html == NULL) || (options->warning_html[0] == '\0'))
213 		expand_list(&options->warning_html, DEF_WARNING_HTML, "\n");
214 	if ( (options->add_header == NULL) || (options->add_header[0] == '\0'))
215 		expand_list(&options->add_header, DEF_ADD_HEADER, "\n");
216 	if ( (options->banned_files == NULL) || (tokenize_list(options->banned_files, 0)==0) )
217 		expand_list(&options->banned_files, DEF_BANNED_FILES, "\n");
218 	if ( (options->goodlist == NULL) || (tokenize_list(options->goodlist, 0)==0) )
219 		expand_list(&options->goodlist, DEF_GOODLIST, "\n");
220 	if ( (options->badlist == NULL) || (tokenize_list(options->badlist, 0)==0) )
221 		expand_list(&options->badlist, DEF_BADLIST, "\n");
222 }
223 
224 
225 /*
226 	Show current configuration; used in verbose mode
227 */
show_configuration(struct config_opts * options)228 void show_configuration(struct config_opts* options)
229 {
230 	/* Where is our configuration file? */
231 	fprintf(stderr, TXT_INFO_CONFIGFILE "\n  ");
232 	if (options->config_file)
233 		fprintf(stderr, "%s\n", options->config_file);
234 	else
235 		fprintf(stderr, TXT_INFO_UNDEF "\n");
236 
237 	fprintf(stderr, TXT_INFO_OUTPUT "\n  ");
238 	if (options->pipe_cmd)
239 	{
240 		int arg = 0;
241 		fprintf(stderr, "{");
242 		while (options->pipe_cmd[arg])
243 		{
244 			if (arg) fprintf(stderr, "|");
245 			fprintf(stderr, "%s", options->pipe_cmd[arg++]);
246 		}
247 		fprintf(stderr, "}\n");
248 	}
249 	else
250 		fprintf(stderr, TXT_INFO_STDOUT "\n");
251 
252 	/* What filtering mode are we using? */
253 	fprintf(stderr, TXT_INFO_MODE "\n  %s\n", mode2str(options->mode));
254 
255 	/* What filtering action are we using? */
256 	fprintf(stderr, TXT_INFO_ACTION "\n  %s\n", act2str(options->action));
257 
258 	fprintf(stderr, TXT_INFO_CONFOPTS "\n");
259 	/* Show status of all settings from renattach.conf */
260 	fprintf(stderr, "  "TAG_DELETE_EXE ": %s\n", opt2str(options->delete_exe));
261 	fprintf(stderr, "  "TAG_KILL_EXE ": %s\n", opt2str(options->kill_exe));
262 	fprintf(stderr, "  "TAG_SEARCH_ZIP ": %s\n", opt2str(options->search_zip));
263 	fprintf(stderr, "  "TAG_PASS_CONTENTID ": %s\n", opt2str(options->pass_contentid));
264 	fprintf(stderr, "  "TAG_FULL_RENAME ": %s\n", opt2str(options->full_rename));
265 	fprintf(stderr, "  "TAG_USE_SYSLOG ": %s\n", opt2str(options->use_syslog));
266 	fprintf(stderr, "  "TAG_GENERIC_NAME ": \"%s\"\n", options->generic_name);
267 	fprintf(stderr, "  "TAG_NEW_EXTENSION ": \"%s\"\n", options->new_extension);
268 	fprintf(stderr, "  "TAG_NEW_MIME_TYPE ": \"%s\"\n", options->new_mime_type);
269 	fprintf(stderr, "  "TAG_SUBJ_BANNED ": \"%s\"\n", options->subj_banned);
270 	fprintf(stderr, "  "TAG_SUBJ_EXEC ": \"%s\"\n", options->subj_exec);
271 	fprintf(stderr, "  "TAG_SUBJ_DELETED ": \"%s\"\n", options->subj_deleted);
272 	fprintf(stderr, "  "TAG_SUBJ_RENAMED ": \"%s\"\n", options->subj_renamed);
273 	fprintf(stderr, "  "TAG_ADD_SUBJECT ": \"%s\"\n", options->add_subject);
274 	fprintf(stderr, "  "TAG_HTMLWARN_POS ": \"%s\"\n", options->htmlwarn_pos);
275 	fprintf(stderr, "  "TAG_WARNING_TEXT ": %d bytes,\n%s\n",
276 		(int)strlen(options->warning_text), options->warning_text);
277 	fprintf(stderr, "  "TAG_WARNING_HTML ": %d bytes,\n%s\n",
278 		(int)strlen(options->warning_html), options->warning_html);
279 	fprintf(stderr, "  "TAG_ADD_HEADER ": %d bytes,\n%s\n",
280 		(int)strlen(options->add_header), options->add_header);
281 	fprintf(stderr, "  "TAG_BANNED_FILES ": {");
282 	tokenize_list(options->banned_files, 1);
283 	fprintf(stderr, "}\n  "TAG_BADLIST ": {");
284 	tokenize_list(options->badlist, 1);
285 	fprintf(stderr, "}\n  " TAG_GOODLIST ": {");
286 	tokenize_list(options->goodlist, 1);
287 	fprintf(stderr, "}\n");
288 }
289 
290 
291 /*
292 	Return description of directive state
293 */
opt2str(int state)294 const char* opt2str(int state)
295 {
296 	if (state == OPTION_DISABLED)
297 		return TAG_OPTDISABLED;
298 	else if (state == OPTION_ENABLED)
299 		return TAG_OPTENABLED;
300 	else
301 		return TXT_INFO_UNDEF;
302 }
303 
304 
305 /*
306 	Return description of filter mode
307 */
mode2str(int mode)308 const char* mode2str(int mode)
309 {
310 	if (mode == MODE_ALL)
311 		return TXT_INFO_MODEALL;
312 	else if (mode == MODE_BAD)
313 		return TXT_INFO_MODEBAD;
314 	else if (mode == MODE_GOOD)
315 		return TXT_INFO_MODEGOOD;
316 	else
317 		return TXT_INFO_UNDEF;
318 }
319 
320 
321 /*
322 	Return description of action type
323 */
act2str(int action)324 const char* act2str(int action)
325 {
326 	switch (action)
327 	{
328 		case ACTION_RENAME:
329 			return TAG_ACTRENAME;
330 
331 		case ACTION_DELETE:
332 			return TAG_ACTDELETE;
333 
334 		case ACTION_KILL:
335 			return TAG_ACTKILL;
336 
337 		case ACTION_SKIP:
338 			return TAG_ACTSKIP;
339 
340 		default:
341 			return TXT_INFO_UNDEF;
342 	}
343 }
344