From 010db437f35e831d170a726aad88bcc305c7b668 Mon Sep 17 00:00:00 2001
From: John Denker <jsd@av8n.com>
Date: Sun, 22 Jul 2012 19:10:38 -0700
Subject: implement "-stain" feature;  the "-penalty" feature was a baaaad idea

---
 tools/filters.conf |  2 +-
 tools/greylist.c   | 57 +++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 38 insertions(+), 21 deletions(-)

(limited to 'tools')

diff --git a/tools/filters.conf b/tools/filters.conf
index 7768e6a..bd8eb33 100644
--- a/tools/filters.conf
+++ b/tools/filters.conf
@@ -5,4 +5,4 @@ sa      /usr/local/bin/spamc -Y 0 -s 1000000 -x
 qq      /var/qmail/bin/qmail-queue
 
 # postspam /var/qmail/bin/greylist -suffix (post) -penalize 86400 -v
-postspam /var/qmail/bin/greylist -suffix (post) -penalize 1 -v
+postspam /var/qmail/bin/greylist -suffix (post) -stain 1 -v
diff --git a/tools/greylist.c b/tools/greylist.c
index fd5ac4f..92e638f 100644
--- a/tools/greylist.c
+++ b/tools/greylist.c
@@ -113,10 +113,10 @@ public:
   {
     gettimeofday(&now, NULL);
   }
-  int doit(const int penalty=0);
+  int doit(const int penalty, const int stain);
 // access comes after modification:
   void update(const string msg, const timeval new_mod,
-        const timeval new_ac, const int penalty=0);
+        const timeval new_ac, const int penalty, const int stain);
   int setup();
   int check_dns();
   int check_dns_sub(string &addr, string &host, vector<string> &checked);
@@ -216,27 +216,37 @@ void scan(const string progid, const string p, const int copies=1){
 }
 
 void whatsit::update(const string msg, const timeval new_mod,
-     const timeval new_ac, const int penalty){
+     const timeval new_ac, const int penalty, const int stain){
   if (verbosity){
     cerr << progid << ": ";
-    if (penalty) cerr << " penalty+";
-    cerr << msg << ": " << ipbase;
-    if (hostname.length()) cerr <<  " " << hostname;
-    cerr << "  mod_age: " << time_out(mod_age)
-            << "  ac_age: " << time_out(ac_age)
-            << endl;
+    if (penalty) cerr << " penalty " << penalty;
+    if (stain) cerr << " stain " << stain;
+    if (verbosity > 1) {
+      if (penalty || stain) cerr << "+";         // separation, punctuation
+      cerr << msg << ": " << ipbase;
+      if (hostname.length()) cerr <<  " " << hostname;
+      cerr << "  mod_age: " << time_out(mod_age)
+              << "  ac_age: " << time_out(ac_age);
+    }
+    cerr << endl;
   }
   timeval pen_mod(new_mod);
+  timeval stain_ac(new_ac);
   if (penalty) {
     pen_mod = now;
     pen_mod.tv_sec += penalty;
   }
+  if (stain) {
+    stain_ac = now;
+    stain_ac.tv_sec -= stain;
+  }
   timeval upd[2] = {
 // beware:  access illogically comes *before* modification here:
-    new_ac,
+    stain_ac,
     pen_mod
   };
-  utimes(ipname.c_str(), upd);
+  if (utimes(ipname.c_str(), upd))
+    cerr << "oops" << endl;
 }
 
 
@@ -249,6 +259,7 @@ int main(int _argc, char** _argv){
   int scanmode(0);
   int copies(1);
   int penalty(0);
+  int stain(0);
   int check(0);
   while (argc > 0) {
     string arg = argv[0]; argc--; argv++;
@@ -267,6 +278,12 @@ int main(int _argc, char** _argv){
         exeunt(ex_syserr);
       }
       penalty = atoi(*argv++);  argc--;
+    } else if (prefix(arg, "-stain"))  {
+      if (!argc){
+        cerr << "Option '" << arg << "' requires an argument" << endl;
+        exeunt(ex_syserr);
+      }
+      stain = atoi(*argv++);  argc--;
     } else if (prefix(arg, "-suffix")) {
       if (!argc){
         cerr << "Option '" << arg << "' requires an argument" << endl;
@@ -285,7 +302,7 @@ int main(int _argc, char** _argv){
     return 0;
   }
 
-  int sts = foo.doit(penalty);
+  int sts = foo.doit(penalty, stain);
   if (sts == ex_syserr) return sts;
   if (!check) return ex_good;
 
@@ -299,7 +316,7 @@ int main(int _argc, char** _argv){
   exeunt(sts);
 }
 
-int whatsit::doit(const int penalty){
+int whatsit::doit(const int penalty, const int stain){
 
   if (!ipvar) {
     cerr << progid
@@ -346,7 +363,7 @@ int whatsit::doit(const int penalty){
       perror(0);
     }
     close(fd);
-    update("new customer", now, now, penalty);
+    update("new customer", now, now, penalty, stain);
     return(ex_greylisting);
   }
 
@@ -355,29 +372,29 @@ int whatsit::doit(const int penalty){
   ac_age = now.tv_sec - ipstat.st_atime;
   timeval mod_orig = {ipstat.st_mtime, 0};
   if (mod_age < 0) {
-    update("penalty box", mod_orig, now, penalty);
+    update("penalty box", mod_orig, now, penalty, stain);
     return(ex_penaltybox);
   }
   if (mod_age < ac_age){
 // when he comes out on parole, he starts over with no reputation:
-    update("paroled spammer", now, now, penalty);
+    update("paroled spammer", now, now, penalty, stain);
     return(ex_greylisting);
   }
   if (mod_age < minimum_age) {
-    update("early bird", mod_orig, now, penalty);
+    update("early bird", mod_orig, now, penalty, stain);
     return(ex_greylisting);
   }
   if (mod_age - ac_age < minimum_age    // early bird, or completely unused
     && mod_age > probation) {           // did not diligently resubmit
-    update("disprobation", now, now, penalty);
+    update("disprobation", now, now, penalty, stain);
     return(ex_greylisting);
   }
   if (ac_age > maximum_age) {
-    update("too old, starting over", now, now, penalty);
+    update("too old, starting over", now, now, penalty, stain);
     return(ex_greylisting);
   }
 // if all checks are passed, must be OK:
-  update("returning customer", mod_orig, now, penalty);
+  update("returning customer", mod_orig, now, penalty, stain);
   return 0;
 }
 
-- 
cgit v1.2.3