Commit e3c98644 authored by Sam Varshavchik's avatar Sam Varshavchik

couriermlm: implement smtp prefiltering, and default Unicode blocking.

parent 71f64f05
2018-07-31 Sam Varshavchik <mrsam@courier-mta.com>
* couriermlm: Implement smtp prefiltering. Implement blocking of
Unicode messages and E-mail addresses, by default.
* rfc2045/reformime: parse utf-8 address types in DSNs.
2018-07-29 Sam Varshavchik <mrsam@courier-mta.com>
* courier: implement "utf-8" address type in delivery status
......
......@@ -14,6 +14,10 @@
/courierd.dist.in
/courierldapaliasd
/couriermlm
/couriermlm-rcptfilter-ctlmsg
/couriermlm-rcptfilter-msg
/couriermlm-smtpfilter-ctlmsg
/couriermlm-smtpfilter-msg
/courierpop3d
/courierpop3login
/couriertcpd
......
......@@ -128,6 +128,11 @@ mlmdata_DATA=\
warn1text.tmpl \
warn2msg.tmpl \
webmlm.tmpl \
\
couriermlm-rcptfilter-ctlmsg \
couriermlm-rcptfilter-msg \
couriermlm-smtpfilter-ctlmsg \
couriermlm-smtpfilter-msg \
\
style.css.tmpl \
webmlmconfirm.html \
......@@ -343,7 +348,9 @@ courierpop3login$(EXEEXT): ../libs/imap/pop3login$(EXEEXT)
couriermlm_SOURCES= cmlm.C cmlm.h cmlm2.C cmlm3.C cmlmarchive.C cmlmarchive.h \
cmlmbounce.C cmlmbounce.h cmlmcleanup.C cmlmcleanup.h cmlmcmdmisc.C \
cmlmcmdmisc.h cmlmdigest.C cmlmfetch.C cmlmfetch.h cmlmmoderate.C \
cmlmcmdmisc.h cmlmdigest.C cmlmfetch.C cmlmfetch.h \
cmlmfilter.C cmlmfilter.h \
cmlmmoderate.C \
cmlmmoderate.h cmlmstartmail.C cmlmstartmail.h cmlmsublist.C \
cmlmsublist.h cmlmsubunsub.C cmlmsubunsub.h cmlmsubunsubmsg.C \
cmlmsubunsubmsg.h
......
/*
** Copyright 2000-2009 Double Precision, Inc.
** Copyright 2000-2018 Double Precision, Inc.
** See COPYING for distribution information.
*/
......@@ -7,6 +7,7 @@
#include "afx/afx.h"
#include "rfc822/rfc822.h"
#include "rfc2045/rfc2045.h"
#include "random128/random128.h"
#include "numlib/numlib.h"
#include "dbobj.h"
......@@ -45,6 +46,7 @@
#include "cmlmbounce.h"
#include "cmlmcleanup.h"
#include "cmlmfetch.h"
#include "cmlmfilter.h"
#include <string>
#include <vector>
......@@ -97,17 +99,66 @@ static struct ncmdtab {
{"digest", cmddigest},
};
static struct filtercmdtab {
const char *cmdname;
int (*cmdfunc)();
} filtercmds[]=
{
{"rcptfilter-msg", rcptfilter_msg},
{"smtpfilter-msg", smtpfilter_msg},
{"rcptfilter-ctlmsg", rcptfilter_ctlmsg},
{"smtpfilter-ctlmsg", smtpfilter_ctlmsg},
};
int main(int argc, char **argv)
{
if (argc < 3) usage();
setlocale(LC_ALL, "");
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_DFL);
const char *cmd=argv[1];
const char *dir=argv[2];
size_t i;
if (argc == 2)
{
int (*cmdfunc)()=0;
for (i=0; i<sizeof(filtercmds)/sizeof(filtercmds[0]); ++i)
{
if (strcmp(filtercmds[i].cmdname, argv[1]) == 0)
{
cmdfunc=filtercmds[i].cmdfunc;
break;
}
}
if (!cmdfunc)
{
exit(1);
}
const char *listdir=getenv("LISTDIR");
if (!listdir || strchr(listdir, '.'))
{
std::cout << "500 Internal configuration error."
<< std::endl;
exit(1);
}
if (chdir(listdir) < 0)
{
std::cout << "500 " << listdir << ": "
<< strerror(errno) << std::endl;
exit(1);
}
exit((*cmdfunc)());
}
if (argc < 3) usage();
const char *cmd=argv[1];
const char *dir=argv[2];
if (strcmp(cmd, "create") == 0)
{
......@@ -136,8 +187,6 @@ const char *dir=argv[2];
exit(EX_SOFTWARE);
}
unsigned i;
std::vector<std::string> argv_cpy;
argv_cpy.insert(argv_cpy.end(), argv+3, argv+argc);
......@@ -157,26 +206,40 @@ unsigned i;
static int help();
const char *is_cmd(const char *default_env,
const char *cmd)
{
size_t l=strlen(cmd);
if (strncasecmp(default_env, cmd, l) == 0)
{
default_env += l;
if (*default_env == 0 || (*default_env == '-' &&
*default_env != 0))
return default_env;
}
return NULL;
}
static int cmdctlmsg(const std::vector<std::string> &)
{
const char *cmd=getenv("DEFAULT");
const char *cmd=getenv("DEFAULT");
const char *ext;
if (!cmd) cmd="";
if (strcasecmp(cmd, "help") == 0)
return (help());
if (strncasecmp(cmd, "subscribe", 9) == 0)
if ((ext=is_cmd(cmd, "subscribe")) != 0)
{
cmd += 9;
if (*cmd == 0 || (*cmd == '-' && *++cmd != 0))
return (dosub(cmd));
return dosub(ext);
}
else if (strncasecmp(cmd, "alias-subscribe", 15) == 0)
else if ((ext=is_cmd(cmd, "alias-subscribe")) != 0)
{
cmd += 15;
if (*cmd == 0 || (*cmd == '-' && *++cmd != 0))
return (doalias(cmd));
return (doalias(ext));
}
else if (strncasecmp(cmd, "modsubconfirm-", 14) == 0)
{
......@@ -661,7 +724,42 @@ void post(std::istream &fs, const char *verp_ret)
mail.Send();
}
struct savemsg_totmpfile : public savemsg_sink {
std::ostream &o;
savemsg_totmpfile(std::ostream &oArg) : o(oArg) {}
void saveline(const std::string &s)
{
o << s << "\n";
}
void error(const std::string &errmsg)
{
std::cout << errmsg << std::endl;
}
};
static int savemsg(std::istream &msgs, std::ostream &fs)
{
savemsg_totmpfile ttf(fs);
int rc=savemsg(msgs, ttf);
fs.flush();
fs.seekp(0);
if (fs.bad() || fs.fail())
{
perror( "write" );
return (EX_TEMPFAIL);
}
std::cout << std::flush;
return rc;
}
int savemsg(std::istream &msgs, savemsg_sink &sink)
{
const char *dt=getenv("DTLINE");
std::string buf;
......@@ -669,12 +767,13 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
int n;
std::string keyword= cmdget_s("KEYWORD"), keywords;
int adminrequest=0;
struct rfc2045 *rfc2045_parser=rfc2045_alloc();
if (keyword.size() > 0)
keywords="["+keyword+"]";
if (dt && *dt)
fs << dt << std::endl;
sink.saveline(dt);
{
std::ifstream ifs(HEADERADD);
......@@ -684,7 +783,7 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
std::string line;
while (std::getline(ifs, line).good())
fs << line << std::endl;
sink.saveline(line);
}
}
......@@ -732,7 +831,7 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
}
if (!dodelete)
fs << buf << std::endl;
sink.saveline(buf);
continue;
}
......@@ -797,16 +896,21 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
from=buf.substr(colon_pos);
if (!dodelete)
fs << buf << std::endl;
{
sink.saveline(buf);
rfc2045_parse(rfc2045_parser, buf.c_str(), buf.size());
rfc2045_parse(rfc2045_parser, "\n", 1);
}
}
fs << "\n";
sink.saveline("");
rfc2045_parse(rfc2045_parser, "\n", 1);
struct rfc822t *t=rfc822t_alloc_new(from.c_str(), 0, 0);
if (!t)
{
rfc2045_free(rfc2045_parser);
perror("malloc");
return (EX_TEMPFAIL);
}
......@@ -816,6 +920,7 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
if (!a)
{
rfc822t_free(t);
rfc2045_free(rfc2045_parser);
perror("malloc");
return (EX_TEMPFAIL);
}
......@@ -829,6 +934,7 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
{
rfc822a_free(a);
rfc822t_free(t);
rfc2045_free(rfc2045_parser);
perror("malloc");
return (EX_TEMPFAIL);
}
......@@ -847,7 +953,9 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
while (std::getline(msgs, buf).good())
{
fs << buf << std::endl;
sink.saveline(buf);
rfc2045_parse(rfc2045_parser, buf.c_str(), buf.size());
rfc2045_parse(rfc2045_parser, "\n", 1);
// Check for "subscribe/unsubscribe on the first line" wankers.
......@@ -872,14 +980,19 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
first_line=0;
}
fs.flush();
fs.seekp(0);
if (fs.bad() || fs.fail())
bool smtputf8=rfc2045_parser->rfcviolation & RFC2045_ERR8BITHEADER
? true:false;
rfc2045_free(rfc2045_parser);
if (smtputf8)
{
perror( "write" );
return (EX_TEMPFAIL);
if (cmdget_s("UNICODE") != "1")
{
sink.error("This mailing list does not accept Unicode messages, yet.");
return (EX_SOFTWARE);
}
}
if ( cmdget_s("NOBOZOS") == "0")
adminrequest=0;
......@@ -892,14 +1005,12 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
{
while (std::getline(ifs, buf).good())
{
std::cout << buf << std::endl;
sink.error(buf);
flag=1;
}
}
if (!flag) std::cout << "Administractive request blocked."
<< std::endl;
std::cout << std::flush;
if (!flag) sink.error("Administrative request blocked.");
return (EX_SOFTWARE);
}
......@@ -918,8 +1029,7 @@ static int savemsg(std::istream &msgs, std::ostream &fs)
{
if (rc == EX_NOUSER)
{
std::cout << "You are not subscribed to this mailing list."
<< std::endl;
sink.error("<" + from + "> is not subscribed to this mailing list.");
}
rc=EX_SOFTWARE;
return (rc);
......
......@@ -165,6 +165,7 @@ int getinfo(std::string, int (*)(std::string));
std::string myname();
void uaddrlower(std::string &);
std::string extract_alias_to_subscribe(const std::string &);
int isfound(std::string);
int sendmail(const char **, pid_t &);
......@@ -182,4 +183,15 @@ int copyio_noseek(afxipipestream &, afxopipestream &);
int copyio_noseek_cnt(afxipipestream &, afxopipestream &, unsigned long *);
int cmddigest(const std::vector<std::string> &);
const char *is_cmd(const char *default_env,
const char *cmd);
struct savemsg_sink {
virtual void saveline(const std::string &)=0;
virtual void error(const std::string &)=0;
};
int savemsg(std::istream &, savemsg_sink &);
#endif
......@@ -236,6 +236,8 @@ int getinfodir(std::string dir, std::string address, int (*func)(std::string))
{
struct stat stat_buf;
uaddrlower(address);
std::string::iterator b=address.begin(), e=address.end(),
p=std::find(b, e, '@');
......@@ -247,8 +249,6 @@ int getinfodir(std::string dir, std::string address, int (*func)(std::string))
return (1);
}
uaddrlower(address);
std::string shared_lock_name=dir;
shared_lock_name += "/";
......@@ -425,7 +425,14 @@ std::string readmsg()
for (j=0; j<i; j++)
if (msgbuf[j] == 0) msgbuf[j]=' ';
return msgbuf;
std::string s(msgbuf, msgbuf+i);
do
{
std::cin.read(msgbuf, sizeof(msgbuf));
} while (std::cin.good());
return s;
}
//
......
/*
** Copyright 2018 Double Precision, Inc.
** See COPYING for distribution information.
*/
#include "config.h"
#include "cmlm.h"
#include "cmlmfilter.h"
#include <string>
#include <string.h>
#include <sysexits.h>
int rcptfilter_msg()
{
std::cerr << "200 Ok" << std::endl;
return 99;
}
struct savemsg_ignore : public savemsg_sink {
std::string last_error;
bool have_error;
savemsg_ignore() : have_error(false)
{
}
void saveline(const std::string &)
{
}
void error(const std::string &errmsg)
{
if (have_error)
std::cerr << "550-" << last_error << std::endl;
have_error=true;
last_error=errmsg;
}
};
int smtpfilter_msg()
{
savemsg_ignore smi;
int rc=savemsg(std::cin, smi);
if (smi.have_error)
{
std::cerr << "550 " << smi.last_error << std::endl
<< std::flush;
}
return rc;
}
static std::string getcmd()
{
const char *mailfilter_env=getenv("MAILFILTER");
if (!mailfilter_env)
mailfilter_env="";
const char *prefix_env=getenv("FILENAMEPREFIX");
if (!prefix_env)
prefix_env="";
std::string mailfilter_s(mailfilter_env);
std::string prefix_s(prefix_env);
prefix_s += "-";
if (mailfilter_s.substr(0, prefix_s.size()) == prefix_s)
{
mailfilter_s=mailfilter_s.substr(prefix_s.size());
}
else
{
mailfilter_s="";
}
return mailfilter_s;
}
int rcptfilter_ctlmsg()
{
std::string cmd=getcmd();
std::cerr << "200 Ok" << std::endl;
if (is_cmd(cmd.c_str(), "subscribe") ||
is_cmd(cmd.c_str(), "alias-subscribe"))
return 99;
return 0;
}
int smtpfilter_ctlmsg()
{
std::string cmd=getcmd();
std::string msg(readmsg());
std::string addr;
{
const char *address_cstr;
if ((address_cstr=is_cmd(cmd.c_str(), "subscribe")) != 0)
{
addr=returnaddr(msg, address_cstr);
}
else if ((address_cstr=is_cmd(cmd.c_str(), "alias-subscribe"))
!= 0)
{
addr=extract_alias_to_subscribe(msg);
}
else
{
std::cerr << "200 Ok" << std::endl;
return 0;
}
}
uaddrlower(addr);
if (cmdget_s("UNICODE") != "1")
{
std::string::const_iterator b=addr.begin(), e=addr.end();
while (b != e)
{
if (*b & 0x80)
{
std::cerr << "550 This mailing list does not "
"accept Unicode E-mail addresses, yet."
<< std::endl;
return EX_SOFTWARE;
}
++b;
}
}
std::cerr << "200 Ok" << std::endl;
return 0;
}
#ifndef cmlmfilter_h
#define cmlmfilter_h
#include "config.h"
/*
** Copyright 2018 Double Precision, Inc.
** See COPYING for distribution information.
*/
int rcptfilter_msg();
int smtpfilter_msg();
int rcptfilter_ctlmsg();
int smtpfilter_ctlmsg();
#endif
......@@ -7,6 +7,7 @@
#include "cmlm.h"
#include "cmlmsubunsubmsg.h"
#include "afx/afx.h"
#include "rfc822/rfc822.h"
#include "random128/random128.h"
#include "dbobj.h"
#include "mydirent.h"
......@@ -47,6 +48,40 @@ int dounsub(const char *address)
0, 0));
}
extern "C" {
#if 0
}
#endif
static void display_header(const char *p,
size_t cnt,
void *dummy)
{
std::string *s=reinterpret_cast<std::string *>(dummy);
s->append(p, cnt);
}
#if 0
{
#endif
}
std::string extract_alias_to_subscribe(const std::string &msg)
{
std::string h(header_s(msg, "subject"));
std::string decoded_header;
rfc822_display_hdrvalue("Subject",
h.c_str(),
"utf-8",
display_header,
NULL,
&decoded_header);
return decoded_header;
}
// Set a write-only alias.
int doalias(const char *address)
......@@ -54,7 +89,7 @@ int doalias(const char *address)
std::string msg(readmsg());
std::string addr=returnaddr(msg, address);
std::string x_alias="X-Alias: " + header_s(msg, "subject");
std::string x_alias="X-Alias: " + extract_alias_to_subscribe(msg);
return (dosubunsub(msg, addr, "alias", "aliasconfirm", "sub.tmpl", 0,
x_alias.c_str()));
......
......@@ -506,6 +506,10 @@ done
AC_OUTPUT(Makefile courier.h \
courierctl.start \
couriermlm-rcptfilter-ctlmsg \
couriermlm-rcptfilter-msg \
couriermlm-smtpfilter-ctlmsg \
couriermlm-smtpfilter-msg \
dot-qmail-to-dot-courier.pl \
pop3d \
pop3d-ssl \
......
# Not implemented
import SENDER
system '@bindir@/couriermlm rcptfilter-ctlmsg'
EXITCODE=$RETURNCODE
exit
import SENDER
import DEFAULT
system '@bindir@/couriermlm rcptfilter-msg'
EXITCODE=$RETURNCODE
exit
import SENDER
`@bindir@/couriermlm smtpfilter-ctlmsg`
EXITCODE=$RETURNCODE
exit
import SENDER
`@bindir@/couriermlm smtpfilter-msg`
EXITCODE=$RETURNCODE
exit
......@@ -177,6 +177,10 @@ PERMS="
@datadir@/couriermlm/webmlmsubinfo.tmpl.html 644
@datadir@/couriermlm/webmlmsublist.tmpl.html 644
@datadir@/couriermlm/couriermlm-rcptfilter-ctlmsg 644
@datadir@/couriermlm/couriermlm-rcptfilter-msg 644
@datadir@/couriermlm/couriermlm-smtpfilter-ctlmsg 644
@datadir@/couriermlm/couriermlm-smtpfilter-msg 644
"
echo "$PERMS" | while read FILE MODE SPECIAL USER GROUP
......
2018-07-31 Sam Varshavchik <mrsam@courier-mta.com>
* rfc2045/reformime: parse utf-8 address types in DSNs.
2018-07-30 Sam Varshavchik <mrsam@courier-mta.com>
* maildrop: explicitly require libidn to build maildrop.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment