changeset 117:5ec5e6637049

added server-side SMTP SIZE support (patch by Paolo) ``SIZE 0'' (= unlimited) is currently not supported client-side support was already implemented
author meillo@marmaro.de
date Thu, 01 Jul 2010 13:08:53 +0200
parents ddc8041fdee1
children 7f1f364c2a29
files man/masqmail.conf.5 src/accept.c src/conf.c src/masqmail.c src/masqmail.h src/smtp_in.c
diffstat 6 files changed, 77 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/man/masqmail.conf.5	Wed Jun 30 15:45:34 2010 +0200
+++ b/man/masqmail.conf.5	Thu Jul 01 13:08:53 2010 +0200
@@ -1,4 +1,4 @@
-.TH masqmail.conf 5 2010-06-30 masqmail-0.2.25 "File Formats"
+.TH masqmail.conf 5 2010-07-01 masqmail-0.2.25 "File Formats"
 
 .SH NAME
 masqmail.conf \- masqmail configuration file
@@ -482,6 +482,18 @@
 For example you can feed your mails into a program like hypermail
 for archiving purpose by placing an appropriate pipe command in masqmail.alias
 
+.TP
+\fBmax_msg_size\fR = \fIbytes\fR
+
+This option sets the maximum size in bytes masqmail will accept for delivery.
+This value is advertised to the SMTP client by the `SIZE' message during SMTP
+session setup.
+Clients pretending to send, or actually send,
+more than \fIbytes\fR will get a 552 error message.
+
+Default is 104857600 (= 100MB).
+(This should be sufficient for most cases.)
+
 
 .SH AUTHOR
 
--- a/src/accept.c	Wed Jun 30 15:45:34 2010 +0200
+++ b/src/accept.c	Thu Jul 01 13:08:53 2010 +0200
@@ -155,6 +155,13 @@
 				line_cnt++;
 			}
 		}
+		if (data_size > conf.max_msg_size) {
+			DEBUG(4) debugf("accept_message_stream(): "
+					"received %d bytes (conf.max_msg_size=%d)\n",
+			                data_size, conf.max_msg_size);
+			return AERR_SIZE;
+		}
+
 	}
 
 	if (msg->data_list != NULL)
--- a/src/conf.c	Wed Jun 30 15:45:34 2010 +0200
+++ b/src/conf.c	Thu Jul 01 13:08:53 2010 +0200
@@ -431,6 +431,7 @@
 	conf.do_relay = TRUE;
 	conf.alias_local_cmp = strcmp;
 	conf.max_defer_time = 86400 * 4;  /* 4 days */
+	conf.max_msg_size = 100*1024*1024; /* in bytes (100MB are probably enough) */
 
 	if ((in = fopen(filename, "r")) == NULL) {
 		fprintf(stderr, "could not open config file %s: %s\n", filename, strerror(errno));
@@ -581,7 +582,11 @@
 				conf.max_defer_time = ival;
 		} else if (strcmp(lval, "log_user") == 0)
 			conf.log_user = g_strdup(rval);
-
+		else if(strcmp(lval, "max_msg_size") == 0) {
+			conf.max_msg_size = atol(rval);
+			DEBUG(6) fprintf(stderr,"rval=%s, conf.max_msg_size=%ld\n",
+			                 rval, conf.max_msg_size);
+		}
 		else
 			fprintf(stderr, "var '%s' not (yet) known, ignored\n", lval);
 	}
--- a/src/masqmail.c	Wed Jun 30 15:45:34 2010 +0200
+++ b/src/masqmail.c	Thu Jul 01 13:08:53 2010 +0200
@@ -317,6 +317,9 @@
 		case AERR_NORCPT:
 			fprintf(stderr, "no recipients.\n");
 			exit(EXIT_FAILURE);
+		case AERR_SIZE:
+			fprintf(stderr, "max message size exceeded.\n");
+			exit(EXIT_FAILURE);
 		default:
 			/* should never happen: */
 			fprintf(stderr, "Unknown error (%d)\r\n", err);
--- a/src/masqmail.h	Wed Jun 30 15:45:34 2010 +0200
+++ b/src/masqmail.h	Thu Jul 01 13:08:53 2010 +0200
@@ -174,6 +174,10 @@
 
 	guint remote_port;
 
+	/* ANSI C defines unsigned long to be at least 32bit
+	   i.e. ca. 4GB max; that should be enough. */
+	gulong max_msg_size;
+
 	gboolean do_save_envelope_to;
 
 	gboolean defer_all;
@@ -332,6 +336,7 @@
 	AERR_SYNTAX,
 	AERR_NOSPOOL,
 	AERR_NORCPT,
+	AERR_SIZE,  /* max msg size exeeded (SMTP SIZE) */
 	AERR_UNKNOWN
 } accept_error;
 
--- a/src/smtp_in.c	Wed Jun 30 15:45:34 2010 +0200
+++ b/src/smtp_in.c	Thu Jul 01 13:08:53 2010 +0200
@@ -55,8 +55,29 @@
 	return SMTP_ERROR;
 }
 
+static gboolean
+get_size(gchar *line, unsigned long *msize) {
+	gchar *s = NULL;
+
+	/* hope we need not to handle cases like SiZe= ...*/
+	s = strstr(line, "SIZE=");
+	if (!s) {
+		/* try it in lowercase too */
+		if (!(s = strstr(line, "size="))) {
+			return FALSE;
+		}
+	}
+	s += 5;
+	*msize = atol(s);
+	DEBUG(5) debugf("get_size(): line=%s, msize=%ld\n", line, *msize);
+
+	return TRUE;
+}
+
+
 /* this is a quick hack: we expect the address to be syntactically correct
-   and containing the mailbox only:
+   and containing the mailbox only, though we first check for size in
+   smtp_in().
 */
 static gboolean
 get_address(gchar * line, gchar * addr)
@@ -135,6 +156,7 @@
 	message *msg = NULL;
 	smtp_connection *psc;
 	int len;
+	unsigned long size, msize;
 
 	DEBUG(5) debugf("smtp_in entered, remote_host = %s\n", remote_host);
 
@@ -168,7 +190,7 @@
 
 			if (psc->prot == PROT_ESMTP) {
 				smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name);
-				/* not yet: fprintf(out, "250-SIZE\r\n"); */
+				smtp_printf(out, "250-SIZE %d\r\n", conf.max_msg_size);
 				smtp_printf(out, "250-PIPELINING\r\n" "250 HELP\r\n");
 			} else {
 				smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name);
@@ -176,6 +198,15 @@
 			break;
 
 		case SMTP_MAIL_FROM:
+			if (get_size(buffer, &msize)) {
+				DEBUG(5) debugf("smtp_in(): get_size: msize=%ld, conf.mms=%d\n",
+				                msize, conf.max_msg_size);
+				if (msize > conf.max_msg_size) {
+					smtp_printf(out, "552 Message size exceeds fixed limit.\r\n");
+					break;
+				}
+			}
+
 			{
 				gchar buf[MAX_ADDRESS];
 				address *addr;
@@ -278,12 +309,18 @@
 
 			err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0);
 			if (err != AERR_OK) {
-				if (err == AERR_TIMEOUT || err == AERR_EOF) {
+				switch (err) {
+				case AERR_TIMEOUT:
+				case AERR_EOF:
+					return;
+				case AERR_SIZE:
+					smtp_printf(out, "552 Error: message too large.\r\n");
+					return;
+				default:
+					/* should never happen: */
+					smtp_printf(out, "451 Unknown error\r\n");
 					return;
 				}
-				/* should never happen: */
-				smtp_printf(out, "451 Unknown error\r\n");
-				return;
 			}