#include /* for exit(), getenv() */ #include #include #include /* for stat() */ #include /* for stat() */ #include /* for stat() */ #include /* for perror */ #include /* for ENOENT */ #include /* for ofstream() */ #include /* for creat() */ #include /* for gettimeofday() */ using namespace std; const int sa_good = 0; const int bug_bait_grey = 1; // qmail_queue and spamc have similar interpretations here: const int sa_syserr = 71; pid_t mypid; string progname; void dump(const string var){ char* str = getenv(var.c_str()); cerr << progname << "[" << mypid << "] " << var; if (str) cerr << " is set to '" << str << "'" << endl; else cerr << " is not set." << endl; } const string dirname("/var/qmail/greylist"); // int stat(const char *path, struct stat *buf); // int fstat(int fd, struct stat *buf); // int lstat(const char *path, struct stat *buf); const int minute(60); const int hour(60*minute); const int day(24*hour); class whatsit{ public: string progname; pid_t mypid; timeval now; string ipname; int mod_age; int ac_age; whatsit(const string name) : progname(name), mypid(getpid()) { gettimeofday(&now, NULL); } int doit(); // access comes after modification: void update(const string msg, const timeval new_mod, const timeval new_ac); }; void whatsit::update(const string msg, const timeval new_mod, const timeval new_ac){ cerr << progname << ": " << msg << ": " << ipname << " mod_age: " << mod_age << " ac_age: " << ac_age << endl; timeval upd[2] = { // beware: access illogically comes *before* modification here: new_ac, new_mod }; utimes(ipname.c_str(), upd); } int main(int argc, char** argv){ // dump("TCPREMOTEIP"); // dump("TCPREMOTEHOST"); whatsit foo(argv[0]); return foo.doit(); } int whatsit::doit(){ char* ipvar = getenv("TCPREMOTEIP"); if (!ipvar) { cerr << progname << ": TCPREMOTEIP not set???" << endl; exit(sa_syserr); } string ipbase = ipvar; // see if our directory exists: struct stat dirstat; int rslt = stat(dirname.c_str(), &dirstat); if (rslt != 0){ if (errno != ENOENT) { cerr << progname << ": stat failed for '" << dirname << "' : "; perror(0); } rslt = mkdir(dirname.c_str(), 0755); if (rslt != 0) { cerr << progname << "uid " << getuid() << ": mkdir failed for '" << dirname << "' : "; perror(0); exit(sa_syserr); } } ipname = dirname + "/" + ipbase; struct stat ipstat; rslt = stat(ipname.c_str(), &ipstat); if (rslt != 0){ if (errno != ENOENT) { cerr << progname << ": stat failed for '" << ipname << "' : "; perror(0); } ofstream foo; int fd = creat(ipname.c_str(), 0644); if (fd < 0){ cerr << progname << ": create failed for '" << ipname << "' : "; perror(0); } close(fd); update("new customer", now, now); return(bug_bait_grey); } // here if stat succeeded mod_age = now.tv_sec - ipstat.st_mtime; ac_age = now.tv_sec - ipstat.st_atime; timeval mod_orig = {ipstat.st_mtime, 0}; if (mod_age < 5*minute) { update("early bird", mod_orig, now); return(bug_bait_grey); } if (ac_age < 32*day) { update("returning customer", mod_orig, now); return 0; } // here if it is too old: update("too old, starting over", now, now); return(bug_bait_grey); }