Makes qmail-smtpd with AUTH support plus SPF and DKIM.
This is the qmail that we're currently running at antartida.xyz. We took the notqmail repository and essentially applied patches for AUTH, SPF and DKIM. The DKIM patch does not come from the notqmail repository. We took it from the excellent notes at https://www.memoryhole.net/qmail/ We also applied the any-to-cname patch. But we did not take the oversize-dns patch. Any mistakes here are mine---I had to merge it as best we could and resolve various conflicts. This is it. -- MAILER DAEMON :) (*) Commit message from the notqmail branch Remove FILES.auth, add new files to FILES. Realphabetize Makefile targets. Remove trailing whitespace variously. Remove duplication declaration of auth in qmail-smtpd.c Modification to Erwin Hoffmann's SMTP authentication for qmail-smtpd, qmail-remote. Apply Jana Saout's qmail-spf-rc5.patch From https://www.saout.de/misc/spf/ This is an SPF implementation for qmail. SPF is something like a DNS based "reverse MX" system to designate permitted senders for mails depending on the domain name. The goal is to disallow sender address forgery. The patch is entirely written using the qmail string and DNS functions, and thus completely integrated into qmail without external dependencies. It can check incoming mails inside the SMTP daemon, add Received-SPF lines and optionally block undesired transfers. The check is performed at the envelope level.
This commit is contained in:
parent
36d7678ec9
commit
69cea49034
35 changed files with 1952 additions and 227 deletions
18
FILES
18
FILES
|
|
@ -3,6 +3,7 @@ BLURB2
|
|||
BLURB3
|
||||
BLURB4
|
||||
README
|
||||
README.auth
|
||||
FAQ
|
||||
INSTALL
|
||||
INSTALL.alias
|
||||
|
|
@ -40,6 +41,7 @@ TARGETS
|
|||
Makefile
|
||||
BIN.README
|
||||
BIN.Makefile
|
||||
LICENSE.authentication
|
||||
idedit.c
|
||||
conf-break
|
||||
auto_break.h
|
||||
|
|
@ -136,6 +138,8 @@ dnsfq.c
|
|||
dnsip.c
|
||||
dnsmxip.c
|
||||
dnsptr.c
|
||||
dnstxt.c
|
||||
spfquery.c
|
||||
hostname.c
|
||||
ipmeprint.c
|
||||
tcp-env.c
|
||||
|
|
@ -336,13 +340,16 @@ envread.c
|
|||
byte.h
|
||||
byte_chr.c
|
||||
byte_copy.c
|
||||
byte_cspn.c
|
||||
byte_cr.c
|
||||
byte_diff.c
|
||||
byte_rchr.c
|
||||
byte_rcspn.c
|
||||
byte_zero.c
|
||||
str.h
|
||||
str_chr.c
|
||||
str_cpy.c
|
||||
str_cpyb.c
|
||||
str_diff.c
|
||||
str_diffn.c
|
||||
str_len.c
|
||||
|
|
@ -402,6 +409,8 @@ date822fmt.h
|
|||
date822fmt.c
|
||||
dns.h
|
||||
dns.c
|
||||
spf.h
|
||||
spf.c
|
||||
trylsock.c
|
||||
tryrsolv.c
|
||||
ip.h
|
||||
|
|
@ -432,3 +441,12 @@ maildir.c
|
|||
tcp-environ.5
|
||||
constmap.h
|
||||
constmap.c
|
||||
base64.c
|
||||
base64.h
|
||||
case_startb.c
|
||||
global.h
|
||||
hmac_md5.h
|
||||
hmac_md5.c
|
||||
install_authentication.sh
|
||||
md5.h
|
||||
md5c.c
|
||||
|
|
|
|||
27
FILES.auth
27
FILES.auth
|
|
@ -1,27 +0,0 @@
|
|||
The qmail-smtpd Auth patch modifies the following QMAIL 1.03 files:
|
||||
|
||||
= TARGETS
|
||||
= Makefile
|
||||
= qmail-smtpd.c
|
||||
= qmail-smtpd.8
|
||||
= qmail-remote.c
|
||||
= qmail-remote.8
|
||||
= qmail-showctl.c
|
||||
= qmail-control.9
|
||||
|
||||
Added files:
|
||||
|
||||
+ base64.c
|
||||
+ base64.h
|
||||
+ case_startb.c
|
||||
+ hmac_md5.h
|
||||
+ hmac_md5.c
|
||||
+ global.h
|
||||
+ md5.h
|
||||
+ md5c.c
|
||||
|
||||
Informational files:
|
||||
|
||||
% install_auth.sh (Installation shell script)
|
||||
% LICENSE.authentication (some sort of ...)
|
||||
% README.auth
|
||||
197
Makefile
197
Makefile
|
|
@ -140,14 +140,6 @@ base64.o: \
|
|||
compile base64.c base64.h stralloc.h substdio.h str.h
|
||||
./compile base64.c
|
||||
|
||||
md5c.o : \
|
||||
compile md5c.c md5.h
|
||||
./compile md5c.c
|
||||
|
||||
hmac_md5.o : \
|
||||
compile hmac_md5.c hmac_md5.h global.h
|
||||
./compile hmac_md5.c
|
||||
|
||||
binm1: \
|
||||
binm1.sh conf-qmail
|
||||
cat binm1.sh \
|
||||
|
|
@ -215,6 +207,10 @@ byte_cr.o: \
|
|||
compile byte_cr.c byte.h
|
||||
./compile byte_cr.c
|
||||
|
||||
byte_cspn.o: \
|
||||
compile byte_cspn.c byte.h
|
||||
./compile byte_cspn.c
|
||||
|
||||
byte_diff.o: \
|
||||
compile byte_diff.c byte.h
|
||||
./compile byte_diff.c
|
||||
|
|
@ -223,6 +219,10 @@ byte_rchr.o: \
|
|||
compile byte_rchr.c byte.h
|
||||
./compile byte_rchr.c
|
||||
|
||||
byte_rcspn.o: \
|
||||
compile byte_rcspn.c byte.h
|
||||
./compile byte_rcspn.c
|
||||
|
||||
byte_zero.o: \
|
||||
compile byte_zero.c byte.h
|
||||
./compile byte_zero.c
|
||||
|
|
@ -405,84 +405,96 @@ compile trydrent.c direntry.h1 direntry.h2
|
|||
rm -f trydrent.o
|
||||
|
||||
dns.lib: \
|
||||
tryrsolv.c compile load socket.lib dns.o ipalloc.o ip.o stralloc.a \
|
||||
alloc.a error.a fs.a str.a
|
||||
tryrsolv.c compile load socket.lib dns.o ipalloc.o strsalloc.o ip.o \
|
||||
stralloc.a alloc.a error.a fs.a str.a
|
||||
( ( ./compile tryrsolv.c && ./load tryrsolv dns.o \
|
||||
ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \
|
||||
ipalloc.o strsalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \
|
||||
-lresolv `cat socket.lib` ) >/dev/null 2>&1 \
|
||||
&& echo -lresolv || exit 0 ) > dns.lib
|
||||
rm -f tryrsolv.o tryrsolv
|
||||
|
||||
dns.o: \
|
||||
compile dns.c ip.h ipalloc.h ip.h gen_alloc.h fmt.h alloc.h str.h \
|
||||
stralloc.h gen_alloc.h dns.h case.h
|
||||
compile dns.c ip.h ipalloc.h strsalloc.h gen_alloc.h fmt.h alloc.h \
|
||||
str.h stralloc.h dns.h case.h
|
||||
./compile dns.c
|
||||
|
||||
dnscname: \
|
||||
load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
|
||||
load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
./load dnscname dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
|
||||
./load dnscname dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
|
||||
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||
socket.lib`
|
||||
|
||||
dnscname.o: \
|
||||
compile dnscname.c substdio.h subfd.h substdio.h stralloc.h \
|
||||
compile dnscname.c substdio.h subfd.h stralloc.h \
|
||||
gen_alloc.h dns.h dnsdoe.h readwrite.h exit.h
|
||||
./compile dnscname.c
|
||||
|
||||
dnsdoe.o: \
|
||||
compile dnsdoe.c substdio.h subfd.h substdio.h exit.h dns.h dnsdoe.h
|
||||
compile dnsdoe.c substdio.h subfd.h exit.h dns.h dnsdoe.h
|
||||
./compile dnsdoe.c
|
||||
|
||||
dnsfq: \
|
||||
load dnsfq.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
|
||||
load dnsfq.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
./load dnsfq dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
|
||||
./load dnsfq dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
|
||||
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||
socket.lib`
|
||||
|
||||
dnsfq.o: \
|
||||
compile dnsfq.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
|
||||
dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h
|
||||
compile dnsfq.c substdio.h subfd.h stralloc.h gen_alloc.h \
|
||||
dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h exit.h
|
||||
./compile dnsfq.c
|
||||
|
||||
dnsip: \
|
||||
load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
|
||||
load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
./load dnsip dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
|
||||
./load dnsip dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
|
||||
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||
socket.lib`
|
||||
|
||||
dnsip.o: \
|
||||
compile dnsip.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
|
||||
dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h
|
||||
compile dnsip.c substdio.h subfd.h stralloc.h gen_alloc.h \
|
||||
dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h exit.h
|
||||
./compile dnsip.c
|
||||
|
||||
dnsmxip: \
|
||||
load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o now.o stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
./load dnsmxip dns.o dnsdoe.o ip.o ipalloc.o now.o \
|
||||
load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o now.o stralloc.a \
|
||||
alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
./load dnsmxip dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o now.o \
|
||||
stralloc.a alloc.a substdio.a error.a str.a fs.a `cat \
|
||||
dns.lib` `cat socket.lib`
|
||||
|
||||
dnsmxip.o: \
|
||||
compile dnsmxip.c substdio.h subfd.h substdio.h stralloc.h \
|
||||
gen_alloc.h fmt.h dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h \
|
||||
compile dnsmxip.c substdio.h subfd.h stralloc.h \
|
||||
gen_alloc.h fmt.h dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h \
|
||||
now.h datetime.h exit.h
|
||||
./compile dnsmxip.c
|
||||
|
||||
dnsptr: \
|
||||
load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
|
||||
load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
./load dnsptr dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
|
||||
./load dnsptr dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
|
||||
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||
socket.lib`
|
||||
|
||||
dnsptr.o: \
|
||||
compile dnsptr.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
|
||||
compile dnsptr.c substdio.h subfd.h stralloc.h gen_alloc.h \
|
||||
str.h scan.h dns.h dnsdoe.h ip.h exit.h
|
||||
./compile dnsptr.c
|
||||
|
||||
dnstxt: \
|
||||
load dnstxt.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
./load dnstxt dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
|
||||
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||
socket.lib`
|
||||
|
||||
dnstxt.o: \
|
||||
compile dnstxt.c substdio.h subfd.h stralloc.h gen_alloc.h \
|
||||
str.h scan.h dns.h dnsdoe.h ip.h exit.h
|
||||
./compile dnstxt.c
|
||||
|
||||
dot-qmail.0: \
|
||||
dot-qmail.5
|
||||
nroff -man dot-qmail.5 > dot-qmail.0
|
||||
|
|
@ -717,6 +729,10 @@ hier.o: \
|
|||
compile hier.c auto_qmail.h auto_split.h auto_uids.h fmt.h fifo.h
|
||||
./compile hier.c
|
||||
|
||||
hmac_md5.o : \
|
||||
compile hmac_md5.c hmac_md5.h global.h
|
||||
./compile hmac_md5.c
|
||||
|
||||
home: \
|
||||
home.sh conf-qmail
|
||||
cat home.sh \
|
||||
|
|
@ -789,24 +805,24 @@ compile ip.c fmt.h scan.h ip.h
|
|||
./compile ip.c
|
||||
|
||||
ipalloc.o: \
|
||||
compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h ip.h \
|
||||
compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h \
|
||||
gen_alloc.h
|
||||
./compile ipalloc.c
|
||||
|
||||
ipme.o: \
|
||||
compile ipme.c hassalen.h byte.h ip.h ipalloc.h ip.h gen_alloc.h \
|
||||
stralloc.h gen_alloc.h ipme.h ip.h ipalloc.h
|
||||
compile ipme.c hassalen.h byte.h ip.h ipalloc.h strsalloc.h ip.h gen_alloc.h \
|
||||
stralloc.h gen_alloc.h ipme.h ip.h ipalloc.h strsalloc.h
|
||||
./compile ipme.c
|
||||
|
||||
ipmeprint: \
|
||||
load ipmeprint.o ipme.o ip.o ipalloc.o stralloc.a alloc.a substdio.a \
|
||||
error.a str.a fs.a socket.lib
|
||||
./load ipmeprint ipme.o ip.o ipalloc.o stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a `cat socket.lib`
|
||||
load ipmeprint.o ipme.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a socket.lib
|
||||
./load ipmeprint ipme.o ip.o ipalloc.o strsalloc.o stralloc.a \
|
||||
alloc.a substdio.a error.a str.a fs.a `cat socket.lib`
|
||||
|
||||
ipmeprint.o: \
|
||||
compile ipmeprint.c subfd.h substdio.h substdio.h ip.h ipme.h ip.h \
|
||||
ipalloc.h ip.h gen_alloc.h exit.h
|
||||
ipalloc.h strsalloc.h ip.h gen_alloc.h exit.h
|
||||
./compile ipmeprint.c
|
||||
|
||||
it: \
|
||||
|
|
@ -816,11 +832,11 @@ predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \
|
|||
qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \
|
||||
qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \
|
||||
qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \
|
||||
dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \
|
||||
dnsptr dnsip dnsmxip dnsfq dnstxt hostname ipmeprint qreceipt qsmhook \
|
||||
forward preline condredirect bouncesaying except maildirmake \
|
||||
maildir2mbox maildirwatch qail elq pinq idedit install-big install \
|
||||
instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
|
||||
binm3 binm3+df
|
||||
binm3 binm3+df spfquery
|
||||
|
||||
load: \
|
||||
make-load warn-auto.sh systype
|
||||
|
|
@ -953,6 +969,10 @@ mbox.0: \
|
|||
mbox.5
|
||||
nroff -man mbox.5 > mbox.0
|
||||
|
||||
md5c.o : \
|
||||
compile md5c.c md5.h
|
||||
./compile md5c.c
|
||||
|
||||
myctime.o: \
|
||||
compile myctime.c datetime.h fmt.h myctime.h
|
||||
./compile myctime.c
|
||||
|
|
@ -1451,14 +1471,14 @@ auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
|
|||
|
||||
qmail-remote: \
|
||||
load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
|
||||
timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \
|
||||
timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o strsalloc.o ipme.o quote.o \
|
||||
ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \
|
||||
substdio.a error.a str.a fs.a auto_qmail.o \
|
||||
base64.o md5c.o hmac_md5.o \
|
||||
dns.lib socket.lib
|
||||
./load qmail-remote control.o constmap.o timeoutread.o \
|
||||
timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
|
||||
ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
|
||||
ipalloc.o strsalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
|
||||
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
|
||||
base64.o md5c.o hmac_md5.o \
|
||||
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
|
||||
|
|
@ -1470,7 +1490,7 @@ qmail-remote.8
|
|||
qmail-remote.o: \
|
||||
compile qmail-remote.c sig.h stralloc.h gen_alloc.h substdio.h \
|
||||
subfd.h substdio.h scan.h case.h error.h auto_qmail.h control.h dns.h \
|
||||
alloc.h quote.h ip.h ipalloc.h ip.h gen_alloc.h ipme.h ip.h ipalloc.h \
|
||||
alloc.h quote.h ip.h ipalloc.h strsalloc.h ip.h gen_alloc.h ipme.h ip.h ipalloc.h strsalloc.h \
|
||||
gen_alloc.h gen_allocdefs.h str.h now.h datetime.h exit.h constmap.h \
|
||||
tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h
|
||||
./compile qmail-remote.c
|
||||
|
|
@ -1543,21 +1563,21 @@ qmail-showctl.o: \
|
|||
compile qmail-showctl.c substdio.h subfd.h substdio.h exit.h fmt.h \
|
||||
str.h control.h constmap.h stralloc.h gen_alloc.h direntry.h \
|
||||
auto_uids.h auto_qmail.h auto_break.h auto_patrn.h auto_spawn.h \
|
||||
auto_split.h
|
||||
auto_split.h spf.h
|
||||
./compile qmail-showctl.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
|
||||
timeoutwrite.o ip.o ipme.o ipalloc.o strsalloc.o control.o constmap.o \
|
||||
received.o date822fmt.o now.o qmail.o spf.o dns.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 dns.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 \
|
||||
alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \
|
||||
socket.lib`
|
||||
timeoutwrite.o ip.o ipme.o ipalloc.o strsalloc.o control.o \
|
||||
constmap.o received.o date822fmt.o now.o qmail.o spf.o dns.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 \
|
||||
str.a `cat socket.lib` `cat dns.lib`
|
||||
|
||||
qmail-smtpd.0: \
|
||||
qmail-smtpd.8
|
||||
|
|
@ -1566,9 +1586,9 @@ qmail-smtpd.8
|
|||
qmail-smtpd.o: \
|
||||
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 \
|
||||
error.h ipme.h ip.h ipalloc.h strsalloc.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 spf.h base64.h
|
||||
./compile qmail-smtpd.c
|
||||
|
||||
qmail-start: \
|
||||
|
|
@ -1760,6 +1780,12 @@ substdio.h alloc.h auto_qmail.h exit.h env.h str.h
|
|||
setup: \
|
||||
it man
|
||||
./install
|
||||
mv "`head -1 conf-qmail`/bin/qmail-remote" "`head -1 conf-qmail`/bin/qmail-remote-orig"
|
||||
cp ./qmail-remote-dkim "`head -1 conf-qmail`/bin/qmail-remote"
|
||||
## It seems with qmail-remote being a Perl program, it cannot
|
||||
## have the same permissions as qmail-remote-orig. I could
|
||||
## get it work with 0755 and did not investigate further.
|
||||
chmod 0755 "`head -1 conf-qmail`/bin/qmail-remote"
|
||||
|
||||
sgetopt.o: \
|
||||
compile sgetopt.c substdio.h subfd.h substdio.h sgetopt.h subgetopt.h \
|
||||
|
|
@ -1794,7 +1820,7 @@ qmail-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \
|
|||
qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \
|
||||
qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c \
|
||||
qmail-start.c qmail-tcpok.c qmail-tcpto.c spawn.c dnscname.c dnsfq.c \
|
||||
dnsip.c dnsmxip.c dnsptr.c hostname.c ipmeprint.c tcp-env.c \
|
||||
dnsip.c dnsmxip.c dnsptr.c dnstxt.c hostname.c ipmeprint.c tcp-env.c \
|
||||
sendmail.c qreceipt.c qsmhook.c qbiff.c forward.c preline.c predate.c \
|
||||
except.c bouncesaying.c condredirect.c maildirmake.c maildir2mbox.c \
|
||||
maildirwatch.c splogger.c qail.sh elq.sh pinq.sh qmail-upq.sh \
|
||||
|
|
@ -1828,8 +1854,9 @@ uint32.h2 tryulong32.c wait.3 wait.h wait_pid.c wait_nohang.c \
|
|||
trywaitp.c sig.h sig_alarm.c sig_block.c sig_catch.c sig_pause.c \
|
||||
sig_pipe.c sig_child.c sig_term.c sig_hup.c sig_misc.c sig_bug.c \
|
||||
trysgact.c trysgprm.c env.3 env.h env.c envread.c byte.h byte_chr.c \
|
||||
byte_copy.c byte_cr.c byte_diff.c byte_rchr.c byte_zero.c str.h \
|
||||
str_chr.c str_cpy.c str_diff.c str_diffn.c str_len.c str_rchr.c \
|
||||
byte_copy.c byte_cr.c byte_cspn.c byte_diff.c byte_rchr.c byte_rcspn.c \
|
||||
byte_zero.c str.h spf.c spf.h spfquery.c \
|
||||
str_chr.c str_cpy.c str_cpyb.c str_diff.c str_diffn.c str_len.c str_rchr.c \
|
||||
str_start.c lock.h lock_ex.c lock_exnb.c lock_un.c tryflock.c getln.3 \
|
||||
getln.h getln.c getln2.3 getln2.c sgetopt.3 sgetopt.h sgetopt.c \
|
||||
subgetopt.3 subgetopt.h subgetopt.c error.3 error_str.3 error_temp.3 \
|
||||
|
|
@ -1839,7 +1866,7 @@ slurpclose.h slurpclose.c quote.h quote.c hfield.h hfield.c \
|
|||
headerbody.h headerbody.c token822.h token822.c control.h control.c \
|
||||
datetime.3 datetime.h datetime.c datetime_un.c prioq.h prioq.c \
|
||||
date822fmt.h date822fmt.c dns.h dns.c trylsock.c tryrsolv.c ip.h ip.c \
|
||||
ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
|
||||
ipalloc.h strsalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
|
||||
ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \
|
||||
prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \
|
||||
maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c
|
||||
|
|
@ -1912,6 +1939,23 @@ auto_qmail.h auto_uids.h auto_spawn.h
|
|||
./chkspawn
|
||||
./compile spawn.c
|
||||
|
||||
spf.o: \
|
||||
compile spf.c stralloc.h gen_alloc.h alloc.h ipme.h ip.h ipalloc.h \
|
||||
strsalloc.h str.h fmt.h scan.h byte.h now.h case.h
|
||||
./compile spf.c
|
||||
|
||||
spfquery: \
|
||||
load spfquery.o spf.o ip.o ipme.o ipalloc.o strsalloc.o now.o dns.o \
|
||||
datetime.a stralloc.a alloc.a str.a substdio.a error.a fs.a case.a dns.lib
|
||||
./load spfquery spf.o ip.o ipme.o ipalloc.o strsalloc.o \
|
||||
now.o dns.o datetime.a stralloc.a alloc.a str.a substdio.a \
|
||||
case.a error.a fs.a `cat dns.lib` `cat socket.lib`
|
||||
|
||||
spfquery.o: \
|
||||
compile spfquery.c substdio.h subfd.h stralloc.h gen_alloc.h alloc.h \
|
||||
spf.h exit.h
|
||||
./compile spfquery.c
|
||||
|
||||
splogger: \
|
||||
load splogger.o substdio.a error.a str.a fs.a syslog.lib socket.lib
|
||||
./load splogger substdio.a error.a str.a fs.a `cat \
|
||||
|
|
@ -1927,12 +1971,12 @@ scan.h fmt.h
|
|||
./compile splogger.c
|
||||
|
||||
str.a: \
|
||||
makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \
|
||||
str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_diff.o byte_copy.o \
|
||||
byte_cr.o byte_zero.o
|
||||
./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \
|
||||
str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \
|
||||
byte_diff.o byte_copy.o byte_cr.o byte_zero.o
|
||||
makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_cpyb.o str_chr.o \
|
||||
str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_cspn.o byte_rcspn.o \
|
||||
byte_diff.o byte_copy.o byte_cr.o byte_zero.o
|
||||
./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o str_cpyb.o \
|
||||
str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_cspn.o \
|
||||
byte_rcspn.o byte_diff.o byte_copy.o byte_cr.o byte_zero.o
|
||||
|
||||
str_chr.o: \
|
||||
compile str_chr.c str.h
|
||||
|
|
@ -1942,6 +1986,10 @@ str_cpy.o: \
|
|||
compile str_cpy.c str.h
|
||||
./compile str_cpy.c
|
||||
|
||||
str_cpyb.o: \
|
||||
compile str_cpyb.c str.h
|
||||
./compile str_cpyb.c
|
||||
|
||||
str_diff.o: \
|
||||
compile str_diff.c str.h
|
||||
./compile str_diff.c
|
||||
|
|
@ -2021,6 +2069,11 @@ strerr_sys.o: \
|
|||
compile strerr_sys.c error.h strerr.h
|
||||
./compile strerr_sys.c
|
||||
|
||||
strsalloc.o: \
|
||||
compile strsalloc.c alloc.h gen_allocdefs.h stralloc.h strsalloc.h \
|
||||
gen_alloc.h
|
||||
./compile strsalloc.c
|
||||
|
||||
subfderr.o: \
|
||||
compile subfderr.c readwrite.h substdio.h subfd.h substdio.h
|
||||
./compile subfderr.c
|
||||
|
|
@ -2081,11 +2134,11 @@ find-systype trycpp.c
|
|||
|
||||
tcp-env: \
|
||||
load tcp-env.o dns.o remoteinfo.o timeoutread.o timeoutwrite.o \
|
||||
timeoutconn.o ip.o ipalloc.o case.a ndelay.a sig.a env.a getopt.a \
|
||||
stralloc.a alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
timeoutconn.o ip.o ipalloc.o strsalloc.o case.a ndelay.a sig.a env.a \
|
||||
getopt.a stralloc.a alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib
|
||||
./load tcp-env dns.o remoteinfo.o timeoutread.o \
|
||||
timeoutwrite.o timeoutconn.o ip.o ipalloc.o case.a ndelay.a \
|
||||
sig.a env.a getopt.a stralloc.a alloc.a substdio.a error.a \
|
||||
timeoutwrite.o timeoutconn.o ip.o ipalloc.o strsalloc.o case.a \
|
||||
ndelay.a sig.a env.a getopt.a stralloc.a alloc.a substdio.a error.a \
|
||||
str.a fs.a `cat dns.lib` `cat socket.lib`
|
||||
|
||||
tcp-env.0: \
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ Version: Notes: Date:
|
|||
0.7.5 Fixed bug in qmail-remote not respecting
|
||||
announced AUTH types. Tx. Callum Gibson.
|
||||
Added '432' server code evaluation for
|
||||
AUTH password expired in qmail-remote. 23.10.2012
|
||||
AUTH password expired in qmail-remote. 23.10.2012
|
||||
0.7.6 Fixed order of SMTP commands (tx roberto).
|
||||
02.02.2013
|
||||
0.8.0 Added authentication by recipient domain
|
||||
|
|
|
|||
10
TARGETS
10
TARGETS
|
|
@ -101,11 +101,14 @@ str_len.o
|
|||
str_diff.o
|
||||
str_diffn.o
|
||||
str_cpy.o
|
||||
str_cpyb.o
|
||||
str_chr.o
|
||||
str_rchr.o
|
||||
str_start.o
|
||||
byte_chr.o
|
||||
byte_rchr.o
|
||||
byte_cspn.o
|
||||
byte_rcspn.o
|
||||
byte_diff.o
|
||||
byte_copy.o
|
||||
byte_cr.o
|
||||
|
|
@ -172,8 +175,10 @@ timeoutwrite.o
|
|||
timeoutconn.o
|
||||
tcpto.o
|
||||
dns.o
|
||||
spf.o
|
||||
ip.o
|
||||
ipalloc.o
|
||||
strsalloc.o
|
||||
hassalen.h
|
||||
ipme.o
|
||||
ndelay.o
|
||||
|
|
@ -215,6 +220,9 @@ qmail-inject.o
|
|||
headerbody.o
|
||||
hfield.o
|
||||
token822.o
|
||||
spf.o
|
||||
spfquery.o
|
||||
spfquery
|
||||
qmail-inject
|
||||
predate.o
|
||||
predate
|
||||
|
|
@ -273,6 +281,8 @@ dnsip.o
|
|||
dnsip
|
||||
dnsmxip.o
|
||||
dnsmxip
|
||||
dnstxt.o
|
||||
dnstxt
|
||||
dnsfq.o
|
||||
dnsfq
|
||||
hostname.o
|
||||
|
|
|
|||
2
byte.h
2
byte.h
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
extern unsigned int byte_chr();
|
||||
extern unsigned int byte_rchr();
|
||||
extern unsigned int byte_cspn();
|
||||
extern unsigned int byte_rcspn();
|
||||
extern void byte_copy();
|
||||
extern void byte_copyr();
|
||||
extern int byte_diff();
|
||||
|
|
|
|||
11
byte_cspn.c
Normal file
11
byte_cspn.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "byte.h"
|
||||
|
||||
unsigned int byte_cspn(s,n,c)
|
||||
register char *s;
|
||||
register unsigned int n;
|
||||
register char *c;
|
||||
{
|
||||
while(*c)
|
||||
n = byte_chr(s,n,*c++);
|
||||
return n;
|
||||
}
|
||||
17
byte_rcspn.c
Normal file
17
byte_rcspn.c
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include "byte.h"
|
||||
|
||||
unsigned int byte_rcspn(s,n,c)
|
||||
register char *s;
|
||||
register unsigned int n;
|
||||
register char *c;
|
||||
{
|
||||
unsigned int ret,pos,i;
|
||||
|
||||
for(ret = n,pos = 0;*c;++c) {
|
||||
i = byte_rchr(s + pos,n - pos,*c) + pos;
|
||||
if (i < n) ret = pos = i;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
132
dns.c
132
dns.c
|
|
@ -9,6 +9,7 @@ extern int res_query();
|
|||
extern int res_search();
|
||||
#include "ip.h"
|
||||
#include "ipalloc.h"
|
||||
#include "strsalloc.h"
|
||||
#include "fmt.h"
|
||||
#include "alloc.h"
|
||||
#include "str.h"
|
||||
|
|
@ -27,6 +28,7 @@ static unsigned char *responsepos;
|
|||
static int numanswers;
|
||||
static char name[MAXDNAME];
|
||||
static struct ip_address ip;
|
||||
static stralloc txt = {0};
|
||||
unsigned short pref;
|
||||
|
||||
static stralloc glue = {0};
|
||||
|
|
@ -177,6 +179,49 @@ int wanttype;
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int findtxt(wanttype)
|
||||
int wanttype;
|
||||
{
|
||||
unsigned short rrtype;
|
||||
unsigned short rrdlen;
|
||||
int i;
|
||||
|
||||
if (numanswers <= 0) return 2;
|
||||
--numanswers;
|
||||
if (responsepos == responseend) return DNS_SOFT;
|
||||
|
||||
i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
|
||||
if (i < 0) return DNS_SOFT;
|
||||
responsepos += i;
|
||||
|
||||
i = responseend - responsepos;
|
||||
if (i < 4 + 3 * 2) return DNS_SOFT;
|
||||
|
||||
rrtype = getshort(responsepos);
|
||||
rrdlen = getshort(responsepos + 8);
|
||||
responsepos += 10;
|
||||
|
||||
if (rrtype == wanttype)
|
||||
{
|
||||
unsigned short txtpos;
|
||||
unsigned char txtlen;
|
||||
|
||||
txt.len = 0;
|
||||
for (txtpos = 0;txtpos < rrdlen;txtpos += txtlen)
|
||||
{
|
||||
txtlen = responsepos[txtpos++];
|
||||
if (txtlen > rrdlen-txtpos) txtlen = rrdlen-txtpos;
|
||||
if (!stralloc_catb(&txt,&responsepos[txtpos],txtlen)) return DNS_MEM;
|
||||
}
|
||||
|
||||
responsepos += rrdlen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
responsepos += rrdlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dns_init(flagsearch)
|
||||
int flagsearch;
|
||||
{
|
||||
|
|
@ -194,7 +239,7 @@ stralloc *sa;
|
|||
if (!sa->len) return loop;
|
||||
if (sa->s[sa->len - 1] == ']') return loop;
|
||||
if (sa->s[sa->len - 1] == '.') { --sa->len; continue; }
|
||||
switch(resolve(sa,T_ANY))
|
||||
switch(resolve(sa,T_CNAME))
|
||||
{
|
||||
case DNS_MEM: return DNS_MEM;
|
||||
case DNS_SOFT: return DNS_SOFT;
|
||||
|
|
@ -235,15 +280,18 @@ struct ip_address *ip;
|
|||
return len;
|
||||
}
|
||||
|
||||
int dns_ptr(sa,ip)
|
||||
stralloc *sa;
|
||||
static int dns_ptrplus(ssa,ip)
|
||||
strsalloc *ssa;
|
||||
struct ip_address *ip;
|
||||
{
|
||||
stralloc sa = {0};
|
||||
int r;
|
||||
|
||||
if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM;
|
||||
sa->len = iaafmt(sa->s,ip);
|
||||
switch(resolve(sa,T_PTR))
|
||||
if (!stralloc_ready(&sa,iaafmt((char *) 0,ip))) return DNS_MEM;
|
||||
sa.len = iaafmt(sa.s,ip);
|
||||
r = resolve(&sa,T_PTR);
|
||||
alloc_free(sa.s);
|
||||
switch(r)
|
||||
{
|
||||
case DNS_MEM: return DNS_MEM;
|
||||
case DNS_SOFT: return DNS_SOFT;
|
||||
|
|
@ -254,13 +302,35 @@ struct ip_address *ip;
|
|||
if (r == DNS_SOFT) return DNS_SOFT;
|
||||
if (r == 1)
|
||||
{
|
||||
if (!stralloc_copys(sa,name)) return DNS_MEM;
|
||||
return 0;
|
||||
stralloc sa2 = {0};
|
||||
if (!stralloc_copys(&sa2,name)) return DNS_MEM;
|
||||
if (!strsalloc_append(ssa,&sa2)) return DNS_MEM;
|
||||
}
|
||||
}
|
||||
if (ssa->len) return 0;
|
||||
return DNS_HARD;
|
||||
}
|
||||
|
||||
int dns_ptr(ssa,ip)
|
||||
strsalloc *ssa;
|
||||
struct ip_address *ip;
|
||||
{
|
||||
int r;
|
||||
int j;
|
||||
|
||||
if (!strsalloc_readyplus(ssa,0)) return DNS_MEM;
|
||||
ssa->len = 0;
|
||||
r = dns_ptrplus(ssa,ip);
|
||||
if (r < 0)
|
||||
{
|
||||
for (j = 0;j < ssa->len;++j)
|
||||
alloc_free(ssa->sa[j].s);
|
||||
ssa->len = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int dns_ipplus(ia,sa,pref)
|
||||
ipalloc *ia;
|
||||
stralloc *sa;
|
||||
|
|
@ -396,3 +466,49 @@ unsigned long random;
|
|||
alloc_free(mx);
|
||||
return flagsoft;
|
||||
}
|
||||
|
||||
|
||||
static int dns_txtplus(ssa,sa)
|
||||
strsalloc *ssa;
|
||||
stralloc *sa;
|
||||
{
|
||||
int r;
|
||||
|
||||
switch(resolve(sa,T_TXT))
|
||||
{
|
||||
case DNS_MEM: return DNS_MEM;
|
||||
case DNS_SOFT: return DNS_SOFT;
|
||||
case DNS_HARD: return DNS_HARD;
|
||||
}
|
||||
while ((r = findtxt(T_TXT)) != 2)
|
||||
{
|
||||
if (r == DNS_SOFT) return DNS_SOFT;
|
||||
if (r == 1)
|
||||
{
|
||||
stralloc sa = {0};
|
||||
if (!stralloc_copy(&sa,&txt)) return DNS_MEM;
|
||||
if (!strsalloc_append(ssa,&sa)) return DNS_MEM;
|
||||
}
|
||||
}
|
||||
if (ssa->len) return 0;
|
||||
return DNS_HARD;
|
||||
}
|
||||
|
||||
int dns_txt(ssa,sa)
|
||||
strsalloc *ssa;
|
||||
stralloc *sa;
|
||||
{
|
||||
int r;
|
||||
int j;
|
||||
|
||||
if (!strsalloc_readyplus(ssa,0)) return DNS_MEM;
|
||||
ssa->len = 0;
|
||||
r = dns_txtplus(ssa,sa);
|
||||
if (r < 0)
|
||||
{
|
||||
for (j = 0;j < ssa->len;++j)
|
||||
alloc_free(ssa->sa[j].s);
|
||||
ssa->len = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
|
|||
1
dns.h
1
dns.h
|
|
@ -10,5 +10,6 @@ int dns_cname();
|
|||
int dns_mxip();
|
||||
int dns_ip();
|
||||
int dns_ptr();
|
||||
int dns_txt();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
13
dnsfq.c
13
dnsfq.c
|
|
@ -5,15 +5,19 @@
|
|||
#include "dnsdoe.h"
|
||||
#include "ip.h"
|
||||
#include "ipalloc.h"
|
||||
#include "strsalloc.h"
|
||||
#include "exit.h"
|
||||
|
||||
stralloc sa = {0};
|
||||
strsalloc ssa = {0};
|
||||
ipalloc ia = {0};
|
||||
|
||||
void main(argc,argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int j;
|
||||
|
||||
if (!argv[1]) _exit(100);
|
||||
|
||||
if (!stralloc_copys(&sa,argv[1]))
|
||||
|
|
@ -25,8 +29,11 @@ char **argv;
|
|||
{
|
||||
substdio_putsflush(subfderr,"no IP addresses\n"); _exit(100);
|
||||
}
|
||||
dnsdoe(dns_ptr(&sa,&ia.ix[0].ip));
|
||||
substdio_putflush(subfdout,sa.s,sa.len);
|
||||
substdio_putsflush(subfdout,"\n");
|
||||
dnsdoe(dns_ptr(&ssa,&ia.ix[0].ip));
|
||||
for(j = 0;j < ssa.len;++j)
|
||||
{
|
||||
substdio_putflush(subfdout,ssa.sa[j].s,ssa.sa[j].len);
|
||||
substdio_putsflush(subfdout,"\n");
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
|
|
|
|||
14
dnsptr.c
14
dnsptr.c
|
|
@ -6,22 +6,28 @@
|
|||
#include "dns.h"
|
||||
#include "dnsdoe.h"
|
||||
#include "ip.h"
|
||||
#include "strsalloc.h"
|
||||
#include "exit.h"
|
||||
|
||||
stralloc sa = {0};
|
||||
strsalloc ssa = {0};
|
||||
struct ip_address ip;
|
||||
|
||||
void main(argc,argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int j;
|
||||
|
||||
if (!argv[1]) _exit(100);
|
||||
|
||||
ip_scan(argv[1],&ip);
|
||||
|
||||
dns_init(0);
|
||||
dnsdoe(dns_ptr(&sa,&ip));
|
||||
substdio_putflush(subfdout,sa.s,sa.len);
|
||||
substdio_putsflush(subfdout,"\n");
|
||||
dnsdoe(dns_ptr(&ssa,&ip));
|
||||
for(j = 0;j < ssa.len;++j)
|
||||
{
|
||||
substdio_putflush(subfdout,ssa.sa[j].s,ssa.sa[j].len);
|
||||
substdio_putsflush(subfdout,"\n");
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
|
|
|
|||
32
dnstxt.c
Normal file
32
dnstxt.c
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include "substdio.h"
|
||||
#include "subfd.h"
|
||||
#include "stralloc.h"
|
||||
#include "str.h"
|
||||
#include "scan.h"
|
||||
#include "dns.h"
|
||||
#include "dnsdoe.h"
|
||||
#include "strsalloc.h"
|
||||
#include "exit.h"
|
||||
|
||||
strsalloc ssa = {0};
|
||||
stralloc sa = {0};
|
||||
|
||||
void main(argc,argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int j;
|
||||
|
||||
if (!argv[1]) _exit(100);
|
||||
|
||||
if (!stralloc_copys(&sa, argv[1]))
|
||||
{ substdio_putsflush(subfderr,"out of memory\n"); _exit(111); }
|
||||
dns_init(0);
|
||||
dnsdoe(dns_txt(&ssa,&sa));
|
||||
for (j = 0;j < ssa.len;++j)
|
||||
{
|
||||
substdio_put(subfdout,ssa.sa[j].s,ssa.sa[j].len);
|
||||
substdio_putsflush(subfdout,"\n");
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
4
hier.c
4
hier.c
|
|
@ -104,7 +104,7 @@ void hier()
|
|||
c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700);
|
||||
c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711);
|
||||
c(auto_qmail,"bin","qmail-local",auto_uido,auto_gidq,0711);
|
||||
c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0711);
|
||||
c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0755);
|
||||
c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711);
|
||||
c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
|
||||
c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
|
||||
|
|
@ -131,7 +131,7 @@ void hier()
|
|||
c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755);
|
||||
c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755);
|
||||
c(auto_qmail,"bin","qsmhook",auto_uido,auto_gidq,0755);
|
||||
c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755);
|
||||
/* c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755); */
|
||||
c(auto_qmail,"bin","forward",auto_uido,auto_gidq,0755);
|
||||
c(auto_qmail,"bin","preline",auto_uido,auto_gidq,0755);
|
||||
c(auto_qmail,"bin","condredirect",auto_uido,auto_gidq,0755);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ control default used by
|
|||
.I rcpthosts \fR(none) \fRqmail-smtpd
|
||||
.I smtpgreeting \fIme \fRqmail-smtpd
|
||||
.I smtproutes \fR(none) \fRqmail-remote
|
||||
.I spfbehavior \fR0 \fRqmail-smtpd
|
||||
.I spfexp \fR(default) \fRqmail-smtpd
|
||||
.I spfguess \fR(none) \fRqmail-smtpd
|
||||
.I spfrules \fR(none) \fRqmail-smtpd
|
||||
.I timeoutconnect \fR60 \fRqmail-remote
|
||||
.I timeoutremote \fR1200 \fRqmail-remote
|
||||
.I timeoutsmtpd \fR1200 \fRqmail-smtpd
|
||||
|
|
|
|||
308
qmail-remote-dkim
Executable file
308
qmail-remote-dkim
Executable file
|
|
@ -0,0 +1,308 @@
|
|||
#!/usr/local/bin/perl
|
||||
#
|
||||
# Copyright (C) 2007 Manuel Mausz (manuel@mausz.at)
|
||||
#
|
||||
# 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.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
our $VERSION = '0.3';
|
||||
|
||||
use Mail::DKIM 0.29;
|
||||
use Mail::DKIM::Signer;
|
||||
|
||||
# enable support for "pretty" signatures, if available
|
||||
eval 'require Mail::DKIM::TextWrap';
|
||||
|
||||
=head
|
||||
config file structure
|
||||
- missing settings will be merged from the global-node
|
||||
- domain-entry will also match its subdomains
|
||||
- create empty domain-node to omit signing (or specify "none" as id)
|
||||
|
||||
<dkimsign>
|
||||
<!-- per default sign all mails using dkim -->
|
||||
<global algorithm="rsa-sha256" domain="/var/qmail/control/me" keyfile="/var/qmail/control/dkim/global.key" method="simple" selector="beta">
|
||||
<types id="dkim" />
|
||||
</global>
|
||||
|
||||
<!-- use dkim + domainkey for example.com -->
|
||||
<example.com selector="beta2">
|
||||
<types id="dkim" />
|
||||
<types id="domainkey" method="nofws" />
|
||||
</example.com>
|
||||
|
||||
<!-- no signing for example2.com -->
|
||||
<example2.com />
|
||||
</dkimsign>
|
||||
=cut
|
||||
|
||||
my $configfile = undef;
|
||||
$configfile = '/var/qmail/control/dkim/signconf.xml';
|
||||
my $debugfile = undef;
|
||||
#$debugfile = '/tmp/dkim.debug';
|
||||
my $qremote = '/var/qmail/bin/qmail-remote-orig';
|
||||
my $rcpthosts = '/var/qmail/control/rcpthosts';
|
||||
my $binary = 0;
|
||||
our $config;
|
||||
$config->{'global'} = {
|
||||
types => { dkim => {} },
|
||||
keyfile => '/var/qmail/control/dkim/global.key',
|
||||
algorithm => 'rsa-sha256',
|
||||
method => 'simple',
|
||||
selector => 'beta',
|
||||
# either undefined (=sender), string or file (first line of file will be used)
|
||||
#domain => '/var/qmail/control/me'
|
||||
};
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# read config file. safely
|
||||
if (defined($configfile) && -r $configfile)
|
||||
{
|
||||
eval 'use XML::Simple';
|
||||
if (!$@)
|
||||
{
|
||||
my $xmlconf;
|
||||
eval { $xmlconf = XMLin($configfile, ForceArray => ['types'], KeyAttr => ['id']); };
|
||||
qexit_deferral('Unable to read config file: ', $@)
|
||||
if ($@);
|
||||
ConfigMerge::merge($config, $xmlconf);
|
||||
}
|
||||
}
|
||||
|
||||
# open debug file
|
||||
my $debugfh = undef;
|
||||
if (defined($debugfile))
|
||||
{
|
||||
open($debugfh, '>', $debugfile)
|
||||
or qexit_deferral('Unable to open ', $debugfile, ' to writing: ', $!);
|
||||
}
|
||||
|
||||
# generate signatures
|
||||
my $dkim;
|
||||
my $mailbuf = '';
|
||||
eval
|
||||
{
|
||||
my $conf = $config->{'global'};
|
||||
$dkim = Mail::DKIM::Signer->new(
|
||||
Policy => 'MySignerPolicy',
|
||||
Debug_Canonicalization => $debugfh
|
||||
);
|
||||
|
||||
if ($binary)
|
||||
{
|
||||
binmode STDIN;
|
||||
}
|
||||
|
||||
while (<STDIN>)
|
||||
{
|
||||
$mailbuf .= $_;
|
||||
unless ($binary)
|
||||
{
|
||||
chomp $_;
|
||||
s/\015?$/\015\012/s;
|
||||
}
|
||||
$dkim->PRINT($_);
|
||||
}
|
||||
$dkim->CLOSE();
|
||||
};
|
||||
qexit_deferral('Error while signing: ', $@)
|
||||
if ($@);
|
||||
|
||||
# close debug file
|
||||
close($debugfh)
|
||||
if (defined($debugfh));
|
||||
|
||||
# execute qmail-remote
|
||||
unshift(@ARGV, $qremote);
|
||||
open(QR, '|-') || exec { $ARGV[0] } @ARGV
|
||||
or qexit_deferral('Unable to run qmail-remote: ', $!);
|
||||
foreach my $dkim_signature ($dkim->signatures)
|
||||
{
|
||||
my $sig = $dkim_signature->as_string;
|
||||
$sig =~ s/\015\012\t/\012\t/g;
|
||||
print QR $sig."\012";
|
||||
}
|
||||
print QR $mailbuf;
|
||||
close(QR);
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
sub qexit
|
||||
{
|
||||
print @_, "\0";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub qexit_deferral
|
||||
{
|
||||
return qexit('Z', @_);
|
||||
}
|
||||
|
||||
sub qexit_failure
|
||||
{
|
||||
return qexit('D', @_);
|
||||
}
|
||||
|
||||
sub qexit_success
|
||||
{
|
||||
return qexit('K', @_);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
package ConfigMerge;
|
||||
|
||||
# merge config hashes. arrays and scalars will be copied.
|
||||
sub merge
|
||||
{
|
||||
my ($left, $right) = @_;
|
||||
foreach my $rkey (keys(%$right))
|
||||
{
|
||||
my $rtype = ref($right->{$rkey}) eq 'HASH' ? 'HASH'
|
||||
: ref($right->{$rkey}) eq 'ARRAY' ? 'ARRAY'
|
||||
: defined($right->{$rkey}) ? 'SCALAR'
|
||||
: '';
|
||||
my $ltype = ref($left->{$rkey}) eq 'HASH' ? 'HASH'
|
||||
: ref($left->{$rkey}) eq 'ARRAY' ? 'ARRAY'
|
||||
: defined($left->{$rkey}) ? 'SCALAR'
|
||||
: '';
|
||||
if ($rtype ne 'HASH' || $ltype ne 'HASH')
|
||||
{
|
||||
$left->{$rkey} = $right->{$rkey};
|
||||
}
|
||||
else
|
||||
{
|
||||
merge($left->{$rkey}, $right->{$rkey});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
package MySignerPolicy;
|
||||
use Mail::DKIM::SignerPolicy;
|
||||
use base 'Mail::DKIM::SignerPolicy';
|
||||
use Mail::DKIM::Signature;
|
||||
use Mail::DKIM::DkSignature;
|
||||
use Carp;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub apply
|
||||
{
|
||||
my ($self, $signer) = @_;
|
||||
my $domain = undef;
|
||||
$domain = lc($signer->message_sender->host)
|
||||
if (defined($signer) && defined($signer->message_sender)
|
||||
&& defined($signer->message_sender->host));
|
||||
my $sender = $domain;
|
||||
|
||||
# merge configs
|
||||
while($domain)
|
||||
{
|
||||
if (defined($config->{$domain}))
|
||||
{
|
||||
$config->{'global'}->{'types'} = undef;
|
||||
ConfigMerge::merge($config->{'global'}, $config->{$domain});
|
||||
last;
|
||||
}
|
||||
(undef, $domain) = split(/\./, $domain, 2);
|
||||
}
|
||||
|
||||
my $conf = $config->{'global'};
|
||||
return 0
|
||||
if (!defined($conf->{'types'}) || defined($conf->{'types'}->{'none'}));
|
||||
|
||||
# set key file
|
||||
$signer->key_file($conf->{'keyfile'});
|
||||
|
||||
# parse (signature) domain
|
||||
if (!defined($conf->{'domain'}) || $conf->{'domain'} eq 'sender')
|
||||
{
|
||||
return 0
|
||||
if (!defined($sender));
|
||||
|
||||
$conf->{'domain'} = undef;
|
||||
open(FH, '<', $rcpthosts)
|
||||
or croak('Unable to open rcpthosts: '.$!);
|
||||
while (my $row = <FH>)
|
||||
{
|
||||
chomp($row);
|
||||
if ($row eq $sender)
|
||||
{
|
||||
$conf->{'domain'} = $sender;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close(FH);
|
||||
return 0
|
||||
if (!defined($conf->{'domain'}));
|
||||
}
|
||||
elsif (substr($conf->{'domain'}, 0, 1) eq '/')
|
||||
{
|
||||
open(FH, '<', $conf->{'domain'})
|
||||
or croak('Unable to open domain-file: '.$!);
|
||||
my $newdom = (split(/ /, <FH>))[0];
|
||||
close(FH);
|
||||
croak("Unable to read domain-file. Maybe empty file.")
|
||||
if (!$newdom);
|
||||
chomp($newdom);
|
||||
$conf->{'domain'} = $newdom;
|
||||
}
|
||||
|
||||
# generate signatures
|
||||
my $sigdone = 0;
|
||||
foreach my $type (keys(%{$conf->{'types'}}))
|
||||
{
|
||||
my $sigconf = $conf->{'types'}->{$type};
|
||||
|
||||
if ($type eq 'dkim')
|
||||
{
|
||||
$signer->add_signature(
|
||||
new Mail::DKIM::Signature(
|
||||
Algorithm => $sigconf->{'algorithm'} || $conf->{'algorithm'} || $signer->algorithm,
|
||||
Method => $sigconf->{'method'} || $conf->{'method'} || $signer->method,
|
||||
Headers => $sigconf->{'headers'} || $conf->{'headers'} || $signer->headers,
|
||||
Domain => $sigconf->{'domain'} || $conf->{'domain'} || $signer->domain,
|
||||
Selector => $sigconf->{'selector'} || $conf->{'selector'} || $signer->selector,
|
||||
Query => $sigconf->{'query'} || $conf->{'query'},
|
||||
Identity => $sigconf->{'identity'} || $conf->{'identity'},
|
||||
Expiration => $sigconf->{'expiration'} || $conf->{'expiration'}
|
||||
)
|
||||
);
|
||||
$sigdone = 1;
|
||||
}
|
||||
elsif ($type eq 'domainkey')
|
||||
{
|
||||
$signer->add_signature(
|
||||
new Mail::DKIM::DkSignature(
|
||||
Algorithm => 'rsa-sha1', # only rsa-sha1 supported
|
||||
Method => $sigconf->{'method'} || $conf->{'method'} || $signer->method,
|
||||
Headers => $sigconf->{'selector'} || $conf->{'headers'} || $signer->headers,
|
||||
Domain => $sigconf->{'domain'} || $conf->{'domain'} || $signer->domain,
|
||||
Selector => $sigconf->{'selector'} || $conf->{'selector'} || $signer->selector,
|
||||
Query => $sigconf->{'query'} || $conf->{'query'}
|
||||
)
|
||||
);
|
||||
$sigdone = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $sigdone;
|
||||
}
|
||||
|
|
@ -53,7 +53,6 @@ does not take options
|
|||
and does not follow the
|
||||
.B getopt
|
||||
standard.
|
||||
|
||||
.SH TRANSPARENCY
|
||||
End-of-file in SMTP is encoded as dot CR LF.
|
||||
A dot at the beginning of a line is encoded as dot dot.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "auto_patrn.h"
|
||||
#include "auto_spawn.h"
|
||||
#include "auto_split.h"
|
||||
#include "spf.h"
|
||||
|
||||
stralloc me = {0};
|
||||
int meok;
|
||||
|
|
@ -258,6 +259,10 @@ void main()
|
|||
|
||||
do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 ");
|
||||
do_lst("smtproutes","No artificial SMTP routes.","SMTP route: ","");
|
||||
do_int("spfbehavior","0","The SPF behavior is ","");
|
||||
do_str("spfexp",0,SPF_DEFEXP,"The SPF default explanation is: 550 ");
|
||||
do_str("spfguess",0,"","The guess SPF rules are: ");
|
||||
do_str("spfrules",0,"","The local SPF rules are: ");
|
||||
do_int("timeoutconnect","60","SMTP client connection timeout is "," seconds");
|
||||
do_int("timeoutremote","1200","SMTP client data timeout is "," seconds");
|
||||
do_int("timeoutsmtpd","1200","SMTP server data timeout is "," seconds");
|
||||
|
|
@ -292,6 +297,10 @@ void main()
|
|||
if (str_equal(d->d_name,"rcpthosts")) continue;
|
||||
if (str_equal(d->d_name,"smtpgreeting")) continue;
|
||||
if (str_equal(d->d_name,"smtproutes")) continue;
|
||||
if (str_equal(d->d_name,"spfbehavior")) continue;
|
||||
if (str_equal(d->d_name,"spfexp")) continue;
|
||||
if (str_equal(d->d_name,"spfguess")) continue;
|
||||
if (str_equal(d->d_name,"spfrules")) continue;
|
||||
if (str_equal(d->d_name,"timeoutconnect")) continue;
|
||||
if (str_equal(d->d_name,"timeoutremote")) continue;
|
||||
if (str_equal(d->d_name,"timeoutsmtpd")) continue;
|
||||
|
|
|
|||
|
|
@ -253,6 +253,42 @@ connections.
|
|||
|
||||
Note: The use of 'cram' requires a CRAM-MD5 enabled PAM.
|
||||
|
||||
.TP 5
|
||||
.I spfbehavior
|
||||
Set to a value between 1 and 6 to enable SPF checks; 0 to disable.
|
||||
1 selects 'annotate-only' mode, where
|
||||
.B qmail-smtpd
|
||||
will annotate incoming email with
|
||||
.B Received-SPF
|
||||
fields, but will not reject any messages. 2 will produce temporary
|
||||
failures on DNS lookup problems so you can make sure you always have
|
||||
meaningful Received-SPF headers. 3 selects 'reject' mode,
|
||||
where incoming mail will be rejected if the SPF record says 'fail'. 4
|
||||
selects a more stricter rejection mode, which is like 'reject' mode,
|
||||
except that incoming mail will also be rejected when the SPF record
|
||||
says 'softfail'. 5 will also reject when the SPF record says 'neutral',
|
||||
and 6 if no SPF records are available at all (or a syntax error was
|
||||
encountered). The contents of this file are overridden by the value of
|
||||
the
|
||||
.B SPFBEHAVIOR
|
||||
environment variable, if set.
|
||||
Default: 0.
|
||||
.TP 5
|
||||
.I spfexp
|
||||
You can add a line with a an SPF explanation that will be shown to the
|
||||
sender in case of a reject. It will override the default one. You can
|
||||
use SPF macro expansion.
|
||||
.TP 5
|
||||
.I spfguess
|
||||
You can add a line with SPF rules that will be checked if a sender
|
||||
domain doesn't have a SPF record. The local rules will also be used
|
||||
in this case.
|
||||
.TP 5
|
||||
.I spfrules
|
||||
You can add a line with SPF rules that will be checked before other SPF
|
||||
rules would fail. This can be used to always allow certain machines to
|
||||
send certain mails.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
tcp-env(1),
|
||||
tcp-environ(5),
|
||||
|
|
|
|||
111
qmail-smtpd.c
111
qmail-smtpd.c
|
|
@ -24,12 +24,13 @@
|
|||
#include "timeoutwrite.h"
|
||||
#include "commands.h"
|
||||
#include "wait.h"
|
||||
#include "spf.h"
|
||||
|
||||
#define AUTHSLEEP 5
|
||||
|
||||
#define MAXHOPS 100
|
||||
unsigned int databytes = 0;
|
||||
int timeout = 1200;
|
||||
unsigned int spfbehavior = 0;
|
||||
|
||||
int safewrite(fd,buf,len) int fd; char *buf; int len;
|
||||
{
|
||||
|
|
@ -50,7 +51,7 @@ void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
|
|||
void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
|
||||
void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
|
||||
void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
|
||||
void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
|
||||
void straynewline() { out("451 See https://cr.yp.to/docs/smtplf.html.\r\n"); flush(); _exit(1); }
|
||||
|
||||
void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
|
||||
void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
|
||||
|
|
@ -76,6 +77,9 @@ void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); }
|
|||
void err_submission() { out("530 Authorization required (#5.7.1) \r\n"); }
|
||||
|
||||
stralloc greeting = {0};
|
||||
stralloc spflocal = {0};
|
||||
stralloc spfguess = {0};
|
||||
stralloc spfexp = {0};
|
||||
|
||||
void smtp_greet(code) char *code;
|
||||
{
|
||||
|
|
@ -84,7 +88,7 @@ void smtp_greet(code) char *code;
|
|||
}
|
||||
void smtp_help(arg) char *arg;
|
||||
{
|
||||
out("214 netqmail home page: http://qmail.org/netqmail\r\n");
|
||||
out("214 Omg, you didn't take ``SMTP 101'' in college.\r\n");
|
||||
}
|
||||
void smtp_quit(arg) char *arg;
|
||||
{
|
||||
|
|
@ -128,6 +132,7 @@ void setup()
|
|||
if (liphostok == -1) die_control();
|
||||
if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
|
||||
if (timeout <= 0) timeout = 1;
|
||||
|
||||
if (rcpthosts_init() == -1) die_control();
|
||||
|
||||
bmfok = control_readfile(&bmf,"control/badmailfrom",0);
|
||||
|
|
@ -141,6 +146,19 @@ void setup()
|
|||
if (!(databytes + 1)) --databytes;
|
||||
|
||||
protocol = "SMTP";
|
||||
if (control_readint(&spfbehavior,"control/spfbehavior") == -1)
|
||||
die_control();
|
||||
x = env_get("SPFBEHAVIOR");
|
||||
if (x) { scan_ulong(x,&u); spfbehavior = u; }
|
||||
|
||||
if (control_readline(&spflocal,"control/spfrules") == -1) die_control();
|
||||
if (spflocal.len && !stralloc_0(&spflocal)) die_nomem();
|
||||
if (control_readline(&spfguess,"control/spfguess") == -1) die_control();
|
||||
if (spfguess.len && !stralloc_0(&spfguess)) die_nomem();
|
||||
if (control_rldef(&spfexp,"control/spfexp",0,SPF_DEFEXP) == -1)
|
||||
die_control();
|
||||
if (!stralloc_0(&spfexp)) die_nomem();
|
||||
|
||||
remoteip = env_get("TCPREMOTEIP");
|
||||
if (!remoteip) remoteip = "unknown";
|
||||
local = env_get("TCPLOCALHOST");
|
||||
|
|
@ -166,6 +184,7 @@ void setup()
|
|||
dohelo(remotehost);
|
||||
}
|
||||
|
||||
|
||||
stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
|
||||
|
||||
int addrparse(arg)
|
||||
|
|
@ -247,11 +266,13 @@ int addrallowed()
|
|||
return r;
|
||||
}
|
||||
|
||||
char *auth;
|
||||
|
||||
int seenauth = 0;
|
||||
int seenmail = 0;
|
||||
int flagbarf; /* defined if seenmail */
|
||||
int flagsize;
|
||||
int flagbarfspf;
|
||||
stralloc spfbarfmsg = {0};
|
||||
stralloc mailfrom = {0};
|
||||
stralloc rcptto = {0};
|
||||
stralloc fuser = {0};
|
||||
|
|
@ -323,8 +344,7 @@ void smtp_ehlo(arg) char *arg;
|
|||
{
|
||||
char size[FMT_ULONG];
|
||||
size[fmt_ulong(size,(unsigned int) databytes)] = 0;
|
||||
smtp_greet("250-");
|
||||
out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
|
||||
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");
|
||||
if (smtpauth == 3 || smtpauth == 13) out("250-AUTH LOGIN PLAIN CRAM-MD5\r\n");
|
||||
|
|
@ -337,25 +357,84 @@ void smtp_rset(arg) char *arg;
|
|||
mailfrom.len = 0; rcptto.len = 0;
|
||||
out("250 flushed\r\n");
|
||||
}
|
||||
|
||||
void smtp_mail(arg) char *arg;
|
||||
{
|
||||
int r;
|
||||
if (smtpauth)
|
||||
if (smtpauth > 10 && !seenauth) { err_submission(); return; }
|
||||
|
||||
if (!addrparse(arg)) { err_syntax(); return; }
|
||||
flagsize = 0;
|
||||
mailfrom_parms(arg);
|
||||
if (flagsize) { err_size(); return; }
|
||||
flagbarf = bmfcheck();
|
||||
flagbarfspf = 0;
|
||||
if (spfbehavior && !relayclient)
|
||||
{
|
||||
switch(r = spfcheck()) {
|
||||
case SPF_OK: env_put2("SPFRESULT","pass"); break;
|
||||
case SPF_NONE: env_put2("SPFRESULT","none"); break;
|
||||
case SPF_UNKNOWN: env_put2("SPFRESULT","unknown"); break;
|
||||
case SPF_NEUTRAL: env_put2("SPFRESULT","neutral"); break;
|
||||
case SPF_SOFTFAIL: env_put2("SPFRESULT","softfail"); break;
|
||||
case SPF_FAIL: env_put2("SPFRESULT","fail"); break;
|
||||
case SPF_ERROR: env_put2("SPFRESULT","error"); break;
|
||||
}
|
||||
switch (r) {
|
||||
case SPF_NOMEM:
|
||||
die_nomem();
|
||||
case SPF_ERROR:
|
||||
if (spfbehavior < 2) break;
|
||||
out("451 SPF lookup failure (#4.3.0)\r\n");
|
||||
return;
|
||||
case SPF_NONE:
|
||||
case SPF_UNKNOWN:
|
||||
if (spfbehavior < 6) break;
|
||||
case SPF_NEUTRAL:
|
||||
if (spfbehavior < 5) break;
|
||||
case SPF_SOFTFAIL:
|
||||
if (spfbehavior < 4) break;
|
||||
case SPF_FAIL:
|
||||
if (spfbehavior < 3) break;
|
||||
if (!spfexplanation(&spfbarfmsg)) die_nomem();
|
||||
if (!stralloc_0(&spfbarfmsg)) die_nomem();
|
||||
flagbarfspf = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
env_unset("SPFRESULT");
|
||||
seenmail = 1;
|
||||
if (!stralloc_copys(&rcptto,"")) die_nomem();
|
||||
if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
|
||||
if (!stralloc_0(&mailfrom)) die_nomem();
|
||||
out("250 ok\r\n");
|
||||
}
|
||||
|
||||
void err_spf() {
|
||||
int i,j;
|
||||
|
||||
for(i = 0; i < spfbarfmsg.len; i = j + 1) {
|
||||
j = byte_chr(spfbarfmsg.s + i, spfbarfmsg.len - i, '\n') + i;
|
||||
if (j < spfbarfmsg.len) {
|
||||
out("550-");
|
||||
spfbarfmsg.s[j] = 0;
|
||||
out(spfbarfmsg.s);
|
||||
spfbarfmsg.s[j] = '\n';
|
||||
out("\r\n");
|
||||
} else {
|
||||
out("550 ");
|
||||
out(spfbarfmsg.s);
|
||||
out(" (#5.7.1)\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void smtp_rcpt(arg) char *arg; {
|
||||
if (!seenmail) { err_wantmail(); return; }
|
||||
if (!addrparse(arg)) { err_syntax(); return; }
|
||||
if (flagbarf) { err_bmf(); return; }
|
||||
if (flagbarfspf) { err_spf(); return; }
|
||||
if (relayclient) {
|
||||
--addr.len;
|
||||
if (!stralloc_cats(&addr,relayclient)) die_nomem();
|
||||
|
|
@ -456,6 +535,25 @@ int *hops;
|
|||
}
|
||||
}
|
||||
|
||||
void spfreceived()
|
||||
{
|
||||
stralloc sa = {0};
|
||||
stralloc rcvd_spf = {0};
|
||||
|
||||
if (!spfbehavior || relayclient) return;
|
||||
|
||||
if (!stralloc_copys(&rcvd_spf, "Received-SPF: ")) die_nomem();
|
||||
if (!spfinfo(&sa)) die_nomem();
|
||||
if (!stralloc_cat(&rcvd_spf, &sa)) die_nomem();
|
||||
if (!stralloc_append(&rcvd_spf, "\n")) die_nomem();
|
||||
if (bytestooverflow) {
|
||||
bytestooverflow -= rcvd_spf.len;
|
||||
if (bytestooverflow <= 0) qmail_fail(&qqt);
|
||||
}
|
||||
qmail_put(&qqt,rcvd_spf.s,rcvd_spf.len);
|
||||
}
|
||||
|
||||
|
||||
char accept_buf[FMT_ULONG];
|
||||
void acceptmessage(qp) unsigned long qp;
|
||||
{
|
||||
|
|
@ -484,6 +582,7 @@ void smtp_data(arg) char *arg; {
|
|||
out("354 go ahead\r\n");
|
||||
|
||||
received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
|
||||
spfreceived();
|
||||
blast(&hops);
|
||||
hops = (hops >= MAXHOPS);
|
||||
if (hops) qmail_fail(&qqt);
|
||||
|
|
|
|||
878
spf.c
Normal file
878
spf.c
Normal file
|
|
@ -0,0 +1,878 @@
|
|||
#include "stralloc.h"
|
||||
#include "strsalloc.h"
|
||||
#include "alloc.h"
|
||||
#include "ip.h"
|
||||
#include "ipalloc.h"
|
||||
#include "ipme.h"
|
||||
#include "str.h"
|
||||
#include "fmt.h"
|
||||
#include "scan.h"
|
||||
#include "byte.h"
|
||||
#include "now.h"
|
||||
#include "dns.h"
|
||||
#include "case.h"
|
||||
#include "spf.h"
|
||||
|
||||
#define SPF_EXT -1
|
||||
#define SPF_SYNTAX -2
|
||||
|
||||
#define WSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n')
|
||||
#define NXTOK(b, p, a) do { (b) = (p); \
|
||||
while((p) < (a)->len && !WSPACE((a)->s[(p)])) ++(p); \
|
||||
while((p) < (a)->len && WSPACE((a)->s[(p)])) (a)->s[(p)++] = 0; \
|
||||
} while(0)
|
||||
|
||||
/* this table and macro came from wget more or less */
|
||||
/* and was in turn stolen by me from libspf as is :) */
|
||||
const static unsigned char urlchr_table[256] =
|
||||
{
|
||||
1, 1, 1, 1, 1, 1, 1, 1, /* NUL SOH STX ETX EOT ENQ ACK BEL */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, /* BS HT LF VT FF CR SO SI */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, /* CAN EM SUB ESC FS GS RS US */
|
||||
1, 0, 1, 1, 0, 1, 1, 0, /* SP ! " # $ % & ' */
|
||||
0, 0, 0, 1, 0, 0, 0, 1, /* ( ) * + , - . / */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
|
||||
0, 0, 1, 1, 1, 1, 1, 1, /* 8 9 : ; < = > ? */
|
||||
1, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
|
||||
0, 0, 0, 1, 1, 1, 1, 0, /* X Y Z [ \ ] ^ _ */
|
||||
1, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
|
||||
0, 0, 0, 1, 1, 1, 1, 1, /* x y z { | } ~ DEL */
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
|
||||
extern stralloc addr;
|
||||
extern stralloc helohost;
|
||||
extern char *remoteip;
|
||||
extern char *local;
|
||||
|
||||
extern stralloc spflocal;
|
||||
extern stralloc spfguess;
|
||||
extern stralloc spfexp;
|
||||
|
||||
static stralloc sender_fqdn = {0};
|
||||
static stralloc explanation = {0};
|
||||
static stralloc expdomain = {0};
|
||||
static stralloc errormsg = {0};
|
||||
static char *received;
|
||||
|
||||
static int recursion;
|
||||
static struct ip_address ip;
|
||||
|
||||
static void hdr_pass() { received = "pass (%{xr}: %{xs} designates %{i} as permitted sender)"; };
|
||||
static void hdr_softfail() { received = "softfail (%{xr}: transitioning %{xs} does not designate %{i} as permitted sender)"; };
|
||||
static void hdr_fail() { received = "fail (%{xr}: %{xs} does not designate %{i} as permitted sender)"; };
|
||||
static void hdr_unknown() { received = "unknown (%{xr}: domain at %{d} does not designate permitted sender hosts)"; };
|
||||
static void hdr_neutral() { received = "neutral (%{xr}: %{i} is neither permitted nor denied by %{xs})"; };
|
||||
static void hdr_none() { received = "none (%{xr}: domain at %{d} does not designate permitted sender hosts)"; };
|
||||
static void hdr_unknown_msg(e) char *e; { stralloc_copys(&errormsg, e); received = "unknown (%{xr}: %{xe})"; };
|
||||
static void hdr_ext(e) char *e; { stralloc_copys(&errormsg, e); received = "unknown %{xe} (%{xr}: %{xs} uses mechanism not recognized by this client)"; };
|
||||
static void hdr_syntax() { received = "unknown (%{xr}: parse error in %{xs})"; };
|
||||
static void hdr_error(e) char *e; { stralloc_copys(&errormsg, e); received = "error (%{xr}: error in processing during lookup of %{d}: %{xe})"; };
|
||||
static void hdr_dns() { hdr_error("DNS problem"); }
|
||||
|
||||
|
||||
static int matchip(struct ip_address *net, int mask, struct ip_address *ip)
|
||||
{
|
||||
int j;
|
||||
int bytemask;
|
||||
|
||||
for (j = 0; j < 4 && mask > 0; ++j) {
|
||||
if (mask > 8) bytemask = 8; else bytemask = mask;
|
||||
mask -= bytemask;
|
||||
|
||||
if ((net->d[j] ^ ip->d[j]) & (0x100 - (1 << (8 - bytemask))))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getipmask(char *mask, int ipv6) {
|
||||
unsigned long r;
|
||||
int pos;
|
||||
|
||||
if (!mask) return 32;
|
||||
|
||||
pos = scan_ulong(mask, &r);
|
||||
if (!pos || (mask[pos] && !(mask[pos] == '/' && ipv6))) return -1;
|
||||
if (r > 32) return -1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int spfget(stralloc *spf, stralloc *domain)
|
||||
{
|
||||
strsalloc ssa = {0};
|
||||
int j;
|
||||
int begin, pos, i;
|
||||
int r = SPF_NONE;
|
||||
|
||||
spf->len = 0;
|
||||
|
||||
switch(dns_txt(&ssa, domain)) {
|
||||
case DNS_MEM: return SPF_NOMEM;
|
||||
case DNS_SOFT: hdr_dns(); return SPF_ERROR;
|
||||
case DNS_HARD: return SPF_NONE;
|
||||
}
|
||||
|
||||
for (j = 0;j < ssa.len;++j) {
|
||||
pos = 0;
|
||||
|
||||
NXTOK(begin, pos, &ssa.sa[j]);
|
||||
if (str_len(ssa.sa[j].s + begin) < 6) continue;
|
||||
if (!byte_equal(ssa.sa[j].s + begin,6,"v=spf1")) continue;
|
||||
if (ssa.sa[j].s[begin + 6]) {
|
||||
/* check for subversion */
|
||||
if (ssa.sa[j].s[begin + 6] != '.') continue;
|
||||
for(i = begin + 7;;++i)
|
||||
if (!(ssa.sa[j].s[i] >= '0' && ssa.sa[j].s[i] <= '9')) break;
|
||||
if (i == (begin + 7)) continue;
|
||||
if (ssa.sa[j].s[i]) continue;
|
||||
}
|
||||
|
||||
if (spf->len > 0) {
|
||||
spf->len = 0;
|
||||
hdr_unknown_msg("Multiple SPF records returned");
|
||||
r = SPF_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (!stralloc_0(&ssa.sa[j])) return SPF_NOMEM;
|
||||
if (!stralloc_copys(spf,ssa.sa[j].s + pos)) return SPF_NOMEM;
|
||||
r = SPF_OK;
|
||||
}
|
||||
|
||||
for (j = 0;j < ssa.len;++j)
|
||||
alloc_free(ssa.sa[j].s);
|
||||
alloc_free(ssa.sa);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int spf_ptr(char *spec, char *mask);
|
||||
|
||||
int spfsubst(stralloc *expand, char *spec, char *domain)
|
||||
{
|
||||
static char hexdigits[] = "0123456789abcdef";
|
||||
stralloc sa = {0};
|
||||
char ch;
|
||||
int digits = -1;
|
||||
int urlencode = 0;
|
||||
int reverse = 0;
|
||||
int start = expand->len;
|
||||
int i, pos;
|
||||
char *split = ".";
|
||||
|
||||
if (!stralloc_readyplus(&sa,0)) return 0;
|
||||
|
||||
if (*spec == 'x') { i = 1; ++spec; } else i = 0;
|
||||
ch = *spec++;
|
||||
if (!ch) { alloc_free(sa.s); return 1; }
|
||||
if (ch >= 'A' && ch <= 'Z') { ch += 32; urlencode = 1; }
|
||||
if (i) ch -= 32;
|
||||
while(*spec >= '0' && *spec <= '9') {
|
||||
if (digits < 0) digits = 0;
|
||||
if (digits >= 1000000) { digits = 10000000; continue; }
|
||||
digits = (digits * 10) + (*spec - '0');
|
||||
spec++;
|
||||
}
|
||||
|
||||
while((*spec >= 'a' && *spec <= 'z') || (*spec >= 'A' && *spec <= 'Z')) {
|
||||
if (*spec == 'r') reverse = 1;
|
||||
spec++;
|
||||
}
|
||||
|
||||
if (*spec) split = spec;
|
||||
|
||||
switch(ch) {
|
||||
case 'l':
|
||||
pos = byte_rchr(addr.s, addr.len, '@');
|
||||
if (pos < addr.len) {
|
||||
if (!stralloc_copyb(&sa, addr.s, pos)) return 0;
|
||||
} else
|
||||
if (!stralloc_copys(&sa, "postmaster")) return 0;
|
||||
break;
|
||||
case 's':
|
||||
if (!stralloc_copys(&sa, addr.s)) return 0;
|
||||
break;
|
||||
case 'o':
|
||||
pos = byte_rchr(addr.s, addr.len, '@') + 1;
|
||||
if (pos > addr.len) break;
|
||||
if (!stralloc_copys(&sa, addr.s + pos)) return 0;
|
||||
break;
|
||||
case 'd':
|
||||
if (!stralloc_copys(&sa, domain)) return 0;
|
||||
break;
|
||||
case 'i':
|
||||
if (!stralloc_ready(&sa, IPFMT)) return 0;
|
||||
sa.len = ip_fmt(sa.s, &ip);
|
||||
break;
|
||||
case 't':
|
||||
if (!stralloc_ready(&sa, FMT_ULONG)) return 0;
|
||||
sa.len = fmt_ulong(sa.s, (unsigned long)now());
|
||||
break;
|
||||
case 'p':
|
||||
if (!sender_fqdn.len)
|
||||
spf_ptr(domain, 0);
|
||||
if (sender_fqdn.len) {
|
||||
if (!stralloc_copy(&sa, &sender_fqdn)) return 0;
|
||||
} else
|
||||
if (!stralloc_copys(&sa, "unknown")) return 0;
|
||||
break;
|
||||
case 'v':
|
||||
if (!stralloc_copys(&sa, "in-addr")) return 0;
|
||||
break;
|
||||
case 'h':
|
||||
if (!stralloc_copys(&sa, helohost.s)) return 0; /* FIXME: FQDN? */
|
||||
break;
|
||||
case 'E':
|
||||
if (errormsg.len && !stralloc_copy(&sa, &errormsg)) return 0;
|
||||
break;
|
||||
case 'R':
|
||||
if (!stralloc_copys(&sa, local)) return 0;
|
||||
break;
|
||||
case 'S':
|
||||
if (expdomain.len > 0) {
|
||||
if (!stralloc_copys(&sa, "SPF record at ")) return 0;
|
||||
if (!stralloc_cats(&sa, expdomain.s)) return 0;
|
||||
} else {
|
||||
if (!stralloc_copys(&sa, "local policy")) return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
for(pos = 0; digits; ++pos) {
|
||||
pos += byte_cspn(sa.s + pos, sa.len - pos, split);
|
||||
if (pos >= sa.len) break;
|
||||
if (!--digits) break;
|
||||
}
|
||||
|
||||
for(; pos > 0; pos = i - 1) {
|
||||
i = byte_rcspn(sa.s, pos, split) + 1;
|
||||
if (i > pos) i = 0;
|
||||
if (!stralloc_catb(expand, sa.s + i, pos - i)) return 0;
|
||||
if (i > 0 && !stralloc_append(expand, ".")) return 0;
|
||||
}
|
||||
} else {
|
||||
for(pos = sa.len; digits; --pos) {
|
||||
i = byte_rcspn(sa.s, pos, split) + 1;
|
||||
if (i > pos) { pos = 0; break; }
|
||||
pos = i;
|
||||
if (!--digits) break;
|
||||
}
|
||||
|
||||
if (!stralloc_catb(expand, sa.s + pos, sa.len - pos)) return 0;
|
||||
if (split[0] != '.' || split[1])
|
||||
for(pos = 0; pos < expand->len; pos++) {
|
||||
pos += byte_cspn(expand->s + pos, expand->len - pos, split);
|
||||
if (pos < expand->len)
|
||||
expand->s[pos] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
if (urlencode) {
|
||||
stralloc_copyb(&sa, expand->s + start, expand->len - start);
|
||||
expand->len = start;
|
||||
|
||||
for(pos = 0; pos < sa.len; ++pos) {
|
||||
ch = sa.s[pos];
|
||||
if (urlchr_table[(unsigned char)ch]) {
|
||||
if (!stralloc_readyplus(expand, 3)) return 0;
|
||||
expand->s[expand->len++] = '%';
|
||||
expand->s[expand->len++] = hexdigits[(unsigned char)ch >> 4];
|
||||
expand->s[expand->len++] = hexdigits[(unsigned char)ch & 15];
|
||||
} else
|
||||
if (!stralloc_append(expand, &ch)) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
alloc_free(sa.s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spfexpand(stralloc *sa, char *spec, char *domain)
|
||||
{
|
||||
char *p;
|
||||
char append;
|
||||
int pos;
|
||||
|
||||
if (!stralloc_readyplus(sa, 0)) return 0;
|
||||
sa->len = 0;
|
||||
|
||||
for(p = spec; *p; p++) {
|
||||
append = *p;
|
||||
if (*p == '%') {
|
||||
p++;
|
||||
switch(*p) {
|
||||
case '%': break;
|
||||
case '_': append = ' '; break;
|
||||
case '-': if (!stralloc_cats(sa, "%20")) return 0; continue;
|
||||
case '{':
|
||||
pos = str_chr(p, '}');
|
||||
if (p[pos] != '}') { p--; break; }
|
||||
p[pos] = 0;
|
||||
if (!spfsubst(sa, p + 1, domain)) return 0;
|
||||
p += pos;
|
||||
continue;
|
||||
default: p--;
|
||||
}
|
||||
}
|
||||
if (!stralloc_append(sa, &append)) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int spflookup(stralloc *domain);
|
||||
|
||||
static int spf_include(char *spec, char *mask)
|
||||
{
|
||||
stralloc sa = {0};
|
||||
int r;
|
||||
|
||||
if (!stralloc_copys(&sa, spec)) return SPF_NOMEM;
|
||||
r = spflookup(&sa);
|
||||
alloc_free(sa.s);
|
||||
|
||||
switch(r) {
|
||||
case SPF_NONE:
|
||||
hdr_unknown();
|
||||
r = SPF_UNKNOWN;
|
||||
break;
|
||||
case SPF_SYNTAX:
|
||||
r = SPF_UNKNOWN;
|
||||
break;
|
||||
case SPF_NEUTRAL:
|
||||
case SPF_SOFTFAIL:
|
||||
case SPF_FAIL:
|
||||
r = SPF_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int spf_a(char *spec, char *mask)
|
||||
{
|
||||
stralloc sa = {0};
|
||||
ipalloc ia = {0};
|
||||
int ipmask = getipmask(mask, 1);
|
||||
int r;
|
||||
int j;
|
||||
|
||||
if (ipmask < 0) return SPF_SYNTAX;
|
||||
|
||||
if (!stralloc_copys(&sa, spec)) return SPF_NOMEM;
|
||||
if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM;
|
||||
|
||||
switch(dns_ip(&ia, &sa)) {
|
||||
case DNS_MEM: return SPF_NOMEM;
|
||||
case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
|
||||
case DNS_HARD: r = SPF_NONE; break;
|
||||
default:
|
||||
r = SPF_NONE;
|
||||
for(j = 0; j < ia.len; ++j)
|
||||
if (matchip(&ia.ix[j].ip, ipmask, &ip)) {
|
||||
r = SPF_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
alloc_free(sa.s);
|
||||
alloc_free(ia.ix);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int spf_mx(char *spec, char *mask)
|
||||
{
|
||||
stralloc sa = {0};
|
||||
ipalloc ia = {0};
|
||||
int ipmask = getipmask(mask, 1);
|
||||
int random = now() + (getpid() << 16);
|
||||
int r;
|
||||
int j;
|
||||
|
||||
if (ipmask < 0) return SPF_SYNTAX;
|
||||
|
||||
if (!stralloc_copys(&sa, spec)) return SPF_NOMEM;
|
||||
if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM;
|
||||
|
||||
switch(dns_mxip(&ia, &sa, random)) {
|
||||
case DNS_MEM: return SPF_NOMEM;
|
||||
case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
|
||||
case DNS_HARD: r = SPF_NONE; break;
|
||||
default:
|
||||
r = SPF_NONE;
|
||||
for(j = 0; j < ia.len; ++j)
|
||||
if (matchip(&ia.ix[j].ip, ipmask, &ip)) {
|
||||
r = SPF_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
alloc_free(sa.s);
|
||||
alloc_free(ia.ix);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int spf_ptr(char *spec, char *mask)
|
||||
{
|
||||
strsalloc ssa = {0};
|
||||
ipalloc ia = {0};
|
||||
int len = str_len(spec);
|
||||
int r;
|
||||
int j, k;
|
||||
int pos;
|
||||
|
||||
/* we didn't find host with the matching ip before */
|
||||
if (sender_fqdn.len == 7 && str_equal(sender_fqdn.s, "unknown"))
|
||||
return SPF_NONE;
|
||||
|
||||
/* the hostname found will probably be the same as before */
|
||||
while (sender_fqdn.len) {
|
||||
pos = sender_fqdn.len - len;
|
||||
if (pos < 0) break;
|
||||
if (pos > 0 && sender_fqdn.s[pos - 1] != '.') break;
|
||||
if (case_diffb(sender_fqdn.s + pos, len, spec)) break;
|
||||
|
||||
return SPF_OK;
|
||||
}
|
||||
|
||||
/* ok, either it's the first test or it's a very weird setup */
|
||||
|
||||
if (!stralloc_readyplus(&ssa, 0)) return SPF_NOMEM;
|
||||
if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM;
|
||||
|
||||
switch(dns_ptr(&ssa, &ip)) {
|
||||
case DNS_MEM: return SPF_NOMEM;
|
||||
case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
|
||||
case DNS_HARD: r = SPF_NONE; break;
|
||||
default:
|
||||
r = SPF_NONE;
|
||||
for(j = 0; j < ssa.len; ++j) {
|
||||
switch(dns_ip(&ia, &ssa.sa[j])) {
|
||||
case DNS_MEM: return SPF_NOMEM;
|
||||
case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
|
||||
case DNS_HARD: break;
|
||||
default:
|
||||
for(k = 0; k < ia.len; ++k)
|
||||
if (matchip(&ia.ix[k].ip, 32, &ip)) {
|
||||
if (!sender_fqdn.len)
|
||||
if (!stralloc_copy(&sender_fqdn, &ssa.sa[j])) return SPF_NOMEM;
|
||||
|
||||
pos = ssa.sa[j].len - len;
|
||||
if (pos < 0) continue;
|
||||
if (pos > 0 && ssa.sa[j].s[pos - 1] != '.') continue;
|
||||
if (case_diffb(ssa.sa[j].s + pos, len, spec)) continue;
|
||||
|
||||
stralloc_copy(&sender_fqdn, &ssa.sa[j]);
|
||||
r = SPF_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r == SPF_ERROR) break;
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 0;j < ssa.len;++j)
|
||||
alloc_free(ssa.sa[j].s);
|
||||
|
||||
alloc_free(ssa.sa);
|
||||
alloc_free(ia.ix);
|
||||
|
||||
if (!sender_fqdn.len)
|
||||
if (!stralloc_copys(&sender_fqdn, "unknown")) return SPF_NOMEM;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int spf_ip(char *spec, char *mask)
|
||||
{
|
||||
struct ip_address net;
|
||||
int ipmask = getipmask(mask, 0);
|
||||
|
||||
if (ipmask < 0) return SPF_SYNTAX;
|
||||
if (!ip_scan(spec, &net)) return SPF_SYNTAX;
|
||||
|
||||
if (matchip(&net, ipmask, &ip)) return SPF_OK;
|
||||
|
||||
return SPF_NONE;
|
||||
}
|
||||
|
||||
static int spf_exists(char *spec, char *mask)
|
||||
{
|
||||
stralloc sa = {0};
|
||||
ipalloc ia = {0};
|
||||
int r;
|
||||
|
||||
if (!stralloc_copys(&sa, spec)) return SPF_NOMEM;
|
||||
if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM;
|
||||
|
||||
switch(dns_ip(&ia, &sa)) {
|
||||
case DNS_MEM: return SPF_NOMEM;
|
||||
case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
|
||||
case DNS_HARD: r = SPF_NONE; break;
|
||||
default: r = SPF_OK;
|
||||
}
|
||||
|
||||
alloc_free(sa.s);
|
||||
alloc_free(ia.ix);
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct mechanisms {
|
||||
char *mechanism;
|
||||
int (*func)(char *spec, char *mask);
|
||||
unsigned int takes_spec : 1;
|
||||
unsigned int takes_mask : 1;
|
||||
unsigned int expands : 1;
|
||||
unsigned int filldomain : 1;
|
||||
int defresult : 4;
|
||||
} mechanisms[] = {
|
||||
{ "all", 0, 0,0,0,0,SPF_OK }
|
||||
, { "include", spf_include,1,0,1,0,0 }
|
||||
, { "a", spf_a, 1,1,1,1,0 }
|
||||
, { "mx", spf_mx, 1,1,1,1,0 }
|
||||
, { "ptr", spf_ptr, 1,0,1,1,0 }
|
||||
, { "ip4", spf_ip, 1,1,0,0,0 }
|
||||
, { "ip6", 0, 1,1,0,0,SPF_NONE }
|
||||
, { "exists", spf_exists, 1,0,1,0,0 }
|
||||
, { "extension",0, 1,1,0,0,SPF_EXT }
|
||||
, { 0, 0, 1,1,0,0,SPF_EXT }
|
||||
};
|
||||
|
||||
static int spfmech(char *mechanism, char *spec, char *mask, char *domain)
|
||||
{
|
||||
struct mechanisms *mech;
|
||||
stralloc sa = {0};
|
||||
int r;
|
||||
int pos;
|
||||
|
||||
for(mech = mechanisms; mech->mechanism; mech++)
|
||||
if (str_equal(mech->mechanism, mechanism)) break;
|
||||
|
||||
if (mech->takes_spec && !spec && mech->filldomain) spec = domain;
|
||||
if (!mech->takes_spec != !spec) return SPF_SYNTAX;
|
||||
if (!mech->takes_mask && mask) return SPF_SYNTAX;
|
||||
if (!mech->func) return mech->defresult;
|
||||
|
||||
if (!stralloc_readyplus(&sa, 0)) return SPF_NOMEM;
|
||||
if (mech->expands && spec != domain) {
|
||||
if (!spfexpand(&sa, spec, domain)) return SPF_NOMEM;
|
||||
for (pos = 0; (sa.len - pos) > 255;) {
|
||||
pos += byte_chr(sa.s + pos, sa.len - pos, '.');
|
||||
if (pos < sa.len) pos++;
|
||||
}
|
||||
sa.len -= pos;
|
||||
if (pos > 0) byte_copy(sa.s, sa.len, sa.s + pos);
|
||||
stralloc_0(&sa);
|
||||
spec = sa.s;
|
||||
}
|
||||
|
||||
r = mech->func(spec, mask);
|
||||
|
||||
alloc_free(sa.s);
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct default_aliases {
|
||||
char *alias;
|
||||
int defret;
|
||||
} default_aliases[] = {
|
||||
{ "allow", SPF_OK }
|
||||
, { "pass", SPF_OK }
|
||||
, { "deny", SPF_FAIL }
|
||||
, { "softdeny",SPF_SOFTFAIL }
|
||||
, { "fail", SPF_FAIL }
|
||||
, { "softfail",SPF_SOFTFAIL }
|
||||
, { "unknown", SPF_NEUTRAL }
|
||||
, { 0, SPF_UNKNOWN }
|
||||
};
|
||||
|
||||
static int spflookup(stralloc *domain)
|
||||
{
|
||||
stralloc spf = {0};
|
||||
stralloc sa = {0};
|
||||
struct default_aliases *da;
|
||||
int main = !recursion;
|
||||
int local_pos = -1;
|
||||
int r, q;
|
||||
int begin, pos;
|
||||
int i;
|
||||
int prefix;
|
||||
int done;
|
||||
int guessing = 0;
|
||||
char *p;
|
||||
|
||||
if (!stralloc_readyplus(&spf, 0)) return SPF_NOMEM;
|
||||
if (!stralloc_readyplus(&sa, 0)) return SPF_NOMEM;
|
||||
|
||||
/* fallthrough result */
|
||||
if (main) hdr_none();
|
||||
|
||||
redirect:
|
||||
if (++recursion > 20) {
|
||||
alloc_free(spf.s);
|
||||
alloc_free(sa.s);
|
||||
hdr_unknown_msg("Maximum nesting level exceeded, possible loop");
|
||||
return SPF_SYNTAX;
|
||||
}
|
||||
|
||||
if (!stralloc_0(domain)) return SPF_NOMEM;
|
||||
if (!stralloc_copy(&expdomain, domain)) return SPF_NOMEM;
|
||||
|
||||
r = spfget(&spf, domain);
|
||||
if (r == SPF_NONE) {
|
||||
if (!main) { alloc_free(spf.s); return r; }
|
||||
|
||||
if (spfguess.len) {
|
||||
/* try to guess */
|
||||
guessing = 1;
|
||||
if (!stralloc_copys(&spf, spfguess.s)) return SPF_NOMEM;
|
||||
if (!stralloc_append(&spf, " ")) return SPF_NOMEM;
|
||||
} else
|
||||
spf.len = 0;
|
||||
|
||||
/* append local rulest */
|
||||
if (spflocal.len) {
|
||||
local_pos = spf.len;
|
||||
if (!stralloc_cats(&spf, spflocal.s)) return SPF_NOMEM;
|
||||
}
|
||||
if (!stralloc_0(&spf)) return SPF_NOMEM;
|
||||
|
||||
expdomain.len = 0;
|
||||
} else if (r == SPF_OK) {
|
||||
if (!stralloc_0(&spf)) return SPF_NOMEM;
|
||||
if (main) hdr_neutral();
|
||||
r = SPF_NEUTRAL;
|
||||
|
||||
/* try to add local rules before fail all mechs */
|
||||
if (main && spflocal.len) {
|
||||
pos = 0;
|
||||
p = (char *) 0;
|
||||
while(pos < spf.len) {
|
||||
NXTOK(begin, pos, &spf);
|
||||
if (!spf.s[begin]) continue;
|
||||
|
||||
if (p && spf.s[begin] != *p) p = (char *) 0;
|
||||
if (!p && (spf.s[begin] == '-' || spf.s[begin] == '~' ||
|
||||
spf.s[begin] == '?')) p = &spf.s[begin];
|
||||
|
||||
if (p && p > spf.s && str_equal(spf.s + begin + 1, "all")) {
|
||||
/* ok, we can insert the local rules at p */
|
||||
local_pos = p - spf.s;
|
||||
|
||||
stralloc_readyplus(&spf, spflocal.len);
|
||||
p = spf.s + local_pos;
|
||||
byte_copyr(p + spflocal.len, spf.len - local_pos, p);
|
||||
byte_copy(p, spflocal.len, spflocal.s);
|
||||
spf.len += spflocal.len;
|
||||
|
||||
pos += spflocal.len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos >= spf.len) pos = spf.len - 1;
|
||||
for(i = 0; i < pos; i++)
|
||||
if (!spf.s[i]) spf.s[i] = ' ';
|
||||
}
|
||||
} else {
|
||||
alloc_free(spf.s);
|
||||
return r;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
done = 0;
|
||||
while(pos < spf.len) {
|
||||
NXTOK(begin, pos, &spf);
|
||||
if (!spf.s[begin]) continue;
|
||||
|
||||
/* in local ruleset? */
|
||||
if (!done && local_pos >= 0 && begin >= local_pos) {
|
||||
if (begin < (local_pos + spflocal.len))
|
||||
expdomain.len = 0;
|
||||
else
|
||||
if (!stralloc_copy(&expdomain, domain))
|
||||
return SPF_NOMEM;
|
||||
}
|
||||
|
||||
for (p = spf.s + begin;*p;++p)
|
||||
if (*p == ':' || *p == '/' || *p == '=') break;
|
||||
|
||||
if (*p == '=') {
|
||||
*p++ = 0;
|
||||
|
||||
/* modifiers are simply handled here */
|
||||
if (str_equal(spf.s + begin, "redirect")) {
|
||||
if (done) continue;
|
||||
|
||||
if (!spfexpand(&sa, p, domain->s)) return SPF_NOMEM;
|
||||
stralloc_copy(domain, &sa);
|
||||
|
||||
hdr_unknown();
|
||||
r = SPF_UNKNOWN;
|
||||
|
||||
goto redirect;
|
||||
} else if (str_equal(spf.s + begin, "default")) {
|
||||
if (done) continue;
|
||||
|
||||
for(da = default_aliases; da->alias; ++da)
|
||||
if (str_equal(da->alias, p)) break;
|
||||
|
||||
r = da->defret;
|
||||
} else if (str_equal(spf.s + begin, "exp")) {
|
||||
strsalloc ssa = {0};
|
||||
|
||||
if (!main) continue;
|
||||
|
||||
if (!stralloc_copys(&sa, p)) return SPF_NOMEM;
|
||||
switch(dns_txt(&ssa, &sa)) {
|
||||
case DNS_MEM: return SPF_NOMEM;
|
||||
case DNS_SOFT: continue; /* FIXME... */
|
||||
case DNS_HARD: continue;
|
||||
}
|
||||
|
||||
explanation.len = 0;
|
||||
for(i = 0; i < ssa.len; i++) {
|
||||
if (!stralloc_cat(&explanation, &ssa.sa[i])) return SPF_NOMEM;
|
||||
if (i < (ssa.len - 1))
|
||||
if (!stralloc_append(&explanation, "\n")) return SPF_NOMEM;
|
||||
|
||||
alloc_free(ssa.sa[i].s);
|
||||
}
|
||||
if (!stralloc_0(&explanation)) return SPF_NOMEM;
|
||||
} /* and unknown modifiers are ignored */
|
||||
} else if (!done) {
|
||||
if (!stralloc_copys(&sa, spf.s + begin)) return SPF_NOMEM;
|
||||
if (!stralloc_0(&sa)) return SPF_NOMEM;
|
||||
|
||||
switch(spf.s[begin]) {
|
||||
case '-': begin++; prefix = SPF_FAIL; break;
|
||||
case '~': begin++; prefix = SPF_SOFTFAIL; break;
|
||||
case '+': begin++; prefix = SPF_OK; break;
|
||||
case '?': begin++; prefix = SPF_NEUTRAL; break;
|
||||
default: prefix = SPF_OK;
|
||||
}
|
||||
|
||||
if (*p == '/') {
|
||||
*p++ = 0;
|
||||
q = spfmech(spf.s + begin, 0, p, domain->s);
|
||||
} else {
|
||||
if (*p) *p++ = 0;
|
||||
i = str_chr(p, '/');
|
||||
if (p[i] == '/') {
|
||||
p[i++] = 0;
|
||||
q = spfmech(spf.s + begin, p, p + i, domain->s);
|
||||
} else if (i > 0)
|
||||
q = spfmech(spf.s + begin, p, 0, domain->s);
|
||||
else
|
||||
q = spfmech(spf.s + begin, 0, 0, domain->s);
|
||||
}
|
||||
|
||||
if (q == SPF_OK) q = prefix;
|
||||
|
||||
switch(q) {
|
||||
case SPF_OK: hdr_pass(); break;
|
||||
case SPF_NEUTRAL: hdr_neutral(); break;
|
||||
case SPF_SYNTAX: hdr_syntax(); break;
|
||||
case SPF_SOFTFAIL: hdr_softfail(); break;
|
||||
case SPF_FAIL: hdr_fail(); break;
|
||||
case SPF_EXT: hdr_ext(sa.s); break;
|
||||
case SPF_ERROR:
|
||||
if (!guessing)
|
||||
break;
|
||||
if (local_pos >= 0 && begin >= local_pos)
|
||||
break;
|
||||
hdr_none();
|
||||
q = SPF_NONE;
|
||||
break;
|
||||
case SPF_NONE: continue;
|
||||
}
|
||||
|
||||
r = q;
|
||||
done = 1; /* we're done, no more mechanisms */
|
||||
}
|
||||
}
|
||||
|
||||
/* we fell through, no local rule applied */
|
||||
if (!done && !stralloc_copy(&expdomain, domain)) return SPF_NOMEM;
|
||||
|
||||
alloc_free(spf.s);
|
||||
alloc_free(sa.s);
|
||||
return r;
|
||||
}
|
||||
|
||||
int spfcheck()
|
||||
{
|
||||
stralloc domain = {0};
|
||||
int pos;
|
||||
int r;
|
||||
|
||||
pos = byte_rchr(addr.s, addr.len, '@') + 1;
|
||||
if (pos < addr.len) {
|
||||
if (!stralloc_copys(&domain, addr.s + pos)) return SPF_NOMEM;
|
||||
} else {
|
||||
pos = str_rchr(helohost.s, '@');
|
||||
if (helohost.s[pos]) {
|
||||
if (!stralloc_copys(&domain, helohost.s + pos + 1)) return SPF_NOMEM;
|
||||
} else
|
||||
if (!stralloc_copys(&domain, helohost.s)) return SPF_NOMEM;
|
||||
}
|
||||
if (!stralloc_copys(&explanation, spfexp.s)) return SPF_NOMEM;
|
||||
if (!stralloc_0(&explanation)) return SPF_NOMEM;
|
||||
recursion = 0;
|
||||
|
||||
if (!remoteip || !ip_scan(remoteip, &ip)) {
|
||||
hdr_unknown_msg("No IP address in conversation");
|
||||
return SPF_UNKNOWN;
|
||||
}
|
||||
|
||||
if (!stralloc_readyplus(&expdomain, 0)) return SPF_NOMEM;
|
||||
if (!stralloc_readyplus(&errormsg, 0)) return SPF_NOMEM;
|
||||
expdomain.len = 0;
|
||||
errormsg.len = 0;
|
||||
sender_fqdn.len = 0;
|
||||
received = (char *) 0;
|
||||
|
||||
if ((ip.d[0] == 127 && ip.d[1] == 0 && ip.d[2] == 0 && ip.d[3] == 1) || ipme_is(&ip))
|
||||
{ hdr_pass(); r = SPF_OK; }
|
||||
else
|
||||
r = spflookup(&domain);
|
||||
|
||||
if (r < 0) r = SPF_UNKNOWN;
|
||||
|
||||
alloc_free(domain.s);
|
||||
return r;
|
||||
}
|
||||
|
||||
int spfexplanation(sa)
|
||||
stralloc *sa;
|
||||
{
|
||||
return spfexpand(sa, explanation.s, expdomain.s);
|
||||
}
|
||||
|
||||
int spfinfo(sa)
|
||||
stralloc *sa;
|
||||
{
|
||||
stralloc tmp = {0};
|
||||
if (!stralloc_copys(&tmp, received)) return 0;
|
||||
if (!stralloc_0(&tmp)) return 0;
|
||||
if (!spfexpand(sa, tmp.s, expdomain.s)) return 0;
|
||||
alloc_free(tmp.s);
|
||||
return 1;
|
||||
}
|
||||
20
spf.h
Normal file
20
spf.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef SPF_H
|
||||
#define SPF_H
|
||||
|
||||
#define SPF_OK 0
|
||||
#define SPF_NONE 1
|
||||
#define SPF_UNKNOWN 2
|
||||
#define SPF_NEUTRAL 3
|
||||
#define SPF_SOFTFAIL 4
|
||||
#define SPF_FAIL 5
|
||||
#define SPF_ERROR 6
|
||||
#define SPF_NOMEM 7
|
||||
|
||||
#define SPF_DEFEXP "See http://spf.pobox.com/" \
|
||||
"why.html?sender=%{S}&ip=%{I}&receiver=%{xR}"
|
||||
|
||||
extern int spfcheck();
|
||||
extern int spfexplanation();
|
||||
extern int spfinfo();
|
||||
|
||||
#endif
|
||||
84
spfquery.c
Normal file
84
spfquery.c
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#include "substdio.h"
|
||||
#include "subfd.h"
|
||||
#include "stralloc.h"
|
||||
#include "alloc.h"
|
||||
#include "spf.h"
|
||||
#include "exit.h"
|
||||
|
||||
void die(e,s) int e; char *s; { substdio_putsflush(subfderr,s); _exit(e); }
|
||||
void die_usage() { die(100,"fatal: invalid usage\nusage: spfquery <sender-ip> <sender-helo/ehlo> <envelope-from> [<local rules>] [<best guess rules>]\n"); }
|
||||
void die_nomem() { die(111,"fatal: out of memory\n"); }
|
||||
|
||||
stralloc addr = {0};
|
||||
stralloc helohost = {0};
|
||||
char *remoteip;
|
||||
char *local;
|
||||
|
||||
stralloc spflocal = {0};
|
||||
stralloc spfguess = {0};
|
||||
stralloc spfexp = {0};
|
||||
|
||||
void main(argc,argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
stralloc sa = {0};
|
||||
int r;
|
||||
|
||||
if (argc < 4) die_usage();
|
||||
|
||||
remoteip = (char *)strdup(argv[1]);
|
||||
local = "localhost";
|
||||
|
||||
if (!stralloc_copys(&helohost, argv[2])) die_nomem();
|
||||
if (!stralloc_0(&helohost)) die_nomem();
|
||||
|
||||
if (!stralloc_copys(&addr, argv[3])) die_nomem();
|
||||
if (!stralloc_0(&addr)) die_nomem();
|
||||
|
||||
if (argc > 4) {
|
||||
if (!stralloc_copys(&spflocal, argv[4])) die_nomem();
|
||||
if (spflocal.len && !stralloc_0(&spflocal)) die_nomem();
|
||||
}
|
||||
|
||||
if (argc > 5) {
|
||||
if (!stralloc_copys(&spfguess, argv[5])) die_nomem();
|
||||
if (spfguess.len && !stralloc_0(&spfguess)) die_nomem();
|
||||
}
|
||||
|
||||
if (argc > 6) {
|
||||
if (!stralloc_copys(&spfexp, argv[6])) die_nomem();
|
||||
} else
|
||||
if (!stralloc_copys(&spfexp, SPF_DEFEXP)) die_nomem();
|
||||
if (spfexp.len && !stralloc_0(&spfexp)) die_nomem();
|
||||
|
||||
dns_init(0);
|
||||
r = spfcheck();
|
||||
if (r == SPF_NOMEM) die_nomem();
|
||||
|
||||
substdio_puts(subfdout,"result=");
|
||||
switch(r) {
|
||||
case SPF_OK: substdio_puts(subfdout,"pass"); break;
|
||||
case SPF_NONE: substdio_puts(subfdout,"none"); break;
|
||||
case SPF_UNKNOWN: substdio_puts(subfdout,"unknown"); break;
|
||||
case SPF_NEUTRAL: substdio_puts(subfdout,"neutral"); break;
|
||||
case SPF_SOFTFAIL: substdio_puts(subfdout,"softfail"); break;
|
||||
case SPF_FAIL: substdio_puts(subfdout,"fail"); break;
|
||||
case SPF_ERROR: substdio_puts(subfdout,"error"); break;
|
||||
}
|
||||
|
||||
if (r == SPF_FAIL) {
|
||||
substdio_puts(subfdout,": ");
|
||||
if (!spfexplanation(&sa)) die_nomem();
|
||||
substdio_put(subfdout,sa.s,sa.len);
|
||||
}
|
||||
|
||||
substdio_putsflush(subfdout,"\n");
|
||||
|
||||
substdio_puts(subfdout,"Received-SPF: ");
|
||||
if (!spfinfo(&sa)) die_nomem();
|
||||
substdio_put(subfdout,sa.s,sa.len);
|
||||
substdio_putsflush(subfdout,"\n");
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
1
str.h
1
str.h
|
|
@ -2,6 +2,7 @@
|
|||
#define STR_H
|
||||
|
||||
extern unsigned int str_copy();
|
||||
extern unsigned int str_copyb();
|
||||
extern int str_diff();
|
||||
extern int str_diffn();
|
||||
extern unsigned int str_len();
|
||||
|
|
|
|||
18
str_cpyb.c
Normal file
18
str_cpyb.c
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include "str.h"
|
||||
|
||||
unsigned int str_copyb(s,t,max)
|
||||
register char *s;
|
||||
register char *t;
|
||||
unsigned int max;
|
||||
{
|
||||
register int len;
|
||||
|
||||
len = 0;
|
||||
while (max-- > 0) {
|
||||
if (!(*s = *t)) return len; ++s; ++t; ++len;
|
||||
if (!(*s = *t)) return len; ++s; ++t; ++len;
|
||||
if (!(*s = *t)) return len; ++s; ++t; ++len;
|
||||
if (!(*s = *t)) return len; ++s; ++t; ++len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
7
strsalloc.c
Normal file
7
strsalloc.c
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include "alloc.h"
|
||||
#include "gen_allocdefs.h"
|
||||
#include "stralloc.h"
|
||||
#include "strsalloc.h"
|
||||
|
||||
GEN_ALLOC_readyplus(strsalloc,stralloc,sa,len,a,i,n,x,10,strsalloc_readyplus)
|
||||
GEN_ALLOC_append(strsalloc,stralloc,sa,len,a,i,n,x,10,strsalloc_readyplus,strsalloc_append)
|
||||
12
strsalloc.h
Normal file
12
strsalloc.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef STRSALLOC_H
|
||||
#define STRSALLOC_H
|
||||
|
||||
#include "stralloc.h"
|
||||
|
||||
#include "gen_alloc.h"
|
||||
|
||||
GEN_ALLOC_typedef(strsalloc,stralloc,sa,len,a)
|
||||
extern int strsalloc_readyplus();
|
||||
extern int strsalloc_append();
|
||||
|
||||
#endif
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include "scan.h"
|
||||
#include "subgetopt.h"
|
||||
#include "ip.h"
|
||||
#include "strsalloc.h"
|
||||
#include "dns.h"
|
||||
#include "byte.h"
|
||||
#include "remoteinfo.h"
|
||||
|
|
@ -34,6 +35,7 @@ void main(argc,argv)
|
|||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
strsalloc ssa = {0};
|
||||
int dummy;
|
||||
char *proto;
|
||||
int opt;
|
||||
|
|
@ -74,12 +76,13 @@ char *argv[];
|
|||
temp[ip_fmt(temp,&iplocal)] = 0;
|
||||
if (!env_put2("TCPLOCALIP",temp)) die();
|
||||
|
||||
switch(dns_ptr(&localname,&iplocal))
|
||||
switch(dns_ptr(&ssa,&iplocal))
|
||||
{
|
||||
case DNS_MEM: die();
|
||||
case DNS_SOFT:
|
||||
if (!stralloc_copys(&localname,"softdnserror")) die();
|
||||
case 0:
|
||||
if (!stralloc_copy(&localname,&ssa.sa[0])) die();
|
||||
if (!stralloc_0(&localname)) die();
|
||||
case_lowers(localname.s);
|
||||
if (!env_put2("TCPLOCALHOST",localname.s)) die();
|
||||
|
|
@ -99,12 +102,13 @@ char *argv[];
|
|||
temp[ip_fmt(temp,&ipremote)] = 0;
|
||||
if (!env_put2("TCPREMOTEIP",temp)) die();
|
||||
|
||||
switch(dns_ptr(&remotename,&ipremote))
|
||||
switch(dns_ptr(&ssa,&ipremote))
|
||||
{
|
||||
case DNS_MEM: die();
|
||||
case DNS_SOFT:
|
||||
if (!stralloc_copys(&remotename,"softdnserror")) die();
|
||||
case 0:
|
||||
if (!stralloc_copy(&remotename,&ssa.sa[0])) die();
|
||||
if (!stralloc_0(&remotename)) die();
|
||||
case_lowers(remotename.s);
|
||||
if (!env_put2("TCPREMOTEHOST",remotename.s)) die();
|
||||
|
|
|
|||
Loading…
Reference in a new issue