]> git.donarmstrong.com Git - deb_pkgs/spamass-milter.git/blobdiff - spamass-milter.cpp
* Import spamass-milter 0.3.1
[deb_pkgs/spamass-milter.git] / spamass-milter.cpp
index 06e54f216cd37b548a9fa6e9f40014541b302fa9..1b89268fcda6679dfb33bfd250f5f37d59c76ded 100644 (file)
@@ -1,6 +1,6 @@
 // 
 //
-//  $Id: spamass-milter.cpp,v 1.86 2005/02/05 07:03:22 dnelson Exp $
+//  $Id: spamass-milter.cpp,v 1.90 2006/03/23 21:41:36 dnelson Exp $
 //
 //  SpamAss-Milter 
 //    - a rather trivial SpamAssassin Sendmail Milter plugin
@@ -127,7 +127,7 @@ int daemon(int nochdir, int noclose);
 
 // }}} 
 
-static const char Id[] = "$Id: spamass-milter.cpp,v 1.86 2005/02/05 07:03:22 dnelson Exp $";
+static const char Id[] = "$Id: spamass-milter.cpp,v 1.90 2006/03/23 21:41:36 dnelson Exp $";
 
 struct smfiDesc smfilter =
   {
@@ -170,6 +170,7 @@ char *spambucket;
 bool flag_full_email = false;          /* pass full email address to spamc */
 bool flag_expand = false;      /* alias/virtusertable expansion */
 bool ignore_authenticated_senders = false;
+bool warnedmacro = false;      /* have we logged that we couldn't fetch a macro? */
 
 #if defined(__FreeBSD__) /* popen bug - see PR bin/50770 */
 static pthread_mutex_t popen_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -297,7 +298,7 @@ main(int argc, char* argv[])
               "          username.  Uses 'defaultdomain' if there was none" << endl;
       cout << "   -f: fork into background" << endl;
       cout << "   -i: skip (ignore) checks from these IPs or netblocks" << endl;
-      cout << "          example: -i 192.168.12.5,10.0.0.0/8,172.16/255.255.0.0" << endl;
+      cout << "          example: -i 192.168.12.5,10.0.0.0/8,172.16.0.0/255.255.0.0" << endl;
       cout << "   -I: skip (ignore) checks if sender is authenticated" << endl;
       cout << "   -m: don't modify body, Content-type: or Subject:" << endl;
       cout << "   -M: don't modify the message at all" << endl;
@@ -684,9 +685,16 @@ retrieve_field(const string& header, const string& field)
   if (header[field_end-1] == '\r')
        field_end--;
 
-  //  Maybe remove the whitespace picked up when a header wraps - this
-  //  might actually be a requirement
-  return header.substr( field_start, field_end - field_start );
+  string data = header.substr( field_start, field_end - field_start );
+  
+  /* Replace all CRLF pairs with LF */
+  idx = 0;
+  while ( (idx = data.find("\r\n", idx)) != string::npos )
+  {
+       data.replace(idx,2,"\n");
+  }
+
+  return data;
 }
 
 
@@ -705,6 +713,7 @@ sfsistat
 mlfi_connect(SMFICTX * ctx, char *hostname, _SOCK_ADDR * hostaddr)
 {
        struct context *sctx;
+       int rv;
 
        debug(D_FUNC, "mlfi_connect: enter");
 
@@ -723,7 +732,13 @@ mlfi_connect(SMFICTX * ctx, char *hostname, _SOCK_ADDR * hostaddr)
        sctx->helo = NULL;
        
        /* store a pointer to it with setpriv */
-       smfi_setpriv(ctx, sctx);
+       rv = smfi_setpriv(ctx, sctx);
+       if (rv != MI_SUCCESS)
+       {
+               debug(D_ALWAYS, "smfi_setpriv failed!");
+               return SMFIS_TEMPFAIL;
+       }
+       /* debug(D_ALWAYS, "ZZZ set private context to %p", sctx); */
 
        if (ip_in_networklist(sctx->connect_ip, &ignorenets))
        {
@@ -767,6 +782,13 @@ mlfi_envfrom(SMFICTX* ctx, char** envfrom)
   struct context *sctx = (struct context *)smfi_getpriv(ctx);
   char *queueid;
 
+  if (sctx == NULL)
+  {
+    debug(D_ALWAYS, "smfi_getpriv failed!");
+    return SMFIS_TEMPFAIL;
+  }
+  /* debug(D_ALWAYS, "ZZZ got private context %p", sctx); */
+
   if (ignore_authenticated_senders)
   {
     char *auth_authen;
@@ -803,7 +825,10 @@ mlfi_envfrom(SMFICTX* ctx, char** envfrom)
   
   queueid=smfi_getsymval(ctx,"i");
   if (!queueid)
-    queueid="unk";
+  {
+    queueid="unknown";
+    warnmacro("i", "ENVFROM");
+  }
   assassin->queueid = queueid;
 
   debug(D_MISC, "queueid=%s", queueid);
@@ -920,13 +945,44 @@ mlfi_envrcpt(SMFICTX* ctx, char** envrcpt)
                                (envelope-from $g)$.
                   
                */
-               const char *macro_b, *macro_s, *macro_j, *macro__;
+               const char *macro_b, *macro_i, *macro_j, *macro_r,
+                          *macro_s, *macro_v, *macro_Z, *macro__;
+               char date[32];
 
-               /* Failure to fetch {b} is not fatal.  Without this date SA can't do
-                  future/past validation on the Date: header, but sendmail doesn't
-                  default to allow milters to see it.
-               */
+               /* RFC 822 date. */
                macro_b = smfi_getsymval(ctx, "b");
+               if (!macro_b)                                  
+               {
+                       time_t tval;
+                       time(&tval);
+                       strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&tval));
+                       macro_b = date;
+                       warnmacro("b", "ENVRCPT");
+               }
+
+               /* queue ID */
+               macro_i = smfi_getsymval(ctx, "i");
+               if (!macro_i)
+               {
+                       macro_i = "unknown";
+                       warnmacro("i", "ENVRCPT");
+               }
+
+               /* FQDN of this site */
+               macro_j = smfi_getsymval(ctx, "j");
+               if (!macro_j)
+               {
+                       macro_j = "localhost";
+                       warnmacro("j", "ENVRCPT");
+               }
+
+               /* Protocol used to receive the message */
+               macro_r = smfi_getsymval(ctx, "r");
+               if (!macro_r)
+               {
+                       macro_r = "SMTP";
+                       warnmacro("r", "ENVRCPT");
+               }
                        
                /* Sendmail currently cannot pass us the {s} macro, but
                   I do not know why.  Leave this in for the day sendmail is
@@ -939,23 +995,38 @@ mlfi_envrcpt(SMFICTX* ctx, char** envrcpt)
                if (!macro_s)
                        macro_s = "nohelo";
 
-               /* FQDN of this site */
-               macro_j = smfi_getsymval(ctx, "j");
-               if (!macro_j)
-                       macro_j = "localhost";
+               /* Sendmail binary version */
+               macro_v = smfi_getsymval(ctx, "v");
+               if (!macro_v)
+               {
+                       macro_v = "8.13.0";
+                       warnmacro("v", "ENVRCPT");
+               }
 
-               /* Sending site's address */
+               /* Sendmail .cf version */
+               macro_Z = smfi_getsymval(ctx, "Z");
+               if (!macro_Z)
+               {
+                       macro_Z = "8.13.0";
+                       warnmacro("Z", "ENVRCPT");
+               }
+
+               /* Validated sending site's address */
                macro__ = smfi_getsymval(ctx, "_");
                if (!macro__)
+               {
                        macro__ = "unknown";
+                       warnmacro("_", "ENVRCPT");
+               }
 
                assassin->output((string)"X-Envelope-From: "+assassin->from()+"\r\n");
                assassin->output((string)"X-Envelope-To: "+envrcpt[0]+"\r\n");
 
-               if (!macro_b)
-                       assassin->output((string)"Received: from "+macro_s+" ("+macro__+") by "+macro_j+";\r\n");
-               else
-                       assassin->output((string)"Received: from "+macro_s+" ("+macro__+") by "+macro_j+"; "+macro_b+"\r\n");
+               assassin->output((string)
+                       "Received: from "+macro_s+" ("+macro__+")\r\n\t"+
+                       "by "+macro_j+"("+macro_v+"/"+macro_Z+") with "+macro_r+" id "+macro_i+"\r\n\t"+
+                       macro_b+"\r\n\t"+
+                       "(envelope-from "+assassin->from()+"\r\n");
 
        } else
                assassin->output((string)"X-Envelope-To: "+envrcpt[0]+"\r\n");
@@ -1204,11 +1275,8 @@ mlfi_close(SMFICTX* ctx)
   
   sctx = (struct context*)smfi_getpriv(ctx);
   if (sctx == NULL)
-  {
-    /* the context should have been set in mlfi_connect */
-       debug(D_ALWAYS, "NULL context in mlfi_close! Should not happen!");
     return SMFIS_ACCEPT;
-  }
+
   if (sctx->helo)
        free(sctx->helo);
   free(sctx);
@@ -1987,7 +2055,7 @@ cmp_nocase_partial(const string& s, const string& s2)
   string::const_iterator p=s.begin();
   string::const_iterator p2=s2.begin();
 
-  while ( p != s.end() && p2 != s2.end() ) {
+  while ( p != s.end() && p2 <= s2.end() ) {
     if (toupper(*p) != toupper(*p2))
     {
       debug(D_STR, "c_nc_p: <%s><%s> : miss", s.c_str(), s2.c_str());
@@ -2101,5 +2169,15 @@ char *strlwr(char *str)
     return str;
 }
 
+/* Log a message about missing milter macros, but only the first time */
+void warnmacro(char *macro, char *scope)
+{
+       if (warnedmacro)
+               return;
+       debug(D_ALWAYS, "Could not retrieve sendmail macro \"%s\"!.  Please add it to confMILTER_MACROS_%s for better spamassassin results",
+               macro, scope);
+       warnedmacro = true;
+}
+
 // }}}
 // vim6:ai:noexpandtab