All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mimestrip / mimereject
@ 2007-02-26 12:35 Sascha Sommer
  2007-02-26 12:53 ` Jakob Hirsch
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Sascha Sommer @ 2007-02-26 12:35 UTC (permalink / raw)
  To: mlmmj

[-- 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 */

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2007-03-18 16:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-02-26 12:35 [PATCH] mimestrip / mimereject Sascha Sommer
2007-02-26 12:53 ` 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

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.