From: Sascha Sommer <ssommer@suse.de>
To: mlmmj@mlmmj.org
Subject: [PATCH] mimestrip / mimereject
Date: Mon, 26 Feb 2007 12:35:13 +0000 [thread overview]
Message-ID: <200702261335.13954.ssommer@suse.de> (raw)
[-- Attachment #1: Type: text/plain, Size: 869 bytes --]
Hi,
this is a first attempt to implement stripping and rejecting of multipart/mime
messages for mlmmj.
There are 2 patches.
mlmmj-1.2.13-split_do_all_the_vodoo_here.patch
splits do_all_the_vodoo_here()
so that the header reading can be found in an extra function.
This function can then later be reused to read the mime headers.
mlmmj-1.2.13-mimestrip-mimereject.patch
makes it possible to add the files
mimereject and mimeremove to the control/ directory.
Each of them can contain a list with different mime types
like "application/octet-stream" or "text/html"
Messages that contain parts with one of these mime types then either get
rejected or the unwanted part gets removed.
It also parses "multipart/alternative" parts that contain multiple parts
themselves.
I'm not sure if the parser should always be enabled, though.
Please review.
Thanks.
Sascha
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mlmmj-1.2.13-mimestrip-mimereject.patch --]
[-- Type: text/x-diff; charset="us-ascii"; name="mlmmj-1.2.13-mimestrip-mimereject.patch", Size: 10960 bytes --]
diff -Naur mlmmj-1.2.13-split/include/do_all_the_voodo_here.h mlmmj-1.2.13/include/do_all_the_voodo_here.h
--- mlmmj-1.2.13-split/include/do_all_the_voodo_here.h 2007-02-26 11:01:19.000000000 +0100
+++ mlmmj-1.2.13/include/do_all_the_voodo_here.h 2007-02-26 11:08:01.000000000 +0100
@@ -30,6 +30,6 @@
void getinfo(const char *line, struct mailhdr *readhdrs);
int do_all_the_voodo_here(int infd, int outfd, int hdrfd, int footfd,
const char **delhdrs, struct mailhdr *readhdrs,
- struct strlist *allhdrs, const char *subjectprefix);
+ struct strlist *allhdrs, const char *subjectprefix, const char** delmime, struct strlist *allmime);
#endif /* DO_ALL_THE_VOODO_HERE_H */
diff -Naur mlmmj-1.2.13-split/README mlmmj-1.2.13/README
--- mlmmj-1.2.13-split/README 2007-02-26 11:01:19.000000000 +0100
+++ mlmmj-1.2.13/README 2007-02-26 11:54:53.000000000 +0100
@@ -126,6 +126,13 @@
10) Have a look at the file TUNABLES for runtime configurable things.
+11) If you want to strip parts with certain mimetypes from multipart/mime messages
+ add a file called 'mimestrip' containing these mimetypes to the control/ directory.
+
+12) If you want to deny multipart/mime messages with certain mimetypes add a file
+ called 'mimedeny' continaing these mimetypes to the control/directory
+
+
Tunables in include/mlmmj.h:
· There's some time intervals for how mlmmj-maintd operates. I've choosen
non-strict defaults, so depending on your BOFH rate you might want to tweak.
diff -Naur mlmmj-1.2.13-split/src/do_all_the_voodo_here.c mlmmj-1.2.13/src/do_all_the_voodo_here.c
--- mlmmj-1.2.13-split/src/do_all_the_voodo_here.c 2007-02-26 11:01:19.000000000 +0100
+++ mlmmj-1.2.13/src/do_all_the_voodo_here.c 2007-02-26 11:45:09.000000000 +0100
@@ -107,11 +107,156 @@
return 0;
}
+/* check if the supplied headers contain a Content-Type header with boundary */
+static int find_boundary(struct strlist *allhdrs, char** mime_type, char** boundary)
+{
+ int x;
+ *boundary = NULL;
+ *mime_type = NULL;
+ for( x = 0 ; x < allhdrs->count ; x++ ){
+ char* hdr = allhdrs->strs[x];
+ if(hdr && !strncasecmp(hdr,"Content-Type:",13)){
+ char* pos = hdr + 13;
+ size_t len = 0;
+
+ /* find the start of the mimetype */
+ while(*pos && (*pos == ' ' || *pos == '\t'))
+ ++pos;
+
+ if(*pos == '"'){ /* handle quoted mime types */
+ ++pos;
+ while(pos[len] && pos[len] != '"')
+ ++len;
+ }else{
+ while(pos[len] && pos[len] != ' ' && pos[len] != '\t' && pos[len] != ';')
+ ++len;
+ }
+
+ /* extract mime type */
+ if(len){
+ *mime_type = mymalloc(len+1);
+ strncpy(*mime_type,pos,len);
+ (*mime_type)[len] = '\0';
+ }
+
+ pos += len;
+ len = 0;
+ /* find start of the boundary info */
+ while(*pos && strncasecmp(pos,"boundary=",9))
+ ++pos;
+ if(*pos == '\0') /* no boundary */
+ return 0;
+ pos += 9;
+ if(*pos == '"'){ /* quoted boundary */
+ ++pos;
+ while(pos[len] && pos[len] != '"')
+ ++len;
+ }else{ /* unquoted boundary */
+ while(pos[len] && pos[len] != ' ' && pos[len] != '\t' && pos[len] != ';')
+ ++len;
+ }
+
+ /* extract boundary */
+ *boundary = mymalloc(len + 3);
+ strcpy(*boundary,"--");
+ strncat(*boundary,pos,len);
+
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/* dump multipart messages skipping parts specified in delmime*/
+static int dump_multipart(int infd, int outfd, char* boundary, const char **delmime, struct strlist *allmime)
+{
+ char* line;
+ int strip_part = 0;
+ int end_of_part = 0;
+
+ /* parse mail line by line */
+ while((line = mygetline(infd)) != NULL) {
+ int i;
+ struct strlist hdrs;
+ char* new_boundary = NULL;
+ hdrs.count = 0;
+ hdrs.strs = NULL;
+
+ /* found a boundary that has been mentioned in the header */
+ if(!strncmp(line,boundary,strlen(boundary))){
+ strip_part = 0;
+ /* check if the boundary is the beginning of a new part */
+ if(strncmp(line + strlen(boundary),"--",2)){
+ char* mime_type = NULL;
+
+ /* read headers */
+ if( gethdrs(infd, &hdrs) < 0) {
+ log_error(LOG_ARGS, "could not read headers");
+ return -1;
+ }
+ /* get mimetype and boundary from the headers */
+ if(find_boundary(&hdrs,&mime_type,&new_boundary) < 0) {
+ log_error(LOG_ARGS, "Error searching for mime_type and boundary");
+ return -1;
+ }
+
+ /* append mime type to mimelist and check if the part should be stripped */
+ if(mime_type) {
+ append_strtolist(allmime,mime_type);
+ if(delmime && findit(mime_type, delmime))
+ strip_part = 1;
+ myfree(mime_type);
+ }
+ }else{
+ end_of_part=1;
+ }
+ }
+ if(!strip_part) {
+ if(writen(outfd, line, strlen(line)) < 0){
+ log_error(LOG_ARGS, "Error when dumping rest of mail");
+ return -1;
+ }
+ /* write headers if any */
+ if(hdrs.count) {
+ for(i = 0; i < hdrs.count ; i++) {
+ if(writen(outfd, hdrs.strs[i], strlen(hdrs.strs[i])) < 0){
+ log_error(LOG_ARGS, "Error when dumping headers for rest of mail");
+ return -1;
+ }
+ }
+ if(writen(outfd, "\n", 1) < 0) {
+ log_error(LOG_ARGS,"Error writting end of hdrs.");
+ return -1;
+ }
+ }
+ /* dump embedded (multipart) part */
+ if(new_boundary) {
+ if( dump_multipart(infd,outfd, new_boundary, delmime, allmime) < 0){
+ log_error(LOG_ARGS, "Error when dumping nested part");
+ return -1;
+ }
+ myfree(new_boundary);
+ }
+ }
+ /* free headers if any */
+ if(hdrs.strs) {
+ for(i = 0; i < hdrs.count ; i++)
+ myfree(hdrs.strs[i]);
+ myfree(hdrs.strs);
+ }
+ myfree(line);
+
+ if(end_of_part)
+ break;
+ }
+ return 0;
+}
int do_all_the_voodo_here(int infd, int outfd, int hdrfd, int footfd,
const char **delhdrs, struct mailhdr *readhdrs,
- struct strlist *allhdrs, const char *prefix)
+ struct strlist *allhdrs, const char *prefix,
+ const char **delmime, struct strlist *allmime)
{
char *subject, *unqp;
int hdrsadded = 0;
@@ -120,6 +265,10 @@
allhdrs->count = 0;
allhdrs->strs = NULL;
+ if(allmime) {
+ allmime->count = 0;
+ allmime->strs = NULL;
+ }
/* copy headers */
gethdrs(infd,allhdrs);
@@ -203,6 +352,28 @@
return -1;
}
+ if(allmime){
+ char* mime_type = NULL,*boundary=NULL;
+ if(find_boundary(allhdrs,&mime_type,&boundary) < 0) {
+ log_error(LOG_ARGS, "Error searching for mime_type and boundary");
+ return -1;
+ }
+
+ if(mime_type) {
+ append_strtolist(allmime,mime_type);
+ myfree(mime_type);
+ }
+
+ if(boundary) {
+ /* dump multipart message */
+ if(dump_multipart(infd, outfd, boundary, delmime, allmime) < 0) {
+ log_error(LOG_ARGS, "Error when dumping multipart");
+ return -1;
+ }
+ myfree(boundary);
+ }
+ }
+
/* Just print the rest of the mail */
if(dumpfd2fd(infd, outfd) < 0) {
log_error(LOG_ARGS, "Error when dumping rest of mail");
diff -Naur mlmmj-1.2.13-split/src/mlmmj-process.c mlmmj-1.2.13/src/mlmmj-process.c
--- mlmmj-1.2.13-split/src/mlmmj-process.c 2007-02-26 11:01:19.000000000 +0100
+++ mlmmj-1.2.13/src/mlmmj-process.c 2007-02-26 11:52:26.000000000 +0100
@@ -166,6 +166,21 @@
}
}
+static enum action check_mime(struct strlist *denymime, struct strlist * allmime)
+{
+ int i;
+ for(i=0;i<allmime->count;i++){
+ int x;
+ for(x=0; x < denymime->count ; x++){
+ if(!strcasecmp(allmime->strs[i],denymime->strs[x])){
+ log_error(LOG_ARGS, "A mail with mime %s was denied",
+ allmime->strs[i]);
+ return DENY;
+ }
+ }
+ }
+ return ALLOW;
+}
static enum action do_access(struct strlist *rule_strs, struct strlist *hdrs)
{
@@ -366,8 +381,11 @@
struct email_container rpemails = { 0, NULL };
struct email_container dtemails = { 0, NULL };
struct strlist *access_rules = NULL;
+ struct strlist *mime_deny = NULL;
struct strlist *delheaders = NULL;
struct strlist allheaders;
+ struct strlist *delmime = NULL;
+ struct strlist allmime;
struct strlist *alternates = NULL;
struct mailhdr readhdrs[] = {
{ "From:", 0, NULL },
@@ -483,12 +501,21 @@
delheaders->strs[delheaders->count++] = mystrdup("From ");
delheaders->strs[delheaders->count++] = mystrdup("Return-Path:");
delheaders->strs[delheaders->count] = NULL;
-
+
+ /* get a list of mime parts that should be stripped */
+ delmime = ctrlvalues(listdir, "mimestrip");
+ if(delmime == NULL) {
+ delmime = mymalloc(sizeof(struct strlist));
+ delmime->count = 0;
+ delmime->strs = NULL;
+ }
+
+
subjectprefix = ctrlvalue(listdir, "prefix");
if(do_all_the_voodo_here(rawmailfd, donemailfd, hdrfd, footfd,
(const char**)delheaders->strs, readhdrs,
- &allheaders, subjectprefix) < 0) {
+ &allheaders, subjectprefix,(const char**)delmime->strs, &allmime) < 0) {
log_error(LOG_ARGS, "Error in do_all_the_voodo_here");
exit(EXIT_FAILURE);
}
@@ -599,7 +626,7 @@
}
if(do_all_the_voodo_here(rawmailfd, donemailfd, -1,
-1, (const char**)delheaders->strs,
- NULL, &allheaders, NULL) < 0) {
+ NULL, &allheaders, NULL, (const char**)delmime->strs, &allmime) < 0) {
log_error(LOG_ARGS, "do_all_the_voodo_here");
exit(EXIT_FAILURE);
}
@@ -654,6 +681,12 @@
myfree(delheaders);
+ for(i = 0; i < delmime->count; i++)
+ myfree(delmime->strs[i]);
+ myfree(delmime->strs);
+ myfree(delmime);
+
+
if(strcmp(efrom, "") == 0) { /* don't send mails with <> in From
to the list */
discardname = concatstr(3, listdir,
@@ -808,11 +841,34 @@
noaccessdenymails = statctrl(listdir, "noaccessdenymails");
access_rules = ctrlvalues(listdir, "access");
- if (access_rules) {
- enum action accret;
+ mime_deny = ctrlvalues(listdir,"mimedeny");
+ if (access_rules || mime_deny) {
+ enum action accret = ALLOW;
/* Don't send a mail about denial to the list, but silently
* discard and exit. Also do this in case it's turned off */
- accret = do_access(access_rules, &allheaders);
+
+ /* check rules */
+ if(access_rules)
+ accret = do_access(access_rules, &allheaders);
+
+ /* check allowed mime types */
+ if(accret == ALLOW && mime_deny)
+ accret = check_mime(mime_deny, &allmime);
+
+ /* free rules */
+ if(access_rules) {
+ for(i = 0; i < access_rules->count; i++)
+ myfree(access_rules->strs[i]);
+ myfree(access_rules->strs);
+ myfree(access_rules);
+ }
+ if(mime_deny) {
+ for(i = 0; i < mime_deny->count; i++)
+ myfree(mime_deny->strs[i]);
+ myfree(mime_deny->strs);
+ myfree(mime_deny);
+ }
+
if (accret == DENY) {
if ((strcasecmp(listaddr, fromemails.emaillist[0]) ==
0) || noaccessdenymails) {
[-- Attachment #3: mlmmj-1.2.13-split_do_all_the_vodoo_here.patch --]
[-- Type: text/x-diff, Size: 4134 bytes --]
diff -Naur mlmmj-1.2.13.org/src/do_all_the_voodo_here.c mlmmj-1.2.13/src/do_all_the_voodo_here.c
--- mlmmj-1.2.13.org/src/do_all_the_voodo_here.c 2007-02-26 09:55:32.000000000 +0100
+++ mlmmj-1.2.13/src/do_all_the_voodo_here.c 2007-02-26 12:26:57.000000000 +0100
@@ -75,28 +75,64 @@
}
}
+/* append a string to a stringlist */
+static void append_strtolist(struct strlist *list, char* str)
+{
+ list->count++;
+ list->strs = myrealloc(list->strs,
+ sizeof(char *) * (list->count + 1));
+ list->strs[list->count-1] = mystrdup(str);
+ list->strs[list->count] = NULL; /* XXX why, why, why? */
+}
+
+
+/* get a copy of all headers */
+static int gethdrs(int infd, struct strlist *allhdrs)
+{
+ char* hdrline;
+ while((hdrline = gethdrline(infd))) {
+
+ /* Done with headers?*/
+ if((strlen(hdrline) == 1) && (hdrline[0] == '\n')) {
+ myfree(hdrline);
+ break;
+ }
+
+ /* Snatch a copy of the header */
+ append_strtolist(allhdrs,hdrline);
+
+ myfree(hdrline);
+
+ }
+ return 0;
+}
+
+
+
int do_all_the_voodo_here(int infd, int outfd, int hdrfd, int footfd,
const char **delhdrs, struct mailhdr *readhdrs,
struct strlist *allhdrs, const char *prefix)
{
- char *hdrline, *subject, *unqp;
+ char *subject, *unqp;
int hdrsadded = 0;
int subject_present = 0;
+ int i;
allhdrs->count = 0;
allhdrs->strs = NULL;
- while((hdrline = gethdrline(infd))) {
- /* Done with headers? Then add extra if wanted*/
- if((strncasecmp(hdrline, "mime", 4) == 0) ||
- ((strlen(hdrline) == 1) && (hdrline[0] == '\n'))){
+ /* copy headers */
+ gethdrs(infd,allhdrs);
+ /* write headers */
+ for(i = 0 ; i < allhdrs->count ; i++) {
+ char* hdrline = allhdrs->strs[i];
+ if(strncasecmp(hdrline, "mime", 4) == 0) {
/* add extra headers */
if(!hdrsadded && hdrfd >= 0) {
if(dumpfd2fd(hdrfd, outfd) < 0) {
log_error(LOG_ARGS, "Could not "
"add extra headers");
- myfree(hdrline);
return -1;
} else
hdrsadded = 1;
@@ -104,41 +140,11 @@
fsync(outfd);
- /* end of headers, write single LF */
- if(hdrline[0] == '\n') {
- /* but first add Subject if none is present
- * and a prefix is defined */
- if (prefix && !subject_present)
- {
- subject = concatstr(3, "Subject: ",
- prefix, "\n");
- writen(outfd, subject, strlen(subject));
- myfree(subject);
- subject_present = 1;
- }
-
- if(writen(outfd, hdrline, strlen(hdrline))
- < 0) {
- myfree(hdrline);
- log_error(LOG_ARGS,
- "Error writing hdrs.");
- return -1;
- }
- myfree(hdrline);
- break;
- }
}
/* Do we want info from hdrs? Get it before it's gone */
if(readhdrs)
getinfo(hdrline, readhdrs);
- /* Snatch a copy of the header */
- allhdrs->count++;
- allhdrs->strs = myrealloc(allhdrs->strs,
- sizeof(char *) * (allhdrs->count + 1));
- allhdrs->strs[allhdrs->count-1] = mystrdup(hdrline);
- allhdrs->strs[allhdrs->count] = NULL; /* XXX why, why, why? */
-
/* Add Subject: prefix if wanted */
if(prefix) {
if(strncasecmp(hdrline, "Subject:", 8) == 0) {
@@ -152,7 +158,6 @@
writen(outfd, subject,
strlen(subject));
myfree(subject);
- myfree(hdrline);
myfree(unqp);
continue;
}
@@ -166,9 +171,36 @@
writen(outfd, hdrline, strlen(hdrline));
} else
writen(outfd, hdrline, strlen(hdrline));
+ }
- myfree(hdrline);
+ /* add extra headers */
+ if(!hdrsadded && hdrfd >= 0) {
+ if(dumpfd2fd(hdrfd, outfd) < 0) {
+ log_error(LOG_ARGS, "Could not "
+ "add extra headers");
+ return -1;
+ } else
+ hdrsadded = 1;
+ }
+
+ fsync(outfd);
+
+ /* end of headers, write single LF */
+ /* but first add Subject if none is present
+ * and a prefix is defined */
+ if (prefix && !subject_present)
+ {
+ subject = concatstr(3, "Subject: ",
+ prefix, "\n");
+ writen(outfd, subject, strlen(subject));
+ myfree(subject);
+ subject_present = 1;
+ }
+
+ if(writen(outfd, "\n", 1) < 0) {
+ log_error(LOG_ARGS,"Error writing hdrs.");
+ return -1;
}
/* Just print the rest of the mail */
next reply other threads:[~2007-02-26 12:35 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-02-26 12:35 Sascha Sommer [this message]
2007-02-26 12:53 ` [PATCH] mimestrip / mimereject Jakob Hirsch
2007-03-03 17:57 ` Morten K. Poulsen
2007-03-05 9:49 ` Sascha Sommer
2007-03-05 14:20 ` Sascha Sommer
2007-03-06 22:23 ` Morten K. Poulsen
2007-03-16 15:22 ` Sascha Sommer
2007-03-18 16:26 ` Morten K. Poulsen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200702261335.13954.ssommer@suse.de \
--to=ssommer@suse.de \
--cc=mlmmj@mlmmj.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.