summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Denker <jsd@av8n.com>2012-07-19 17:24:43 -0700
committerJohn Denker <jsd@av8n.com>2012-07-19 17:24:43 -0700
commitd4ca9eda839b2c9d3bbbf8b48617977f483001b2 (patch)
tree0b8a5c2a93c48ee52a72a3c3d9d69fb563280059
parent82616449ee0c9f704e8c123d8b485c65fe428179 (diff)
bare beginnings of a greylisting system
-rw-r--r--.gitignore3
-rw-r--r--tools/filters.conf1
-rw-r--r--tools/greylist.c89
-rw-r--r--tools/hi-q.c111
4 files changed, 152 insertions, 52 deletions
diff --git a/.gitignore b/.gitignore
index 3561ee3..ca1ef6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
*.orig
*.rej
*.logg
+*#[0-9]*
has?????.h
auto-gid
@@ -151,7 +152,9 @@ checkpasswd/hasuserpw.h
skrewt
mail-scan
hi-test
+greylist
+auto_uids.c
control.tar.gz
data.tar.gz
dummy-mail-transfer-agent_all.deb
diff --git a/tools/filters.conf b/tools/filters.conf
index 8bc2efe..641b792 100644
--- a/tools/filters.conf
+++ b/tools/filters.conf
@@ -1,4 +1,5 @@
# configuration file for hi-q
black /var/qmail/bin/skrewt
+gray /var/qmail/bin/greylist
black /usr/local/bin/spamc -Y 0 -s 1000000
qq /var/qmail/bin/qmail-queue
diff --git a/tools/greylist.c b/tools/greylist.c
index fa7d701..8adac05 100644
--- a/tools/greylist.c
+++ b/tools/greylist.c
@@ -1,5 +1,92 @@
+#include <stdlib.h> /* for exit(), getenv() */
+#include <iostream>
+#include <string>
+#include <sys/types.h> /* for stat() */
+#include <sys/stat.h> /* for stat() */
+#include <unistd.h> /* for stat() */
+#include <stdio.h> /* for perror */
+#include <errno.h> /* for ENOENT */
+#include <fstream> /* for ofstream() */
+#include <fcntl.h> /* for creat() */
+using namespace std;
-int main(){
+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);
+
+int main(int argc, char** argv){
+ mypid = getpid();
+ progname = argv[0];
+// dump("TCPREMOTEIP");
+// dump("TCPREMOTEHOST");
+
+ 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);
+ }
+ }
+
+ string 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);
+ return(bug_bait_grey);
+ } else {
+ cerr << "file exists: " << ipname << endl;
+ }
return 0;
}
diff --git a/tools/hi-q.c b/tools/hi-q.c
index 2ddc448..21724a1 100644
--- a/tools/hi-q.c
+++ b/tools/hi-q.c
@@ -11,7 +11,7 @@
#include <unistd.h>
#include <stdlib.h> /* for exit(), getenv() */
-#include <stdio.h>
+#include <stdio.h> /* for perror */
#include <errno.h>
#include <sys/types.h> /* for fork(), wait() */
#include <sys/stat.h>
@@ -29,6 +29,7 @@ using namespace std;
// error exit codes, mostly as stated in qmail.c
const int ex_good = 0;
const int ex_spam = 21;
+const int ex_grey = 70;
const int ex_syserr = 71;
const int ex_comerr = 74;
@@ -139,7 +140,7 @@ int xclose(int arg){
extern char** environ;
-typedef enum {gray, black, qq, fail} moder;
+typedef enum {grey, black, qq, fail} moder;
class jobber{
public:
@@ -161,8 +162,8 @@ public:
void setmode(const string _mode) {
if (0) {}
- else if (_mode == "gray") mode = gray;
- else if (_mode == "grey") mode = gray; // variant spelling
+ else if (_mode == "gray") mode = grey;
+ else if (_mode == "grey") mode = grey; // variant spelling
else if (_mode == "black") mode = black;
else if (_mode == "qq") mode = qq;
else {
@@ -175,8 +176,8 @@ public:
int main(int argc, char** argv) {
progname = *argv;
mypid = getpid();
- dump("TCPREMOTEIP");
- dump("TCPREMOTEHOST");
+// dump("TCPREMOTEIP");
+// dump("TCPREMOTEHOST");
int verbose(0);
int kidstatus;
@@ -270,41 +271,44 @@ int main(int argc, char** argv) {
// to close it and dup() something useful onto it.
map<int,int> iiofpid;
- for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */
- int datapipe[2];
- int kid_end;
+ for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */
//xx fprintf(stderr, "Top of loop %d loose: %d\n", ii, loose_end);
- if (loose_end) {
- close(0);
- dup2(loose_end, 0);
- close(loose_end);
- }
+ int kid_end;
+ if (filter[ii].mode != grey){
+ int datapipe[2];
-// Create a pipe, which will be used to connect
-// this child's fd1 to the next child's fd0 ...
-// except for the last kid, which reads both fd0 and fd1,
-// while writing nothing.
+ if (loose_end) {
+ close(0);
+ dup2(loose_end, 0);
+ close(loose_end);
+ }
- rslt = pipe(datapipe);
- if (rslt < 0) {
- fprintf(stderr, "hi-q: could not create datapipe: ");
- perror(0);
- panic(ex_syserr);
- }
+ // Create a pipe, which will be used to connect
+ // this child's fd1 to the next child's fd0 ...
+ // except for the last kid, which reads both fd0 and fd1,
+ // while writing nothing.
-//xx fprintf(stderr, "pipe: %d %d\n", datapipe[0], datapipe[1]);
+ rslt = pipe(datapipe);
+ if (rslt < 0) {
+ fprintf(stderr, "hi-q: could not create datapipe: ");
+ perror(0);
+ panic(ex_syserr);
+ }
-// For N-1 kids, the loose end feeds forward.
-// It will be written by this kid and read by the next kid.
-// For the last kid, the loose end connects to hi-q.
-// It will be written by hi-q and read by the last kid.
+ //xx fprintf(stderr, "pipe: %d %d\n", datapipe[0], datapipe[1]);
- int lastkid = (ii == nkids-1);
-#define flip(a,b) (lastkid ? b : a)
- loose_end = datapipe[flip(rEnd, wEnd)];
- kid_end = datapipe[flip(wEnd, rEnd)];
+ // For N-1 kids, the loose end feeds forward.
+ // It will be written by this kid and read by the next kid.
+ // For the last kid, the loose end connects to hi-q.
+ // It will be written by hi-q and read by the last kid.
+
+ int lastkid = (ii == nkids-1);
+ #define flip(a,b) (lastkid ? b : a)
+ loose_end = datapipe[flip(rEnd, wEnd)];
+ kid_end = datapipe[flip(wEnd, rEnd)];
+ }
kidpid[ii] = fork();
if (kidpid[ii] == -1) {
@@ -358,24 +362,23 @@ int main(int argc, char** argv) {
}
}
-// Now that we are through creating pipes, we don't
-// need to continue blocking fd1:
- close(1);
-
- close(loose_end); // the reading end is none of this kid's business
- // except last kid: writing end
+ if (filter[ii].mode != grey){
+ close(loose_end); // the reading end is none of this kid's business
+ // except last kid: writing end
+
+ // Note this does an implicit close on the previously-open fd1:
+ rslt = dup2(kid_end, 1); // the writing end is stdout for this kid
+ // except last kid: nonstandard input
+ if (rslt < 0) {
+ fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end);
+ perror(0);
+ exit(ex_syserr);
+ }
- rslt = dup2(kid_end, 1); // the writing end is stdout for this kid
- // except last kid: nonstandard input
- if (rslt < 0) {
- fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end);
- perror(0);
- exit(ex_syserr);
+ close(kid_end); // use fd1 instead now
+ // OK, at this point this kid is set up to read fd0 and write fd1
+ // (except last kid reads fd1 as well as fd0).
}
-
- close(kid_end); // use fd1 instead now
- // OK, at this point this kid is set up to read fd0 and write fd1
- // (except last kid reads fd1 as well as fd0).
//// probe_fd();
int ntok = filter[ii].cmd.size();
@@ -499,14 +502,20 @@ int main(int argc, char** argv) {
if (best_blame) {
string short_name("");
int kidno(iiofpid[argbest_blame]);
+ string exword = "spam";
+ int excode = ex_spam;
+ if (filter[kidno].mode == grey) {
+ exword = "greylisting";
+ excode = ex_grey;
+ }
if (WIFEXITED(best_blame)) {
int sts = WEXITSTATUS(best_blame);
if (sts == 1) {
cerr << "hi-q says: kid[" << kidno << "]"
<< " pid " << argbest_blame
<< " i.e. '" << filter[kidno].cmd[0] << "'"
- << " reports spam." << endl;
- panic(ex_spam);
+ << " reports " << exword << endl;
+ panic(excode);
}
if (sts != 0) {
cerr << "hi-q says: kid " << argbest_blame