From b36d52a0dd7315a969f2a9a7455717466e45be23 Mon Sep 17 00:00:00 2001 From: Pawel Foremski Date: Sat, 1 Apr 2006 22:48:04 +0200 Subject: [PATCH] qmail SPP patch https://sourceforge.net/projects/qmail-spp/files/qmail-spp/0.42/qmail-spp-0.42.tar.gz --- Makefile | 11 ++- qmail-smtpd.c | 28 +++++- qmail-spp.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++ qmail-spp.h | 14 +++ 4 files changed, 297 insertions(+), 7 deletions(-) create mode 100644 qmail-spp.c create mode 100644 qmail-spp.h diff --git a/Makefile b/Makefile index 08810df..fc0bd02 100644 --- a/Makefile +++ b/Makefile @@ -1541,16 +1541,21 @@ auto_uids.h auto_users.h auto_qmail.h auto_break.h auto_patrn.h \ auto_spawn.h auto_split.h ./compile qmail-showctl.c +qmail-spp.o: \ +compile qmail-spp.c readwrite.h stralloc.h substdio.h control.h str.h \ +byte.h env.h exit.h wait.h fork.h fd.h fmt.h getln.h + ./compile qmail-spp.c + qmail-smtpd: \ load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \ date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \ open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \ -fs.a auto_qmail.o base64.o socket.lib +fs.a auto_qmail.o base64.o qmail-spp.o socket.lib ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \ received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \ - datetime.a getln.a open.a sig.a case.a env.a stralloc.a \ + datetime.a getln.a open.a sig.a case.a qmail-spp.o env.a stralloc.a \ alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \ socket.lib` @@ -1562,7 +1567,7 @@ compile qmail-smtpd.c sig.h readwrite.h stralloc.h gen_alloc.h \ substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \ error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \ substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \ -exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h +exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h qmail-spp.h ./compile qmail-smtpd.c qmail-start: \ diff --git a/qmail-smtpd.c b/qmail-smtpd.c index a87a1d8..2c2bfb5 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c @@ -24,9 +24,12 @@ #include "timeoutwrite.h" #include "commands.h" #include "wait.h" +#include "qmail-spp.h" #define AUTHSLEEP 5 +int spp_val; + #define MAXHOPS 100 unsigned int databytes = 0; int timeout = 1200; @@ -129,6 +132,7 @@ void setup() if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control(); if (timeout <= 0) timeout = 1; if (rcpthosts_init() == -1) die_control(); + if (spp_init() == -1) die_control(); bmfok = control_readfile(&bmf,"control/badmailfrom",0); if (bmfok == -1) die_control(); @@ -252,6 +256,7 @@ int seenauth = 0; int seenmail = 0; int flagbarf; /* defined if seenmail */ int flagsize; +int allowed; stralloc mailfrom = {0}; stralloc rcptto = {0}; stralloc fuser = {0}; @@ -316,14 +321,16 @@ void mailfrom_parms(arg) char *arg; void smtp_helo(arg) char *arg; { + if(!spp_helo(arg)) return; smtp_greet("250 "); out("\r\n"); seenmail = 0; dohelo(arg); } void smtp_ehlo(arg) char *arg; { char size[FMT_ULONG]; + if(!spp_helo(arg)) return; size[fmt_ulong(size,(unsigned int) databytes)] = 0; - smtp_greet("250-"); + smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n"); if (smtpauth == 1 || smtpauth == 11) out("250-AUTH LOGIN PLAIN\r\n"); if (smtpauth == 2 || smtpauth == 12) out("250-AUTH CRAM-MD5\r\n"); @@ -333,7 +340,8 @@ void smtp_ehlo(arg) char *arg; } void smtp_rset(arg) char *arg; { - seenmail = 0; seenauth = 0; + spp_rset(); + seenmail = 0; seenauth = 0; mailfrom.len = 0; rcptto.len = 0; out("250 flushed\r\n"); } @@ -342,9 +350,11 @@ void smtp_mail(arg) char *arg; if (smtpauth) if (smtpauth > 10 && !seenauth) { err_submission(); return; } if (!addrparse(arg)) { err_syntax(); return; } + if (!(spp_val = spp_mail())) return; flagsize = 0; mailfrom_parms(arg); if (flagsize) { err_size(); return; } + if (spp_val == 1) flagbarf = bmfcheck(); seenmail = 1; if (!stralloc_copys(&rcptto,"")) die_nomem(); @@ -356,13 +366,18 @@ void smtp_rcpt(arg) char *arg; { if (!seenmail) { err_wantmail(); return; } if (!addrparse(arg)) { err_syntax(); return; } if (flagbarf) { err_bmf(); return; } + if (!relayclient) allowed = addrallowed(); + else allowed = 1; + if (!(spp_val = spp_rcpt(allowed))) return; if (relayclient) { --addr.len; if (!stralloc_cats(&addr,relayclient)) die_nomem(); if (!stralloc_0(&addr)) die_nomem(); } - else - if (!addrallowed()) { err_nogateway(); return; } + else if (spp_val == 1) { + if (!allowed) { err_nogateway(); return; } + } + spp_rcpt_accepted(); if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem(); @@ -477,6 +492,7 @@ void smtp_data(arg) char *arg; { if (!seenmail) { err_wantmail(); return; } if (!rcptto.len) { err_wantrcpt(); return; } + if (!spp_data()) return; seenmail = 0; if (databytes) bytestooverflow = databytes + 1; if (qmail_open(&qqt) == -1) { err_qqt(); return; } @@ -484,6 +500,8 @@ void smtp_data(arg) char *arg; { out("354 go ahead\r\n"); received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo); + qmail_put(&qqt,sppheaders.s,sppheaders.len); /* set in qmail-spp.c */ + spp_rset(); blast(&hops); hops = (hops >= MAXHOPS); if (hops) qmail_fail(&qqt); @@ -734,8 +752,10 @@ char **argv; if (chdir(auto_qmail) == -1) die_control(); setup(); if (ipme_init() != 1) die_ipme(); + if (spp_connect()) { smtp_greet("220 "); out(" ESMTP\r\n"); + } if (commands(&ssin,&smtpcommands) == 0) die_read(); die_nomem(); } diff --git a/qmail-spp.c b/qmail-spp.c new file mode 100644 index 0000000..d9f4340 --- /dev/null +++ b/qmail-spp.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2004-2005 Pawel Foremski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *** Note + * + * This is the core of qmail-spp patch for qmail + * + * Why I made it a separate file? Because I wanted qmail-spp to apply more + * cleanly on heavily patched qmail sources and to make it bit simpler to + * maintain, so don't treat it as a library. + * + * "..." comments marks places where code for other SMTP commands should be + * added, if needed. + * + */ + +#include "readwrite.h" +#include "stralloc.h" +#include "substdio.h" +#include "control.h" +#include "str.h" +#include "byte.h" +#include "env.h" +#include "exit.h" +#include "wait.h" +#include "fork.h" +#include "fd.h" +#include "fmt.h" +#include "getln.h" + +/* stuff needed from qmail-smtpd */ +extern void flush(); +extern void out(); +extern void die_nomem(); +extern stralloc addr; +/* *** */ + +stralloc sppheaders = {0}; +static int spprun = 0; +static int sppfok = 0; +static int sppret; +static stralloc sppf = {0}; +static stralloc plugins_dummy = {0}, plugins_connect = {0}, plugins_helo = {0}, plugins_mail = {0}, + plugins_rcpt = {0}, plugins_data = {0}; /* ... */ +static stralloc error_mail = {0}, error_rcpt = {0}, error_data = {0}; /* ... */ +static stralloc sppmsg = {0}; +static char rcptcountstr[FMT_ULONG]; +static unsigned long rcptcount; +static unsigned long rcptcountall; +static substdio ssdown; +static char downbuf[128]; + +static void err_spp(s1, s2) char *s1, *s2; { out("451 qmail-spp failure: "); out(s1); out(": "); out(s2); out(" (#4.3.0)\r\n"); } + +int spp_init() +{ + int i, len = 0; + stralloc *plugins_to; + char *x, *conffile = "control/smtpplugins"; + + if (!env_get("NOSPP")) { + spprun = 1; + plugins_to = &plugins_dummy; + x = env_get("SPPCONFFILE"); + if (x && *x) conffile = x; + sppfok = control_readfile(&sppf, conffile, 0); + if (sppfok != 1) return -1; + for (i = 0; i < sppf.len; i += len) { + len = str_len(sppf.s + i) + 1; + if (sppf.s[i] == '[') + switch (sppf.s[i + 1]) { + case 'c': plugins_to = &plugins_connect; break; + case 'h': plugins_to = &plugins_helo; break; + case 'm': plugins_to = &plugins_mail; break; + case 'r': plugins_to = &plugins_rcpt; break; + case 'd': plugins_to = &plugins_data; break; + /* ... */ + default: plugins_to = &plugins_dummy; + } + else + if (!stralloc_catb(plugins_to, sppf.s + i, len)) die_nomem(); + } + } + + return 0; +} + +void sppout() { if (sppmsg.len) out(sppmsg.s); out("\r\n"); } + +int spp(plugins, addrenv) stralloc *plugins; char *addrenv; +{ + static int pipes[2]; + static int i, pid, wstat, match, last; + static stralloc data = {0}; + static char *(args[4]); + static stralloc *errors_to; + + if (!spprun) return 1; + if (addrenv) if (!env_put2(addrenv, addr.s)) die_nomem(); + last = 0; + + for (i = 0; i < plugins->len; i += str_len(plugins->s + i) + 1) { + if (plugins->s[i] == ':') + { args[0] = "/bin/sh"; args[1] = "-c"; args[2] = plugins->s + i + 1; args[3] = 0; } + else + { args[0] = plugins->s + i; args[1] = 0; } + + if (pipe(pipes) == -1) + { err_spp(plugins->s + i, "can't pipe()"); return 0; } + + switch (pid = vfork()) { + case -1: + err_spp(plugins->s + i, "vfork() failed"); + return 0; + case 0: + close(0); close(pipes[0]); fd_move(1, pipes[1]); + execv(*args, args); + _exit(120); + } + + close(pipes[1]); + substdio_fdbuf(&ssdown, read, pipes[0], downbuf, sizeof(downbuf)); + do { + if (getln(&ssdown, &data, &match, '\n') == -1) die_nomem(); + if (data.len > 1) { + data.s[data.len - 1] = 0; + switch (data.s[0]) { + case 'H': + if (!stralloc_catb(&sppheaders, data.s + 1, data.len - 2)) die_nomem(); + if (!stralloc_append(&sppheaders, "\n")) die_nomem(); + break; + case 'C': + if (addrenv) { + if (!stralloc_copyb(&addr, data.s + 1, data.len - 1)) die_nomem(); + if (!env_put2(addrenv, addr.s)) die_nomem(); + } + break; + case 'S': if (!env_put(data.s + 1)) die_nomem(); break; + case 'U': if (!env_unset(data.s + 1)) die_nomem(); break; + case 'A': spprun = 0; + case 'O': + case 'N': + case 'D': last = 1; match = 0; break; + case 'E': + case 'R': last = 1; match = 0; + case 'P': out(data.s + 1); out("\r\n"); break; + case 'L': + switch (data.s[1]) { + case 'M': errors_to = &error_mail; break; + case 'R': errors_to = &error_rcpt; break; + case 'D': errors_to = &error_data; break; + /* ... */ + default: errors_to = 0; + } + if (errors_to) { + if (!stralloc_catb(errors_to, data.s + 2, data.len - 3)) die_nomem(); + if (!stralloc_catb(errors_to, "\r\n", 2)) die_nomem(); + } + break; + } + } + } while (match); + + close(pipes[0]); + if (wait_pid(&wstat,pid) == -1) { err_spp(plugins->s + i, "wait_pid() failed"); return 0; } + if (wait_crashed(wstat)) { err_spp(plugins->s + i, "child crashed"); return 0; } + if (wait_exitcode(wstat) == 120) { err_spp(plugins->s + i, "can't execute"); return 0; } + + if (last) + switch (*data.s) { + case 'E': return 0; + case 'A': + case 'N': return 1; + case 'O': return 2; + case 'R': + case 'D': flush(); _exit(0); + } + } + + return 1; +} + +int spp_errors(errors) stralloc *errors; +{ + if (!errors->len) return 1; + if (!stralloc_0(errors)) die_nomem(); + out(errors->s); + return 0; +} + +int spp_connect() { return spp(&plugins_connect, 0); } + +int spp_helo(arg) char *arg; +{ + if (!env_put2("SMTPHELOHOST", arg)) die_nomem(); + return spp(&plugins_helo, 0); +} + +void spp_rset() +{ + if (!stralloc_copys(&sppheaders, "")) die_nomem(); + if (!stralloc_copys(&error_mail, "")) die_nomem(); + if (!stralloc_copys(&error_rcpt, "")) die_nomem(); + if (!stralloc_copys(&error_data, "")) die_nomem(); + /* ... */ + rcptcount = rcptcountall = 0; +} + +int spp_mail() +{ + if (!spp_errors(&error_mail)) return 0; + rcptcount = rcptcountall = 0; + return spp(&plugins_mail, "SMTPMAILFROM"); +} + +int spp_rcpt(allowed) int allowed; +{ + if (!spp_errors(&error_rcpt)) return 0; + rcptcountstr[fmt_ulong(rcptcountstr, rcptcount)] = 0; + if (!env_put2("SMTPRCPTCOUNT", rcptcountstr)) die_nomem(); + rcptcountstr[fmt_ulong(rcptcountstr, ++rcptcountall)] = 0; + if (!env_put2("SMTPRCPTCOUNTALL", rcptcountstr)) die_nomem(); + if (!env_put2("SMTPRCPTHOSTSOK", allowed ? "1" : "0")) die_nomem(); + sppret = spp(&plugins_rcpt, "SMTPRCPTTO"); + return sppret; +} + +void spp_rcpt_accepted() { rcptcount++; } + +int spp_data() +{ + if (!spp_errors(&error_data)) return 0; + return spp(&plugins_data, 0); +} + +/* ... */ diff --git a/qmail-spp.h b/qmail-spp.h new file mode 100644 index 0000000..1ecc274 --- /dev/null +++ b/qmail-spp.h @@ -0,0 +1,14 @@ +#ifndef QMAIL_SPP_H +#define QMAIL_SPP_H + +extern stralloc sppheaders; +extern int spp_init(); +extern int spp_connect(); +extern int spp_helo(); +extern void spp_rset(); +extern int spp_mail(); +extern int spp_rcpt(); +extern int spp_rcpt_accepted(); +extern int spp_data(); + +#endif