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
|
BLURB3
|
||||||
BLURB4
|
BLURB4
|
||||||
README
|
README
|
||||||
|
README.auth
|
||||||
FAQ
|
FAQ
|
||||||
INSTALL
|
INSTALL
|
||||||
INSTALL.alias
|
INSTALL.alias
|
||||||
|
|
@ -40,6 +41,7 @@ TARGETS
|
||||||
Makefile
|
Makefile
|
||||||
BIN.README
|
BIN.README
|
||||||
BIN.Makefile
|
BIN.Makefile
|
||||||
|
LICENSE.authentication
|
||||||
idedit.c
|
idedit.c
|
||||||
conf-break
|
conf-break
|
||||||
auto_break.h
|
auto_break.h
|
||||||
|
|
@ -136,6 +138,8 @@ dnsfq.c
|
||||||
dnsip.c
|
dnsip.c
|
||||||
dnsmxip.c
|
dnsmxip.c
|
||||||
dnsptr.c
|
dnsptr.c
|
||||||
|
dnstxt.c
|
||||||
|
spfquery.c
|
||||||
hostname.c
|
hostname.c
|
||||||
ipmeprint.c
|
ipmeprint.c
|
||||||
tcp-env.c
|
tcp-env.c
|
||||||
|
|
@ -336,13 +340,16 @@ envread.c
|
||||||
byte.h
|
byte.h
|
||||||
byte_chr.c
|
byte_chr.c
|
||||||
byte_copy.c
|
byte_copy.c
|
||||||
|
byte_cspn.c
|
||||||
byte_cr.c
|
byte_cr.c
|
||||||
byte_diff.c
|
byte_diff.c
|
||||||
byte_rchr.c
|
byte_rchr.c
|
||||||
|
byte_rcspn.c
|
||||||
byte_zero.c
|
byte_zero.c
|
||||||
str.h
|
str.h
|
||||||
str_chr.c
|
str_chr.c
|
||||||
str_cpy.c
|
str_cpy.c
|
||||||
|
str_cpyb.c
|
||||||
str_diff.c
|
str_diff.c
|
||||||
str_diffn.c
|
str_diffn.c
|
||||||
str_len.c
|
str_len.c
|
||||||
|
|
@ -402,6 +409,8 @@ date822fmt.h
|
||||||
date822fmt.c
|
date822fmt.c
|
||||||
dns.h
|
dns.h
|
||||||
dns.c
|
dns.c
|
||||||
|
spf.h
|
||||||
|
spf.c
|
||||||
trylsock.c
|
trylsock.c
|
||||||
tryrsolv.c
|
tryrsolv.c
|
||||||
ip.h
|
ip.h
|
||||||
|
|
@ -432,3 +441,12 @@ maildir.c
|
||||||
tcp-environ.5
|
tcp-environ.5
|
||||||
constmap.h
|
constmap.h
|
||||||
constmap.c
|
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
|
|
||||||
195
Makefile
195
Makefile
|
|
@ -140,14 +140,6 @@ base64.o: \
|
||||||
compile base64.c base64.h stralloc.h substdio.h str.h
|
compile base64.c base64.h stralloc.h substdio.h str.h
|
||||||
./compile base64.c
|
./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: \
|
||||||
binm1.sh conf-qmail
|
binm1.sh conf-qmail
|
||||||
cat binm1.sh \
|
cat binm1.sh \
|
||||||
|
|
@ -215,6 +207,10 @@ byte_cr.o: \
|
||||||
compile byte_cr.c byte.h
|
compile byte_cr.c byte.h
|
||||||
./compile byte_cr.c
|
./compile byte_cr.c
|
||||||
|
|
||||||
|
byte_cspn.o: \
|
||||||
|
compile byte_cspn.c byte.h
|
||||||
|
./compile byte_cspn.c
|
||||||
|
|
||||||
byte_diff.o: \
|
byte_diff.o: \
|
||||||
compile byte_diff.c byte.h
|
compile byte_diff.c byte.h
|
||||||
./compile byte_diff.c
|
./compile byte_diff.c
|
||||||
|
|
@ -223,6 +219,10 @@ byte_rchr.o: \
|
||||||
compile byte_rchr.c byte.h
|
compile byte_rchr.c byte.h
|
||||||
./compile byte_rchr.c
|
./compile byte_rchr.c
|
||||||
|
|
||||||
|
byte_rcspn.o: \
|
||||||
|
compile byte_rcspn.c byte.h
|
||||||
|
./compile byte_rcspn.c
|
||||||
|
|
||||||
byte_zero.o: \
|
byte_zero.o: \
|
||||||
compile byte_zero.c byte.h
|
compile byte_zero.c byte.h
|
||||||
./compile byte_zero.c
|
./compile byte_zero.c
|
||||||
|
|
@ -405,84 +405,96 @@ compile trydrent.c direntry.h1 direntry.h2
|
||||||
rm -f trydrent.o
|
rm -f trydrent.o
|
||||||
|
|
||||||
dns.lib: \
|
dns.lib: \
|
||||||
tryrsolv.c compile load socket.lib dns.o ipalloc.o ip.o stralloc.a \
|
tryrsolv.c compile load socket.lib dns.o ipalloc.o strsalloc.o ip.o \
|
||||||
alloc.a error.a fs.a str.a
|
stralloc.a alloc.a error.a fs.a str.a
|
||||||
( ( ./compile tryrsolv.c && ./load tryrsolv dns.o \
|
( ( ./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 \
|
-lresolv `cat socket.lib` ) >/dev/null 2>&1 \
|
||||||
&& echo -lresolv || exit 0 ) > dns.lib
|
&& echo -lresolv || exit 0 ) > dns.lib
|
||||||
rm -f tryrsolv.o tryrsolv
|
rm -f tryrsolv.o tryrsolv
|
||||||
|
|
||||||
dns.o: \
|
dns.o: \
|
||||||
compile dns.c ip.h ipalloc.h ip.h gen_alloc.h fmt.h alloc.h str.h \
|
compile dns.c ip.h ipalloc.h strsalloc.h gen_alloc.h fmt.h alloc.h \
|
||||||
stralloc.h gen_alloc.h dns.h case.h
|
str.h stralloc.h dns.h case.h
|
||||||
./compile dns.c
|
./compile dns.c
|
||||||
|
|
||||||
dnscname: \
|
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
|
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 \
|
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||||
socket.lib`
|
socket.lib`
|
||||||
|
|
||||||
dnscname.o: \
|
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
|
gen_alloc.h dns.h dnsdoe.h readwrite.h exit.h
|
||||||
./compile dnscname.c
|
./compile dnscname.c
|
||||||
|
|
||||||
dnsdoe.o: \
|
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
|
./compile dnsdoe.c
|
||||||
|
|
||||||
dnsfq: \
|
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
|
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 \
|
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||||
socket.lib`
|
socket.lib`
|
||||||
|
|
||||||
dnsfq.o: \
|
dnsfq.o: \
|
||||||
compile dnsfq.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
|
compile dnsfq.c substdio.h subfd.h stralloc.h gen_alloc.h \
|
||||||
dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h
|
dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h exit.h
|
||||||
./compile dnsfq.c
|
./compile dnsfq.c
|
||||||
|
|
||||||
dnsip: \
|
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
|
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 \
|
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||||
socket.lib`
|
socket.lib`
|
||||||
|
|
||||||
dnsip.o: \
|
dnsip.o: \
|
||||||
compile dnsip.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
|
compile dnsip.c substdio.h subfd.h stralloc.h gen_alloc.h \
|
||||||
dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h
|
dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h exit.h
|
||||||
./compile dnsip.c
|
./compile dnsip.c
|
||||||
|
|
||||||
dnsmxip: \
|
dnsmxip: \
|
||||||
load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o now.o stralloc.a alloc.a \
|
load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o now.o stralloc.a \
|
||||||
substdio.a error.a str.a fs.a dns.lib socket.lib
|
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 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 \
|
stralloc.a alloc.a substdio.a error.a str.a fs.a `cat \
|
||||||
dns.lib` `cat socket.lib`
|
dns.lib` `cat socket.lib`
|
||||||
|
|
||||||
dnsmxip.o: \
|
dnsmxip.o: \
|
||||||
compile dnsmxip.c substdio.h subfd.h substdio.h stralloc.h \
|
compile dnsmxip.c substdio.h subfd.h stralloc.h \
|
||||||
gen_alloc.h fmt.h dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h \
|
gen_alloc.h fmt.h dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h \
|
||||||
now.h datetime.h exit.h
|
now.h datetime.h exit.h
|
||||||
./compile dnsmxip.c
|
./compile dnsmxip.c
|
||||||
|
|
||||||
dnsptr: \
|
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
|
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 \
|
alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \
|
||||||
socket.lib`
|
socket.lib`
|
||||||
|
|
||||||
dnsptr.o: \
|
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
|
str.h scan.h dns.h dnsdoe.h ip.h exit.h
|
||||||
./compile dnsptr.c
|
./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.0: \
|
||||||
dot-qmail.5
|
dot-qmail.5
|
||||||
nroff -man dot-qmail.5 > dot-qmail.0
|
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 auto_qmail.h auto_split.h auto_uids.h fmt.h fifo.h
|
||||||
./compile hier.c
|
./compile hier.c
|
||||||
|
|
||||||
|
hmac_md5.o : \
|
||||||
|
compile hmac_md5.c hmac_md5.h global.h
|
||||||
|
./compile hmac_md5.c
|
||||||
|
|
||||||
home: \
|
home: \
|
||||||
home.sh conf-qmail
|
home.sh conf-qmail
|
||||||
cat home.sh \
|
cat home.sh \
|
||||||
|
|
@ -789,24 +805,24 @@ compile ip.c fmt.h scan.h ip.h
|
||||||
./compile ip.c
|
./compile ip.c
|
||||||
|
|
||||||
ipalloc.o: \
|
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
|
gen_alloc.h
|
||||||
./compile ipalloc.c
|
./compile ipalloc.c
|
||||||
|
|
||||||
ipme.o: \
|
ipme.o: \
|
||||||
compile ipme.c hassalen.h byte.h ip.h ipalloc.h ip.h gen_alloc.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
|
stralloc.h gen_alloc.h ipme.h ip.h ipalloc.h strsalloc.h
|
||||||
./compile ipme.c
|
./compile ipme.c
|
||||||
|
|
||||||
ipmeprint: \
|
ipmeprint: \
|
||||||
load ipmeprint.o ipme.o ip.o ipalloc.o stralloc.a alloc.a substdio.a \
|
load ipmeprint.o ipme.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
|
||||||
error.a str.a fs.a socket.lib
|
substdio.a error.a str.a fs.a socket.lib
|
||||||
./load ipmeprint ipme.o ip.o ipalloc.o stralloc.a alloc.a \
|
./load ipmeprint ipme.o ip.o ipalloc.o strsalloc.o stralloc.a \
|
||||||
substdio.a error.a str.a fs.a `cat socket.lib`
|
alloc.a substdio.a error.a str.a fs.a `cat socket.lib`
|
||||||
|
|
||||||
ipmeprint.o: \
|
ipmeprint.o: \
|
||||||
compile ipmeprint.c subfd.h substdio.h substdio.h ip.h ipme.h ip.h \
|
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
|
./compile ipmeprint.c
|
||||||
|
|
||||||
it: \
|
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-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \
|
||||||
qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \
|
qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \
|
||||||
qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \
|
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 \
|
forward preline condredirect bouncesaying except maildirmake \
|
||||||
maildir2mbox maildirwatch qail elq pinq idedit install-big install \
|
maildir2mbox maildirwatch qail elq pinq idedit install-big install \
|
||||||
instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
|
instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
|
||||||
binm3 binm3+df
|
binm3 binm3+df spfquery
|
||||||
|
|
||||||
load: \
|
load: \
|
||||||
make-load warn-auto.sh systype
|
make-load warn-auto.sh systype
|
||||||
|
|
@ -953,6 +969,10 @@ mbox.0: \
|
||||||
mbox.5
|
mbox.5
|
||||||
nroff -man mbox.5 > mbox.0
|
nroff -man mbox.5 > mbox.0
|
||||||
|
|
||||||
|
md5c.o : \
|
||||||
|
compile md5c.c md5.h
|
||||||
|
./compile md5c.c
|
||||||
|
|
||||||
myctime.o: \
|
myctime.o: \
|
||||||
compile myctime.c datetime.h fmt.h myctime.h
|
compile myctime.c datetime.h fmt.h myctime.h
|
||||||
./compile myctime.c
|
./compile myctime.c
|
||||||
|
|
@ -1451,14 +1471,14 @@ auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
|
||||||
|
|
||||||
qmail-remote: \
|
qmail-remote: \
|
||||||
load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
|
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 \
|
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 \
|
substdio.a error.a str.a fs.a auto_qmail.o \
|
||||||
base64.o md5c.o hmac_md5.o \
|
base64.o md5c.o hmac_md5.o \
|
||||||
dns.lib socket.lib
|
dns.lib socket.lib
|
||||||
./load qmail-remote control.o constmap.o timeoutread.o \
|
./load qmail-remote control.o constmap.o timeoutread.o \
|
||||||
timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.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 \
|
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
|
||||||
base64.o md5c.o hmac_md5.o \
|
base64.o md5c.o hmac_md5.o \
|
||||||
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
|
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
|
||||||
|
|
@ -1470,7 +1490,7 @@ qmail-remote.8
|
||||||
qmail-remote.o: \
|
qmail-remote.o: \
|
||||||
compile qmail-remote.c sig.h stralloc.h gen_alloc.h substdio.h \
|
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 \
|
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 \
|
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
|
tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h
|
||||||
./compile qmail-remote.c
|
./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 \
|
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 \
|
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_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
|
./compile qmail-showctl.c
|
||||||
|
|
||||||
qmail-smtpd: \
|
qmail-smtpd: \
|
||||||
load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
|
load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
|
||||||
timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
|
timeoutwrite.o ip.o ipme.o ipalloc.o strsalloc.o control.o constmap.o \
|
||||||
date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
|
received.o date822fmt.o now.o qmail.o spf.o dns.o cdb.a fd.a wait.a \
|
||||||
open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
|
datetime.a getln.a open.a sig.a case.a env.a stralloc.a alloc.a substdio.a \
|
||||||
fs.a auto_qmail.o base64.o socket.lib
|
error.a str.a fs.a auto_qmail.o base64.o socket.lib dns.lib
|
||||||
./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
|
./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
|
||||||
timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
|
timeoutwrite.o ip.o ipme.o ipalloc.o strsalloc.o control.o \
|
||||||
received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
|
constmap.o received.o date822fmt.o now.o qmail.o spf.o dns.o cdb.a \
|
||||||
datetime.a getln.a open.a sig.a case.a env.a stralloc.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 \
|
alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o \
|
||||||
socket.lib`
|
str.a `cat socket.lib` `cat dns.lib`
|
||||||
|
|
||||||
qmail-smtpd.0: \
|
qmail-smtpd.0: \
|
||||||
qmail-smtpd.8
|
qmail-smtpd.8
|
||||||
|
|
@ -1566,9 +1586,9 @@ qmail-smtpd.8
|
||||||
qmail-smtpd.o: \
|
qmail-smtpd.o: \
|
||||||
compile qmail-smtpd.c sig.h readwrite.h stralloc.h gen_alloc.h \
|
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 \
|
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 \
|
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
|
./compile qmail-smtpd.c
|
||||||
|
|
||||||
qmail-start: \
|
qmail-start: \
|
||||||
|
|
@ -1760,6 +1780,12 @@ substdio.h alloc.h auto_qmail.h exit.h env.h str.h
|
||||||
setup: \
|
setup: \
|
||||||
it man
|
it man
|
||||||
./install
|
./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: \
|
sgetopt.o: \
|
||||||
compile sgetopt.c substdio.h subfd.h substdio.h sgetopt.h subgetopt.h \
|
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-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \
|
||||||
qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.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 \
|
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 \
|
sendmail.c qreceipt.c qsmhook.c qbiff.c forward.c preline.c predate.c \
|
||||||
except.c bouncesaying.c condredirect.c maildirmake.c maildir2mbox.c \
|
except.c bouncesaying.c condredirect.c maildirmake.c maildir2mbox.c \
|
||||||
maildirwatch.c splogger.c qail.sh elq.sh pinq.sh qmail-upq.sh \
|
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 \
|
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 \
|
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 \
|
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 \
|
byte_copy.c byte_cr.c byte_cspn.c byte_diff.c byte_rchr.c byte_rcspn.c \
|
||||||
str_chr.c str_cpy.c str_diff.c str_diffn.c str_len.c str_rchr.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 \
|
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 \
|
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 \
|
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 \
|
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 \
|
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 \
|
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 \
|
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 \
|
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
|
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
|
./chkspawn
|
||||||
./compile spawn.c
|
./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: \
|
splogger: \
|
||||||
load splogger.o substdio.a error.a str.a fs.a syslog.lib socket.lib
|
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 \
|
./load splogger substdio.a error.a str.a fs.a `cat \
|
||||||
|
|
@ -1927,12 +1971,12 @@ scan.h fmt.h
|
||||||
./compile splogger.c
|
./compile splogger.c
|
||||||
|
|
||||||
str.a: \
|
str.a: \
|
||||||
makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.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_diff.o byte_copy.o \
|
str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_cspn.o byte_rcspn.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
|
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: \
|
str_chr.o: \
|
||||||
compile str_chr.c str.h
|
compile str_chr.c str.h
|
||||||
|
|
@ -1942,6 +1986,10 @@ str_cpy.o: \
|
||||||
compile str_cpy.c str.h
|
compile str_cpy.c str.h
|
||||||
./compile str_cpy.c
|
./compile str_cpy.c
|
||||||
|
|
||||||
|
str_cpyb.o: \
|
||||||
|
compile str_cpyb.c str.h
|
||||||
|
./compile str_cpyb.c
|
||||||
|
|
||||||
str_diff.o: \
|
str_diff.o: \
|
||||||
compile str_diff.c str.h
|
compile str_diff.c str.h
|
||||||
./compile str_diff.c
|
./compile str_diff.c
|
||||||
|
|
@ -2021,6 +2069,11 @@ strerr_sys.o: \
|
||||||
compile strerr_sys.c error.h strerr.h
|
compile strerr_sys.c error.h strerr.h
|
||||||
./compile strerr_sys.c
|
./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: \
|
subfderr.o: \
|
||||||
compile subfderr.c readwrite.h substdio.h subfd.h substdio.h
|
compile subfderr.c readwrite.h substdio.h subfd.h substdio.h
|
||||||
./compile subfderr.c
|
./compile subfderr.c
|
||||||
|
|
@ -2081,11 +2134,11 @@ find-systype trycpp.c
|
||||||
|
|
||||||
tcp-env: \
|
tcp-env: \
|
||||||
load tcp-env.o dns.o remoteinfo.o timeoutread.o timeoutwrite.o \
|
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 \
|
timeoutconn.o ip.o ipalloc.o strsalloc.o case.a ndelay.a sig.a env.a \
|
||||||
stralloc.a alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib
|
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 \
|
./load tcp-env dns.o remoteinfo.o timeoutread.o \
|
||||||
timeoutwrite.o timeoutconn.o ip.o ipalloc.o case.a ndelay.a \
|
timeoutwrite.o timeoutconn.o ip.o ipalloc.o strsalloc.o case.a \
|
||||||
sig.a env.a getopt.a stralloc.a alloc.a substdio.a error.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`
|
str.a fs.a `cat dns.lib` `cat socket.lib`
|
||||||
|
|
||||||
tcp-env.0: \
|
tcp-env.0: \
|
||||||
|
|
|
||||||
10
TARGETS
10
TARGETS
|
|
@ -101,11 +101,14 @@ str_len.o
|
||||||
str_diff.o
|
str_diff.o
|
||||||
str_diffn.o
|
str_diffn.o
|
||||||
str_cpy.o
|
str_cpy.o
|
||||||
|
str_cpyb.o
|
||||||
str_chr.o
|
str_chr.o
|
||||||
str_rchr.o
|
str_rchr.o
|
||||||
str_start.o
|
str_start.o
|
||||||
byte_chr.o
|
byte_chr.o
|
||||||
byte_rchr.o
|
byte_rchr.o
|
||||||
|
byte_cspn.o
|
||||||
|
byte_rcspn.o
|
||||||
byte_diff.o
|
byte_diff.o
|
||||||
byte_copy.o
|
byte_copy.o
|
||||||
byte_cr.o
|
byte_cr.o
|
||||||
|
|
@ -172,8 +175,10 @@ timeoutwrite.o
|
||||||
timeoutconn.o
|
timeoutconn.o
|
||||||
tcpto.o
|
tcpto.o
|
||||||
dns.o
|
dns.o
|
||||||
|
spf.o
|
||||||
ip.o
|
ip.o
|
||||||
ipalloc.o
|
ipalloc.o
|
||||||
|
strsalloc.o
|
||||||
hassalen.h
|
hassalen.h
|
||||||
ipme.o
|
ipme.o
|
||||||
ndelay.o
|
ndelay.o
|
||||||
|
|
@ -215,6 +220,9 @@ qmail-inject.o
|
||||||
headerbody.o
|
headerbody.o
|
||||||
hfield.o
|
hfield.o
|
||||||
token822.o
|
token822.o
|
||||||
|
spf.o
|
||||||
|
spfquery.o
|
||||||
|
spfquery
|
||||||
qmail-inject
|
qmail-inject
|
||||||
predate.o
|
predate.o
|
||||||
predate
|
predate
|
||||||
|
|
@ -273,6 +281,8 @@ dnsip.o
|
||||||
dnsip
|
dnsip
|
||||||
dnsmxip.o
|
dnsmxip.o
|
||||||
dnsmxip
|
dnsmxip
|
||||||
|
dnstxt.o
|
||||||
|
dnstxt
|
||||||
dnsfq.o
|
dnsfq.o
|
||||||
dnsfq
|
dnsfq
|
||||||
hostname.o
|
hostname.o
|
||||||
|
|
|
||||||
2
byte.h
2
byte.h
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
extern unsigned int byte_chr();
|
extern unsigned int byte_chr();
|
||||||
extern unsigned int byte_rchr();
|
extern unsigned int byte_rchr();
|
||||||
|
extern unsigned int byte_cspn();
|
||||||
|
extern unsigned int byte_rcspn();
|
||||||
extern void byte_copy();
|
extern void byte_copy();
|
||||||
extern void byte_copyr();
|
extern void byte_copyr();
|
||||||
extern int byte_diff();
|
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();
|
extern int res_search();
|
||||||
#include "ip.h"
|
#include "ip.h"
|
||||||
#include "ipalloc.h"
|
#include "ipalloc.h"
|
||||||
|
#include "strsalloc.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include "alloc.h"
|
#include "alloc.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
@ -27,6 +28,7 @@ static unsigned char *responsepos;
|
||||||
static int numanswers;
|
static int numanswers;
|
||||||
static char name[MAXDNAME];
|
static char name[MAXDNAME];
|
||||||
static struct ip_address ip;
|
static struct ip_address ip;
|
||||||
|
static stralloc txt = {0};
|
||||||
unsigned short pref;
|
unsigned short pref;
|
||||||
|
|
||||||
static stralloc glue = {0};
|
static stralloc glue = {0};
|
||||||
|
|
@ -177,6 +179,49 @@ int wanttype;
|
||||||
return 0;
|
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)
|
void dns_init(flagsearch)
|
||||||
int flagsearch;
|
int flagsearch;
|
||||||
{
|
{
|
||||||
|
|
@ -194,7 +239,7 @@ stralloc *sa;
|
||||||
if (!sa->len) return loop;
|
if (!sa->len) return loop;
|
||||||
if (sa->s[sa->len - 1] == ']') return loop;
|
if (sa->s[sa->len - 1] == ']') return loop;
|
||||||
if (sa->s[sa->len - 1] == '.') { --sa->len; continue; }
|
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_MEM: return DNS_MEM;
|
||||||
case DNS_SOFT: return DNS_SOFT;
|
case DNS_SOFT: return DNS_SOFT;
|
||||||
|
|
@ -235,15 +280,18 @@ struct ip_address *ip;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dns_ptr(sa,ip)
|
static int dns_ptrplus(ssa,ip)
|
||||||
stralloc *sa;
|
strsalloc *ssa;
|
||||||
struct ip_address *ip;
|
struct ip_address *ip;
|
||||||
{
|
{
|
||||||
|
stralloc sa = {0};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM;
|
if (!stralloc_ready(&sa,iaafmt((char *) 0,ip))) return DNS_MEM;
|
||||||
sa->len = iaafmt(sa->s,ip);
|
sa.len = iaafmt(sa.s,ip);
|
||||||
switch(resolve(sa,T_PTR))
|
r = resolve(&sa,T_PTR);
|
||||||
|
alloc_free(sa.s);
|
||||||
|
switch(r)
|
||||||
{
|
{
|
||||||
case DNS_MEM: return DNS_MEM;
|
case DNS_MEM: return DNS_MEM;
|
||||||
case DNS_SOFT: return DNS_SOFT;
|
case DNS_SOFT: return DNS_SOFT;
|
||||||
|
|
@ -254,13 +302,35 @@ struct ip_address *ip;
|
||||||
if (r == DNS_SOFT) return DNS_SOFT;
|
if (r == DNS_SOFT) return DNS_SOFT;
|
||||||
if (r == 1)
|
if (r == 1)
|
||||||
{
|
{
|
||||||
if (!stralloc_copys(sa,name)) return DNS_MEM;
|
stralloc sa2 = {0};
|
||||||
return 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;
|
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)
|
static int dns_ipplus(ia,sa,pref)
|
||||||
ipalloc *ia;
|
ipalloc *ia;
|
||||||
stralloc *sa;
|
stralloc *sa;
|
||||||
|
|
@ -396,3 +466,49 @@ unsigned long random;
|
||||||
alloc_free(mx);
|
alloc_free(mx);
|
||||||
return flagsoft;
|
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_mxip();
|
||||||
int dns_ip();
|
int dns_ip();
|
||||||
int dns_ptr();
|
int dns_ptr();
|
||||||
|
int dns_txt();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
11
dnsfq.c
11
dnsfq.c
|
|
@ -5,15 +5,19 @@
|
||||||
#include "dnsdoe.h"
|
#include "dnsdoe.h"
|
||||||
#include "ip.h"
|
#include "ip.h"
|
||||||
#include "ipalloc.h"
|
#include "ipalloc.h"
|
||||||
|
#include "strsalloc.h"
|
||||||
#include "exit.h"
|
#include "exit.h"
|
||||||
|
|
||||||
stralloc sa = {0};
|
stralloc sa = {0};
|
||||||
|
strsalloc ssa = {0};
|
||||||
ipalloc ia = {0};
|
ipalloc ia = {0};
|
||||||
|
|
||||||
void main(argc,argv)
|
void main(argc,argv)
|
||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
{
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
if (!argv[1]) _exit(100);
|
if (!argv[1]) _exit(100);
|
||||||
|
|
||||||
if (!stralloc_copys(&sa,argv[1]))
|
if (!stralloc_copys(&sa,argv[1]))
|
||||||
|
|
@ -25,8 +29,11 @@ char **argv;
|
||||||
{
|
{
|
||||||
substdio_putsflush(subfderr,"no IP addresses\n"); _exit(100);
|
substdio_putsflush(subfderr,"no IP addresses\n"); _exit(100);
|
||||||
}
|
}
|
||||||
dnsdoe(dns_ptr(&sa,&ia.ix[0].ip));
|
dnsdoe(dns_ptr(&ssa,&ia.ix[0].ip));
|
||||||
substdio_putflush(subfdout,sa.s,sa.len);
|
for(j = 0;j < ssa.len;++j)
|
||||||
|
{
|
||||||
|
substdio_putflush(subfdout,ssa.sa[j].s,ssa.sa[j].len);
|
||||||
substdio_putsflush(subfdout,"\n");
|
substdio_putsflush(subfdout,"\n");
|
||||||
|
}
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
dnsptr.c
12
dnsptr.c
|
|
@ -6,22 +6,28 @@
|
||||||
#include "dns.h"
|
#include "dns.h"
|
||||||
#include "dnsdoe.h"
|
#include "dnsdoe.h"
|
||||||
#include "ip.h"
|
#include "ip.h"
|
||||||
|
#include "strsalloc.h"
|
||||||
#include "exit.h"
|
#include "exit.h"
|
||||||
|
|
||||||
stralloc sa = {0};
|
strsalloc ssa = {0};
|
||||||
struct ip_address ip;
|
struct ip_address ip;
|
||||||
|
|
||||||
void main(argc,argv)
|
void main(argc,argv)
|
||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
{
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
if (!argv[1]) _exit(100);
|
if (!argv[1]) _exit(100);
|
||||||
|
|
||||||
ip_scan(argv[1],&ip);
|
ip_scan(argv[1],&ip);
|
||||||
|
|
||||||
dns_init(0);
|
dns_init(0);
|
||||||
dnsdoe(dns_ptr(&sa,&ip));
|
dnsdoe(dns_ptr(&ssa,&ip));
|
||||||
substdio_putflush(subfdout,sa.s,sa.len);
|
for(j = 0;j < ssa.len;++j)
|
||||||
|
{
|
||||||
|
substdio_putflush(subfdout,ssa.sa[j].s,ssa.sa[j].len);
|
||||||
substdio_putsflush(subfdout,"\n");
|
substdio_putsflush(subfdout,"\n");
|
||||||
|
}
|
||||||
_exit(0);
|
_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-start",auto_uido,auto_gidq,0700);
|
||||||
c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711);
|
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-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-rspawn",auto_uido,auto_gidq,0711);
|
||||||
c(auto_qmail,"bin","qmail-clean",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);
|
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","tcp-env",auto_uido,auto_gidq,0755);
|
||||||
c(auto_qmail,"bin","qreceipt",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","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","forward",auto_uido,auto_gidq,0755);
|
||||||
c(auto_qmail,"bin","preline",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);
|
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 rcpthosts \fR(none) \fRqmail-smtpd
|
||||||
.I smtpgreeting \fIme \fRqmail-smtpd
|
.I smtpgreeting \fIme \fRqmail-smtpd
|
||||||
.I smtproutes \fR(none) \fRqmail-remote
|
.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 timeoutconnect \fR60 \fRqmail-remote
|
||||||
.I timeoutremote \fR1200 \fRqmail-remote
|
.I timeoutremote \fR1200 \fRqmail-remote
|
||||||
.I timeoutsmtpd \fR1200 \fRqmail-smtpd
|
.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
|
and does not follow the
|
||||||
.B getopt
|
.B getopt
|
||||||
standard.
|
standard.
|
||||||
|
|
||||||
.SH TRANSPARENCY
|
.SH TRANSPARENCY
|
||||||
End-of-file in SMTP is encoded as dot CR LF.
|
End-of-file in SMTP is encoded as dot CR LF.
|
||||||
A dot at the beginning of a line is encoded as dot dot.
|
A dot at the beginning of a line is encoded as dot dot.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include "auto_patrn.h"
|
#include "auto_patrn.h"
|
||||||
#include "auto_spawn.h"
|
#include "auto_spawn.h"
|
||||||
#include "auto_split.h"
|
#include "auto_split.h"
|
||||||
|
#include "spf.h"
|
||||||
|
|
||||||
stralloc me = {0};
|
stralloc me = {0};
|
||||||
int meok;
|
int meok;
|
||||||
|
|
@ -258,6 +259,10 @@ void main()
|
||||||
|
|
||||||
do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 ");
|
do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 ");
|
||||||
do_lst("smtproutes","No artificial SMTP routes.","SMTP route: ","");
|
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("timeoutconnect","60","SMTP client connection timeout is "," seconds");
|
||||||
do_int("timeoutremote","1200","SMTP client data timeout is "," seconds");
|
do_int("timeoutremote","1200","SMTP client data timeout is "," seconds");
|
||||||
do_int("timeoutsmtpd","1200","SMTP server 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,"rcpthosts")) continue;
|
||||||
if (str_equal(d->d_name,"smtpgreeting")) continue;
|
if (str_equal(d->d_name,"smtpgreeting")) continue;
|
||||||
if (str_equal(d->d_name,"smtproutes")) 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,"timeoutconnect")) continue;
|
||||||
if (str_equal(d->d_name,"timeoutremote")) continue;
|
if (str_equal(d->d_name,"timeoutremote")) continue;
|
||||||
if (str_equal(d->d_name,"timeoutsmtpd")) 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.
|
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"
|
.SH "SEE ALSO"
|
||||||
tcp-env(1),
|
tcp-env(1),
|
||||||
tcp-environ(5),
|
tcp-environ(5),
|
||||||
|
|
|
||||||
111
qmail-smtpd.c
111
qmail-smtpd.c
|
|
@ -24,12 +24,13 @@
|
||||||
#include "timeoutwrite.h"
|
#include "timeoutwrite.h"
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
#include "wait.h"
|
#include "wait.h"
|
||||||
|
#include "spf.h"
|
||||||
|
|
||||||
#define AUTHSLEEP 5
|
#define AUTHSLEEP 5
|
||||||
|
|
||||||
#define MAXHOPS 100
|
#define MAXHOPS 100
|
||||||
unsigned int databytes = 0;
|
unsigned int databytes = 0;
|
||||||
int timeout = 1200;
|
int timeout = 1200;
|
||||||
|
unsigned int spfbehavior = 0;
|
||||||
|
|
||||||
int safewrite(fd,buf,len) int fd; char *buf; int len;
|
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_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_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 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_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"); }
|
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"); }
|
void err_submission() { out("530 Authorization required (#5.7.1) \r\n"); }
|
||||||
|
|
||||||
stralloc greeting = {0};
|
stralloc greeting = {0};
|
||||||
|
stralloc spflocal = {0};
|
||||||
|
stralloc spfguess = {0};
|
||||||
|
stralloc spfexp = {0};
|
||||||
|
|
||||||
void smtp_greet(code) char *code;
|
void smtp_greet(code) char *code;
|
||||||
{
|
{
|
||||||
|
|
@ -84,7 +88,7 @@ void smtp_greet(code) char *code;
|
||||||
}
|
}
|
||||||
void smtp_help(arg) char *arg;
|
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;
|
void smtp_quit(arg) char *arg;
|
||||||
{
|
{
|
||||||
|
|
@ -128,6 +132,7 @@ void setup()
|
||||||
if (liphostok == -1) die_control();
|
if (liphostok == -1) die_control();
|
||||||
if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
|
if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
|
||||||
if (timeout <= 0) timeout = 1;
|
if (timeout <= 0) timeout = 1;
|
||||||
|
|
||||||
if (rcpthosts_init() == -1) die_control();
|
if (rcpthosts_init() == -1) die_control();
|
||||||
|
|
||||||
bmfok = control_readfile(&bmf,"control/badmailfrom",0);
|
bmfok = control_readfile(&bmf,"control/badmailfrom",0);
|
||||||
|
|
@ -141,6 +146,19 @@ void setup()
|
||||||
if (!(databytes + 1)) --databytes;
|
if (!(databytes + 1)) --databytes;
|
||||||
|
|
||||||
protocol = "SMTP";
|
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");
|
remoteip = env_get("TCPREMOTEIP");
|
||||||
if (!remoteip) remoteip = "unknown";
|
if (!remoteip) remoteip = "unknown";
|
||||||
local = env_get("TCPLOCALHOST");
|
local = env_get("TCPLOCALHOST");
|
||||||
|
|
@ -166,6 +184,7 @@ void setup()
|
||||||
dohelo(remotehost);
|
dohelo(remotehost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
|
stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
|
||||||
|
|
||||||
int addrparse(arg)
|
int addrparse(arg)
|
||||||
|
|
@ -247,11 +266,13 @@ int addrallowed()
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *auth;
|
|
||||||
int seenauth = 0;
|
int seenauth = 0;
|
||||||
int seenmail = 0;
|
int seenmail = 0;
|
||||||
int flagbarf; /* defined if seenmail */
|
int flagbarf; /* defined if seenmail */
|
||||||
int flagsize;
|
int flagsize;
|
||||||
|
int flagbarfspf;
|
||||||
|
stralloc spfbarfmsg = {0};
|
||||||
stralloc mailfrom = {0};
|
stralloc mailfrom = {0};
|
||||||
stralloc rcptto = {0};
|
stralloc rcptto = {0};
|
||||||
stralloc fuser = {0};
|
stralloc fuser = {0};
|
||||||
|
|
@ -323,8 +344,7 @@ void smtp_ehlo(arg) char *arg;
|
||||||
{
|
{
|
||||||
char size[FMT_ULONG];
|
char size[FMT_ULONG];
|
||||||
size[fmt_ulong(size,(unsigned int) databytes)] = 0;
|
size[fmt_ulong(size,(unsigned int) databytes)] = 0;
|
||||||
smtp_greet("250-");
|
smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
|
||||||
out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
|
|
||||||
if (smtpauth == 1 || smtpauth == 11) out("250-AUTH LOGIN PLAIN\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 == 2 || smtpauth == 12) out("250-AUTH CRAM-MD5\r\n");
|
||||||
if (smtpauth == 3 || smtpauth == 13) out("250-AUTH LOGIN PLAIN 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;
|
mailfrom.len = 0; rcptto.len = 0;
|
||||||
out("250 flushed\r\n");
|
out("250 flushed\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void smtp_mail(arg) char *arg;
|
void smtp_mail(arg) char *arg;
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
if (smtpauth)
|
if (smtpauth)
|
||||||
if (smtpauth > 10 && !seenauth) { err_submission(); return; }
|
if (smtpauth > 10 && !seenauth) { err_submission(); return; }
|
||||||
|
|
||||||
if (!addrparse(arg)) { err_syntax(); return; }
|
if (!addrparse(arg)) { err_syntax(); return; }
|
||||||
flagsize = 0;
|
flagsize = 0;
|
||||||
mailfrom_parms(arg);
|
mailfrom_parms(arg);
|
||||||
if (flagsize) { err_size(); return; }
|
if (flagsize) { err_size(); return; }
|
||||||
flagbarf = bmfcheck();
|
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;
|
seenmail = 1;
|
||||||
if (!stralloc_copys(&rcptto,"")) die_nomem();
|
if (!stralloc_copys(&rcptto,"")) die_nomem();
|
||||||
if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
|
if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
|
||||||
if (!stralloc_0(&mailfrom)) die_nomem();
|
if (!stralloc_0(&mailfrom)) die_nomem();
|
||||||
out("250 ok\r\n");
|
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; {
|
void smtp_rcpt(arg) char *arg; {
|
||||||
if (!seenmail) { err_wantmail(); return; }
|
if (!seenmail) { err_wantmail(); return; }
|
||||||
if (!addrparse(arg)) { err_syntax(); return; }
|
if (!addrparse(arg)) { err_syntax(); return; }
|
||||||
if (flagbarf) { err_bmf(); return; }
|
if (flagbarf) { err_bmf(); return; }
|
||||||
|
if (flagbarfspf) { err_spf(); return; }
|
||||||
if (relayclient) {
|
if (relayclient) {
|
||||||
--addr.len;
|
--addr.len;
|
||||||
if (!stralloc_cats(&addr,relayclient)) die_nomem();
|
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];
|
char accept_buf[FMT_ULONG];
|
||||||
void acceptmessage(qp) unsigned long qp;
|
void acceptmessage(qp) unsigned long qp;
|
||||||
{
|
{
|
||||||
|
|
@ -484,6 +582,7 @@ void smtp_data(arg) char *arg; {
|
||||||
out("354 go ahead\r\n");
|
out("354 go ahead\r\n");
|
||||||
|
|
||||||
received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
|
received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
|
||||||
|
spfreceived();
|
||||||
blast(&hops);
|
blast(&hops);
|
||||||
hops = (hops >= MAXHOPS);
|
hops = (hops >= MAXHOPS);
|
||||||
if (hops) qmail_fail(&qqt);
|
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
|
#define STR_H
|
||||||
|
|
||||||
extern unsigned int str_copy();
|
extern unsigned int str_copy();
|
||||||
|
extern unsigned int str_copyb();
|
||||||
extern int str_diff();
|
extern int str_diff();
|
||||||
extern int str_diffn();
|
extern int str_diffn();
|
||||||
extern unsigned int str_len();
|
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 "scan.h"
|
||||||
#include "subgetopt.h"
|
#include "subgetopt.h"
|
||||||
#include "ip.h"
|
#include "ip.h"
|
||||||
|
#include "strsalloc.h"
|
||||||
#include "dns.h"
|
#include "dns.h"
|
||||||
#include "byte.h"
|
#include "byte.h"
|
||||||
#include "remoteinfo.h"
|
#include "remoteinfo.h"
|
||||||
|
|
@ -34,6 +35,7 @@ void main(argc,argv)
|
||||||
int argc;
|
int argc;
|
||||||
char *argv[];
|
char *argv[];
|
||||||
{
|
{
|
||||||
|
strsalloc ssa = {0};
|
||||||
int dummy;
|
int dummy;
|
||||||
char *proto;
|
char *proto;
|
||||||
int opt;
|
int opt;
|
||||||
|
|
@ -74,12 +76,13 @@ char *argv[];
|
||||||
temp[ip_fmt(temp,&iplocal)] = 0;
|
temp[ip_fmt(temp,&iplocal)] = 0;
|
||||||
if (!env_put2("TCPLOCALIP",temp)) die();
|
if (!env_put2("TCPLOCALIP",temp)) die();
|
||||||
|
|
||||||
switch(dns_ptr(&localname,&iplocal))
|
switch(dns_ptr(&ssa,&iplocal))
|
||||||
{
|
{
|
||||||
case DNS_MEM: die();
|
case DNS_MEM: die();
|
||||||
case DNS_SOFT:
|
case DNS_SOFT:
|
||||||
if (!stralloc_copys(&localname,"softdnserror")) die();
|
if (!stralloc_copys(&localname,"softdnserror")) die();
|
||||||
case 0:
|
case 0:
|
||||||
|
if (!stralloc_copy(&localname,&ssa.sa[0])) die();
|
||||||
if (!stralloc_0(&localname)) die();
|
if (!stralloc_0(&localname)) die();
|
||||||
case_lowers(localname.s);
|
case_lowers(localname.s);
|
||||||
if (!env_put2("TCPLOCALHOST",localname.s)) die();
|
if (!env_put2("TCPLOCALHOST",localname.s)) die();
|
||||||
|
|
@ -99,12 +102,13 @@ char *argv[];
|
||||||
temp[ip_fmt(temp,&ipremote)] = 0;
|
temp[ip_fmt(temp,&ipremote)] = 0;
|
||||||
if (!env_put2("TCPREMOTEIP",temp)) die();
|
if (!env_put2("TCPREMOTEIP",temp)) die();
|
||||||
|
|
||||||
switch(dns_ptr(&remotename,&ipremote))
|
switch(dns_ptr(&ssa,&ipremote))
|
||||||
{
|
{
|
||||||
case DNS_MEM: die();
|
case DNS_MEM: die();
|
||||||
case DNS_SOFT:
|
case DNS_SOFT:
|
||||||
if (!stralloc_copys(&remotename,"softdnserror")) die();
|
if (!stralloc_copys(&remotename,"softdnserror")) die();
|
||||||
case 0:
|
case 0:
|
||||||
|
if (!stralloc_copy(&remotename,&ssa.sa[0])) die();
|
||||||
if (!stralloc_0(&remotename)) die();
|
if (!stralloc_0(&remotename)) die();
|
||||||
case_lowers(remotename.s);
|
case_lowers(remotename.s);
|
||||||
if (!env_put2("TCPREMOTEHOST",remotename.s)) die();
|
if (!env_put2("TCPREMOTEHOST",remotename.s)) die();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue