[Mimedefang] Multiline Responses revisited

Michiel Brandenburg apex at xepa.nl
Tue Jun 9 16:13:02 EDT 2009


Howdie all,

Attached there is a patch against mimedefang.c to enable multiline 
responses.  This was mentioned in the mailing list some time back and 
was a todo on my private mimedefang list.

Can someone take a look at it, and implement it within mimedefang if you 
like it.  Now my c is kinda rusty so there might be some errors 
somewhere, hey at least it compiles without errors :)

Guess I found Jan's extra second in 2005, better late than never.

Keep up the good work all,
--
Michiel

-------------- next part --------------
--- mimedefang.c.original	2009-06-09 00:20:53.000000000 +0200
+++ mimedefang.c	2009-06-09 21:57:06.000000000 +0200
@@ -216,6 +216,13 @@ static int set_reply(SMFICTX *ctx, char 
 /* Number of file descriptors to close when forking */
 #define CLOSEFDS 256
 
+/* Amount of new lines in a response we want to handle (milters max is 32 do not raise above that) 
+   As it HAS to be NULL terminated the list is realy one smaller 
+*/
+#define REPLY_MAX_BUFF_SIZE 32-1
+/* max string length of a reply to milter (max is 970 chars including \0 ) */
+#define REPLY_MAX_STR_LENGTH 970
+
 /* Mutex to protect mkdir() calls */
 static pthread_mutex_t MkdirMutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -336,6 +343,8 @@ set_reply(SMFICTX *ctx,
 	  char const *reply)
 {
     char *safe_reply;
+    int retcode;
+    
     if (!reply || !*reply) {
 	if (*first == '4') {
 	    reply = "Please try again later";
@@ -351,10 +360,8 @@ set_reply(SMFICTX *ctx,
 	if (*first == '4') dsn  = "4.3.0";
 	else               dsn  = "5.7.1";
     }
-
     /* We need to double any "%" chars in reply */
     if (strchr(reply, '%')) {
-	int retcode;
 	char const *s;
 	char *t;
 	/* Worst-case, we'll double our length */
@@ -371,13 +378,73 @@ set_reply(SMFICTX *ctx,
 	    *t++ = *s++;
 	}
 	*t = 0;
-	retcode = smfi_setreply(ctx, (char *) code, (char *) dsn, safe_reply);
-	free(safe_reply);
-	return retcode;
     }
-
+    else {
+      /* copy over the rely to safe_reply */
+      safe_reply = malloc(strlen(reply) + 1);
+      strncpy(safe_reply, reply, strlen(reply));
+	  safe_reply[strlen(reply)]='\0';
+    }
+#ifdef MILTER_BUILDLIB_HAS_SETMLREPLY
+    // if we encounter a \n enter nasty milter phase
+	char *token = strtok(safe_reply, "\n");
+    if ( token != NULL ) {
+      int size = 0;
+      char *replyBuff[REPLY_MAX_BUFF_SIZE];
+      int i = -1;
+	  while( token != NULL && ++i < REPLY_MAX_BUFF_SIZE ) {
+	    // each reply cannot be large than MAX_REPLY_SIZE
+		size = (strlen(token) > REPLY_MAX_STR_LENGTH - 1 ? REPLY_MAX_STR_LENGTH - 1 : strlen(token) );
+        if ( strlen(token) > size ) {
+          syslog(LOG_ERR, "Trunkating reply element [%d] too long", i);
+        }
+
+        if ( !(replyBuff[i] = malloc(size + 1)) ) {
+          syslog(LOG_ERR, "Out of memory splitting reply [%s]",token);
+          return smfi_setreply(ctx, (char *) code, (char *) dsn,
+                        "Out of memory");
+        }
+        strncpy(replyBuff[i], token, size+1);
+		replyBuff[i][size+1]='\0';
+		token = strtok(NULL, "\n");
+	  }
+	  // notify someone if there are more enters in the safe_reply
+	  // as we will not send them (specs u know).
+      if ( strtok(NULL, "\n") != NULL ) {
+        syslog(LOG_ERR, "Dropping extra reply elements");
+      }
+      // initialize all left over buffers
+      while( ++i < REPLY_MAX_BUFF_SIZE ) {
+        replyBuff[i] = NULL;
+      }
+      // send off the reply code (yes I know nasty, tell the milter ppl)
+      retcode = smfi_setmlreply(ctx, (char *) code, (char *) dsn,
+           replyBuff[0], replyBuff[1], replyBuff[2], replyBuff[3], replyBuff[4],
+           replyBuff[5], replyBuff[6], replyBuff[7], replyBuff[8], replyBuff[9],
+           replyBuff[10],replyBuff[11],replyBuff[12],replyBuff[13],replyBuff[14],
+           replyBuff[15],replyBuff[16],replyBuff[17],replyBuff[18],replyBuff[19],
+           replyBuff[20],replyBuff[21],replyBuff[22],replyBuff[23],replyBuff[24],
+           replyBuff[25],replyBuff[26],replyBuff[27],replyBuff[28],replyBuff[29],
+          replyBuff[30], NULL);
+     // prevent leaks and free
+      i = -1;
+      while( i++ > REPLY_MAX_BUFF_SIZE && replyBuff[i] != NULL ) {
+        free(replyBuff[i]);
+      }
+	  free(safe_reply);
+      return retcode;
+    }
+#else 
+	// no smfi_setmlreply support replace all \n with space
+	char *token = NULL;
+    while( (token = strchr(safe_reply, '\n')) != NULL) {
+		*token = ' ';
+	}
+#endif
     /* smfi_setreply is not const-correct, hence the (char *) casts */
-    return smfi_setreply(ctx, (char *) code, (char *) dsn, (char *) reply);
+    retcode = smfi_setreply(ctx, (char *) code, (char *) dsn, safe_reply);
+    free(safe_reply);
+    return retcode;
 }
 
 /**********************************************************************


More information about the MIMEDefang mailing list