~ubuntu-branches/ubuntu/dapper/renattach/dapper

« back to all changes in this revision

Viewing changes to renattach.c

  • Committer: Bazaar Package Importer
  • Author(s): Mats Rynge
  • Date: 2004-12-29 20:52:50 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20041229205250-b3z2r3df8kteoel8
Tags: 1.2.2-1
* New upstream release (closes: #284698)
* Changed build-depends to include exim4 as an alternative to
  the virtual mail-transport-agent package

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 
3
 
RenAttach 1.1.1 - GNU email virus/trojan attachment filter
4
 
Copyright(C) 2000-2001 Jem E. Berkes
5
 
Release date: October 18, 2001
6
 
 
7
 
Author's e-mail: jberkes at pc-tools dot net
8
 
Distribution site:
9
 
http://www.pc-tools.net/
10
 
 
11
 
Write to -stdout and modified file rename technique contributed by:
12
 
Colin McKinnon <colinmckinnon at technologist dot com>
13
 
 
14
 
Before compiling and executing this software you must read and agree to
15
 
the terms in LICENSE.
16
 
 
17
 
    This program is free software; you can redistribute it and/or modify
18
 
    it under the terms of the GNU General Public License as published by
19
 
    the Free Software Foundation; either version 2 of the License, or
20
 
    (at your option) any later version.
21
 
 
22
 
    This program is distributed in the hope that it will be useful,
23
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 
    GNU General Public License for more details.
26
 
 
27
 
    You should have received a copy of the GNU General Public License
28
 
    along with this program (see LICENSE); if not, write to the Free
29
 
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30
 
    02111-1307  USA
31
 
 
32
 
*/
33
 
 
34
 
 
35
 
#include "defs.h"
36
 
#include <ctype.h>
37
 
#include <malloc.h>
38
 
#include <stdio.h>
39
 
#include <stdlib.h>
40
 
#include <string.h>
41
 
#include <syslog.h>
42
 
#include <unistd.h>
43
 
 
44
 
const char VERSION[]="RenAttach 1.1.1 (www.pc-tools.net)";
45
 
int cursize = DEF_BUFSIZE; /* sets buffer sizes; changes on the fly */
46
 
char *scratch, *good_list, *bad_list, *gl_scratch, *bl_scratch;
47
 
FILE *mailer;
48
 
int mode, use_stdout=0;
49
 
/* these buffers have fixed size */
50
 
char messageid[DEF_BUFSIZE];
51
 
char generic[DEF_BUFSIZE];
52
 
char mime_buf[MAX_MIMEHEAD];
53
 
 
54
 
void free_lists()
55
 
{
56
 
free(good_list);
57
 
free(bad_list);
58
 
free(gl_scratch);
59
 
free(bl_scratch);
60
 
}
61
 
 
62
 
 
63
 
void log_it(char* filename)
64
 
/* Log a renamed filename and message ID to syslog */
65
 
{
66
 
#ifdef USE_SYSLOG
67
 
openlog("renattach", LOG_PID, LOG_MAIL);
68
 
syslog(LOG_WARNING, "renamed \"%s\" in %s", filename, messageid);
69
 
closelog();
70
 
#endif
71
 
}
72
 
 
73
 
char *startof_fn(char *line)
74
 
/*
75
 
Looks inside line, and returns a pointer to the start of a found
76
 
filename, or NULL if no filename is located.
77
 
*/
78
 
{
79
 
char *filename1, *filename2, *line_copy, *mime_fn, *loc;
80
 
int line_length, i;
81
 
 
82
 
filename1 = (char*)malloc(cursize);
83
 
filename2 = (char*)malloc(cursize);
84
 
line_copy = (char*)malloc(cursize);
85
 
if (filename1 == NULL)
86
 
        return NULL;
87
 
if (filename2 == NULL)
88
 
        {
89
 
        free(filename1);
90
 
        return NULL;
91
 
        }
92
 
if (line_copy == NULL)
93
 
        {
94
 
        free(filename1);
95
 
        free(filename2);
96
 
        return NULL;
97
 
        }
98
 
line_length = strlen(line)+1;
99
 
for (i=0; i<line_length; i++)
100
 
        line_copy[i] = tolower(line[i]);
101
 
if ((mime_fn=strstr(line_copy, "name")) == NULL)
102
 
        {
103
 
        if ( (mime_fn=strstr(line_copy, "content-description:")) == NULL)
104
 
                {
105
 
                free(filename1);
106
 
                free(filename2);
107
 
                free(line_copy);
108
 
                return NULL;
109
 
                }
110
 
        else
111
 
                {
112
 
                mime_fn = mime_fn-line_copy+line+20;
113
 
                free(filename2);
114
 
                free(line_copy);
115
 
                if (sscanf(mime_fn, "%s", filename1) == 1)
116
 
                        {
117
 
                        loc = strstr(mime_fn, filename1);
118
 
                        free(filename1);
119
 
                        return loc;
120
 
                        }
121
 
                else
122
 
                        {
123
 
                        free(filename1);
124
 
                        return NULL;
125
 
                        }
126
 
                }
127
 
        }
128
 
mime_fn += 4;
129
 
mime_fn = mime_fn-line_copy+line;
130
 
free(line_copy);
131
 
switch (sscanf(mime_fn, "%s%s", filename1, filename2))
132
 
        {
133
 
        case 1:
134
 
                {
135
 
                if (strcmp(filename1, "=") == 0)
136
 
                        break;
137
 
                else if (*filename1 == '=')
138
 
                        {
139
 
                        char *loc = strstr(mime_fn, filename1+1);
140
 
                        free(filename1);
141
 
                        free(filename2);
142
 
                        return loc;
143
 
                        }
144
 
                break;
145
 
                }
146
 
        case 2:
147
 
                {
148
 
                if (strcmp(filename1, "=") == 0)
149
 
                        {
150
 
                        char *loc = strstr(mime_fn, filename2);
151
 
                        free(filename1);
152
 
                        free(filename2);
153
 
                        return loc;
154
 
                        }
155
 
                else if (*filename1 == '=')
156
 
                        {
157
 
                        char *loc = strstr(mime_fn, filename1+1);
158
 
                        free(filename1);
159
 
                        free(filename2);
160
 
                        return loc;
161
 
                        }
162
 
                break;
163
 
                }
164
 
        }
165
 
free(filename1);
166
 
free(filename2);
167
 
return NULL;
168
 
}
169
 
 
170
 
 
171
 
int is_kosher(char *address)
172
 
/*
173
 
Catches bad "forward to" addresses. Tells whether address is good.
174
 
NB will reject prog mailers "|" and "`...`" [CM]
175
 
Return: 0 means address is bad, 1 means good
176
 
*/
177
 
{
178
 
int i;
179
 
char ch;
180
 
 
181
 
for (i=0; i < (int)strlen(address); i++)
182
 
        {
183
 
        ch = address[i];
184
 
        if (ch == '.' || ch == '_' || ch == '-' || ch == '@')
185
 
                continue;
186
 
        else if (ch >= 'a' && ch <= 'z')
187
 
                continue;
188
 
        else if (ch >= 'A' && ch <= 'Z')
189
 
                continue;
190
 
        else if (ch >= '0' && ch <= '9')
191
 
                continue;
192
 
        return 0;
193
 
        }
194
 
return 1;
195
 
}
196
 
 
197
 
 
198
 
int syntax(char *exec)
199
 
/*  Generic syntax error */
200
 
{
201
 
fprintf(stderr, "\n%s\nCopyright(C) 2000-2001 Jem E. Berkes\n\n", VERSION);
202
 
fprintf(stderr, "\tRenAttach comes with ABSOLUTELY NO WARRANTY. This is\n"
203
 
                "\tfree software, and you are welcome to redistribute it\n"
204
 
                "\tunder certain conditions. See LICENSE for details.\n\n");
205
 
fprintf(stderr, "Usage: %s [-v] -b|-g|-f [-s|-t address]\n\n", exec);
206
 
fprintf(stderr, "-bad or -partial (old) will rename only dangerous extensions\n");
207
 
fprintf(stderr, "-good will rename everything except known safe extensions\n");
208
 
fprintf(stderr, "-full will rename all attachments\n");
209
 
fprintf(stderr, "-to will forward the filtered mail to some address\n");
210
 
fprintf(stderr, "-stdout writes the filtered output to stdout\n");
211
 
fprintf(stderr, "-verbose will dump internal settings (including lists)\n\n");
212
 
fprintf(stderr, "Examples: (insert into .forward, with quotes)\n");
213
 
fprintf(stderr, "\"|/path/renattach -g\"\n");
214
 
fprintf(stderr, "\"|/path/renattach -b -t address@domain.tld\"\n\n");
215
 
return -1;
216
 
}
217
 
 
218
 
 
219
 
int is_match(char *filename, int good)
220
 
/*
221
 
Compares filename's extension to either the good (1) or bad (0) list
222
 
Return: 0 is not match, 1 is match
223
 
*/
224
 
{
225
 
char *extcopy, *ext, *lastdot, *token;
226
 
 
227
 
strcpy(gl_scratch, good_list);
228
 
strcpy(bl_scratch, bad_list);
229
 
 
230
 
if (good==1)
231
 
        extcopy = gl_scratch;
232
 
else
233
 
        extcopy = bl_scratch;
234
 
ext = NULL;
235
 
lastdot = strrchr(filename, '.');
236
 
if (lastdot == NULL)
237
 
        return 0;
238
 
ext = lastdot+1;
239
 
token = strtok(extcopy, CONF_TOKS);
240
 
while (token != NULL)
241
 
        {
242
 
        if (strcasecmp(token, ext) == 0)
243
 
                return 1;
244
 
        token = strtok(NULL, CONF_TOKS);
245
 
        }
246
 
return 0;
247
 
}
248
 
 
249
 
 
250
 
int make_safe(char *orig_line, char *name, int in_mime)
251
 
/*
252
 
Processes lines which contain filenames. Returns 1 if it renames
253
 
a filename. If in_mime, then output is appended to mime_buf instead
254
 
of output immediately. Note: orig_line and name must point into the
255
 
same buffer.
256
 
*/
257
 
{
258
 
char *fnbuf, *filename, *txtend, *lastdot;
259
 
int i, n;
260
 
int renamed = 0;
261
 
 
262
 
/* prepare this generic filename in case it is needed */
263
 
strncpy(generic, GENERIC_FN, DEF_BUFSIZE);
264
 
generic[DEF_BUFSIZE-1] = 0;
265
 
 
266
 
if (*name=='\n' || *name==0)
267
 
        return 0;
268
 
fnbuf = (char*)malloc(cursize);
269
 
if (fnbuf == NULL)
270
 
        return 0;
271
 
filename = fnbuf;
272
 
if ((sscanf(name, "%[^\"]", filename)==1) ||
273
 
        (sscanf(name, "\"%[^\"]", filename)==1) ||
274
 
        (sscanf(name, "%[^\n]", filename)==1))
275
 
        {
276
 
        if (filename[strlen(filename)-1] == '\n')
277
 
                filename[strlen(filename)-1] = 0;
278
 
        }
279
 
else
280
 
        {
281
 
        free(fnbuf);
282
 
        return 0;
283
 
        }
284
 
n = (strstr(name, filename)-orig_line);
285
 
strncpy(scratch, orig_line, n);
286
 
scratch[n] = 0;
287
 
txtend = strstr(name, filename) + strlen(filename);
288
 
for (i=strlen(filename)-1; (filename[i]=='.' || filename[i]==' ')
289
 
                                && i>0 ; i--)
290
 
        filename[i] = 0;
291
 
#ifdef CATCH_CODED
292
 
if (strstr(filename, "=?")!=NULL)
293
 
        {
294
 
        renamed = 1;
295
 
        log_it(filename);
296
 
        filename = generic;
297
 
        }
298
 
#endif
299
 
switch (mode)
300
 
        {
301
 
        case MODE_BADLIST:
302
 
                if (is_match(filename, 0)==1)
303
 
                        {
304
 
                        renamed = 1;
305
 
                        log_it(filename);
306
 
                        *strrchr(filename, '.') = '_';
307
 
                        if (strlen(filename)+strlen(NEW_EXTN)+1 < cursize)
308
 
                                strcat(filename, NEW_EXTN);
309
 
                        else
310
 
                                filename = generic;
311
 
                        }
312
 
                break;
313
 
 
314
 
        case MODE_GOODLIST:
315
 
                if (is_match(filename, 1)==1)
316
 
                        break;
317
 
                /* deliberate run into following case */
318
 
 
319
 
        case MODE_FULL:
320
 
                /* simply appending a string doesn't fix Eudora light where the
321
 
                extension _may_ be truncated back to its original value */
322
 
                renamed = 1;
323
 
                log_it(filename);
324
 
                lastdot = strrchr(filename, '.');
325
 
                if (lastdot != NULL)
326
 
                        *lastdot = '_';
327
 
                if (strlen(filename)+strlen(NEW_EXTN)+1 < cursize)
328
 
                        strcat(filename, NEW_EXTN);
329
 
                else
330
 
                        filename = generic;
331
 
                break;
332
 
        }
333
 
strcat(scratch, filename);
334
 
strcat(scratch, txtend);
335
 
if (in_mime == 1)
336
 
        {
337
 
        if (strlen(mime_buf)+strlen(scratch)+1 < MAX_MIMEHEAD)
338
 
                strcat(mime_buf, scratch);
339
 
        }
340
 
else
341
 
        fputs(scratch, mailer);
342
 
free(fnbuf);
343
 
return renamed;
344
 
}
345
 
 
346
 
 
347
 
int main (int argc, char *argv[])
348
 
{
349
 
char *line, *fname, *bigger_line, *bigger_scratch, *token, *after_mt;
350
 
int inheader=1, mime_type=0, change_mime=0, i;
351
 
int badlist=0, goodlist=0, full=0, address=0, verbose=0;
352
 
 
353
 
*messageid = 0;
354
 
if (argc == 1)
355
 
        return syntax(argv[0]);
356
 
        
357
 
for (i = 1; i < argc; i++)
358
 
        {
359
 
        if (*argv[i] != '-')
360
 
                return syntax(argv[0]);
361
 
        switch (argv[i][1])
362
 
                {
363
 
                case 'v': case 'V':
364
 
                        verbose = 1;
365
 
                        break;
366
 
                        
367
 
                case 'f': case 'F':
368
 
                        full = 1;
369
 
                        break;
370
 
 
371
 
                case 'g': case 'G':
372
 
                        goodlist = 1;
373
 
                        break;
374
 
 
375
 
                case 'b': case 'B':
376
 
                case 'p': case 'P':
377
 
                        badlist = 1;
378
 
                        break;
379
 
 
380
 
                case 's': case 'S':
381
 
                        use_stdout = 1;
382
 
                        break;
383
 
 
384
 
                case 't': case 'T':
385
 
                        if (argc-1 > i)
386
 
                                {
387
 
                                i++;
388
 
                                address = i;
389
 
                                }
390
 
                        else
391
 
                                return syntax(argv[0]);
392
 
                        break;
393
 
 
394
 
                default:
395
 
                        return syntax(argv[0]);
396
 
                }
397
 
        }
398
 
if (use_stdout==0)
399
 
        {
400
 
        if (access(LOCAL_MAILER, X_OK) == -1)
401
 
                {
402
 
                fprintf(stderr, "Can not find/execute local mailer: %s\n", LOCAL_MAILER);
403
 
                return -1;
404
 
                }
405
 
        if (access(MTA_COMMAND, X_OK) == -1)
406
 
                {
407
 
                fprintf(stderr, "Can not find/execute MTA: %s\n", MTA_COMMAND);
408
 
                return -1;
409
 
                }
410
 
        }
411
 
 
412
 
if (read_lists(&good_list, &bad_list, &gl_scratch, &bl_scratch) != 0)
413
 
        return -1;
414
 
        
415
 
if (verbose == 1)
416
 
        {
417
 
        printf("Version string: %s\n", VERSION);
418
 
        printf("Configuration file is %s\n", CONF_FILE);
419
 
        printf("Mail transport agent is %s\n", MTA_COMMAND);
420
 
        printf("Local mailer is %s\n", LOCAL_MAILER);
421
 
        printf("\nReading lists from configuration file...\n");
422
 
        printf("-- begin goodlist --\n");
423
 
        strcpy(gl_scratch, good_list);
424
 
        tokenize_list(gl_scratch, 1);
425
 
        printf("\n-- begin badlist --\n");
426
 
        strcpy(bl_scratch, bad_list);
427
 
        tokenize_list(bl_scratch, 1);
428
 
        printf("\n-- end --\n\n");
429
 
        return 0;
430
 
        }
431
 
 
432
 
if ( (badlist==0 && goodlist==0 && full==0) ||
433
 
        (badlist==1 && goodlist==1) || (badlist==1 && full==1) || (goodlist==1 && full==1) )
434
 
        {
435
 
        fprintf(stderr, "Specify -badlist, -goodlist or -full filtering (only one)\n");
436
 
        free_lists();
437
 
        return -1;
438
 
        }
439
 
if ((address>0) && use_stdout==1)
440
 
        {
441
 
        fprintf(stderr, "Specify -stdout or -to address, but not both\n");
442
 
        free_lists();
443
 
        return -1;
444
 
        }
445
 
if (badlist==1)
446
 
        mode = MODE_BADLIST;
447
 
else if (goodlist==1)
448
 
        mode = MODE_GOODLIST;
449
 
else
450
 
        mode = MODE_FULL;
451
 
scratch = (char*)malloc(cursize);
452
 
if (scratch == NULL)
453
 
        {
454
 
        free_lists();
455
 
        return mem_error();
456
 
        }
457
 
if (address > 0)
458
 
        {
459
 
        if (is_kosher(argv[address])==0)
460
 
                {
461
 
                fprintf(stderr, "\"%s\" is not a valid e-mail address\n", argv[address]);
462
 
                free_lists();
463
 
                free(scratch);
464
 
                return -1;
465
 
                }
466
 
        else if (cursize < (int)(3+sizeof(MTA_COMMAND)+sizeof(MTA_TAIL)+strlen(argv[address])))
467
 
                {
468
 
                fprintf(stderr, "Address is too long\n");
469
 
                free_lists();
470
 
                free(scratch);
471
 
                return -1;
472
 
                }
473
 
        else sprintf(scratch, "%s %s %s", MTA_COMMAND, MTA_TAIL, argv[address]);
474
 
        }
475
 
else
476
 
        {
477
 
        strncpy(scratch, LOCAL_MAILER, cursize);
478
 
        scratch[cursize-1] = 0;
479
 
        }
480
 
line = (char*)malloc(cursize);
481
 
if (line == NULL)
482
 
        {
483
 
        free_lists();
484
 
        free(scratch);
485
 
        return mem_error();
486
 
        }
487
 
if (use_stdout==1)
488
 
        mailer=stdout;
489
 
else
490
 
        mailer = popen(scratch, "w");   /* init MDA */
491
 
if (mailer == NULL)
492
 
        {
493
 
        free_lists();
494
 
        free(scratch);
495
 
        free(line);
496
 
        return -1;
497
 
        }
498
 
while (fgets(line, cursize, stdin) != NULL)
499
 
        {
500
 
        while ( ((int)strlen(line)==cursize-1) && (line[strlen(line)-1]!='\n') )
501
 
                {
502
 
                if (cursize >= BUF_LIMIT)
503
 
                        bigger_line = NULL;
504
 
                else
505
 
                        {
506
 
                        cursize *= 2;
507
 
                        bigger_line = (char*)malloc(cursize);
508
 
                        }
509
 
                if (bigger_line == NULL)
510
 
                        {
511
 
                        free_lists();
512
 
                        free(scratch);
513
 
                        free(line);
514
 
                        return mem_error();
515
 
                        }
516
 
                strcpy(bigger_line, line);
517
 
                free(line);
518
 
                line = bigger_line;
519
 
                free(scratch);
520
 
                bigger_scratch = (char*)malloc(cursize);
521
 
                if (bigger_scratch == NULL)
522
 
                        {
523
 
                        free_lists();
524
 
                        free(line);
525
 
                        return mem_error();
526
 
                        }
527
 
                scratch = bigger_scratch;
528
 
                fgets(line+(cursize/2)-1, (cursize/2)+1, stdin);
529
 
                }
530
 
        if (inheader==1)
531
 
                {
532
 
                if (strncasecmp(line, "Message-ID:", 11)==0)
533
 
                        {
534
 
                        strncpy(messageid, line, DEF_BUFSIZE);
535
 
                        messageid[DEF_BUFSIZE-1] = 0;
536
 
                        }
537
 
                else if (*line=='\n')
538
 
                        {
539
 
                        /*
540
 
                        Should have reached end of headers - add additional before body [CM]
541
 
                        */
542
 
                        inheader = 0;
543
 
                        fprintf(mailer, "X-Filtered-With: %s - ", VERSION);
544
 
                                if (mode == MODE_BADLIST)
545
 
                                        fprintf(mailer, "badlist filter\n\n");
546
 
                                else if (mode == MODE_GOODLIST)
547
 
                                        fprintf(mailer, "goodlist filter\n\n");
548
 
                                else
549
 
                                        fprintf(mailer, "full filter\n\n");
550
 
                        continue;
551
 
                        }
552
 
                }
553
 
        else
554
 
                {
555
 
                if (mime_type==0 && (strncasecmp(line, "Content-type:", 13)==0))
556
 
                        {
557
 
                        mime_type = 1;
558
 
                        change_mime = 0;
559
 
                        *mime_buf = 0;
560
 
                        }
561
 
                else
562
 
                        {
563
 
                        if      ( (strncmp(line, "begin", 5)==0) &&
564
 
                                        (sscanf(line, "begin %*d %[^\n]", scratch)==1) )
565
 
                                {
566
 
                                if (make_safe(line, strstr(line+5, scratch), 0)==1)
567
 
                                        continue;
568
 
                                }
569
 
                        }
570
 
 
571
 
                if (mime_type==1)
572
 
                        {
573
 
                        if (*line=='\n')
574
 
                                {
575
 
                                mime_type = 0;
576
 
                                if (change_mime == 1)
577
 
                                        {
578
 
                                        /* Change content-type */
579
 
                                        token = strtok(mime_buf, "\r\n");
580
 
                                        while (token != NULL)
581
 
                                                {
582
 
                                                if (strncasecmp(token, "Content-type:", 13)==0)
583
 
                                                        {
584
 
                                                        after_mt = strchr(token, ';');
585
 
                                                        if (after_mt == NULL)
586
 
                                                                after_mt = "";
587
 
                                                        fprintf(mailer, "Content-Type: %s%s\n", NEW_MIMETYPE, after_mt);
588
 
                                                        }
589
 
                                                else
590
 
                                                        fprintf(mailer, "%s\n", token);
591
 
                                                token = strtok(NULL, "\r\n");
592
 
                                                }
593
 
                                        }
594
 
                                else
595
 
                                        fputs(mime_buf, mailer);
596
 
                                fprintf(mailer, "\n");
597
 
                                }
598
 
                        else
599
 
                                {
600
 
                                if ((fname=startof_fn(line)) != NULL)
601
 
                                        {
602
 
                                        if (make_safe(line, fname, 1)==1)
603
 
                                                change_mime = 1;
604
 
                                        }
605
 
                                else
606
 
                                        {
607
 
                                        if (strlen(mime_buf)+strlen(line)+1 < MAX_MIMEHEAD)
608
 
                                                strcat(mime_buf, line);
609
 
                                        }
610
 
                                }
611
 
                        continue;       /* no output, yet */
612
 
                        }
613
 
                }
614
 
 
615
 
        fputs(line, mailer);
616
 
        }
617
 
pclose(mailer);
618
 
free_lists();
619
 
free(scratch);
620
 
free(line);
621
 
return 0;
622
 
}