/* Copyright 2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ap_config.h" #include "apr_optional.h" #include "apr_strings.h" #include "httpd.h" #include "http_config.h" #include "http_connection.h" #include "util_filter.h" #include #include "mod_smtpd.h" #include "dnsbl_lookup.h" module AP_MODULE_DECLARE_DATA smtpd_rbl_module; typedef struct smtpd_rbl_config { const char* whitelist_chain; const char* blacklist_chain; } smtpd_rbl_config; static void *smtpd_rbl_create_server_config(apr_pool_t * p, server_rec * s) { smtpd_rbl_config *cfg = apr_pcalloc(p, sizeof(smtpd_rbl_config)); /* the pointers to chain names will be null unless configured */ return cfg; } /* When mod_smtpd gets MAIL FROM it will invoke this callback, (smtpd_run_mail) and we will do a RHSBL check on the envelope sender's domain portion to see whether mail should be denied. If there is a whitelist match, it will override a blacklist. */ smtpd_retcode check_envelope(smtpd_conn_rec *scr, smtpd_return_data *in, char *str) { char *pos, *querystr; smtpd_rbl_config* cfg = ap_get_module_config(scr->s->module_config, &smtpd_rbl_module); int (* dnsbl_domain)(const char*, int, const char*, apr_pool_t*, server_rec*, apr_table_t**); pos = strchr(str, '@'); /* find domain in MAIL FROM: */ if (pos) { querystr = apr_pstrdup(scr->p, pos+1); for (pos=querystr; *pos && (*pos != '>') && (*pos != ' '); pos++) ; *pos = '\0'; /* querystr now has just domain */ } else return SMTPD_OK; dnsbl_domain = APR_RETRIEVE_OPTIONAL_FN(dnsbl_lookup_domain); if (dnsbl_domain && cfg) { if (cfg->whitelist_chain) { if (dnsbl_domain(cfg->whitelist_chain, DNSBL_ANYPOSTV_RETFIRST, querystr, scr->p, scr->s, NULL) == DNSBL_POSITIVE) { return SMTPD_OK; /* envelope domain was whitelisted */ } } if (cfg->blacklist_chain) { if (dnsbl_domain(cfg->blacklist_chain, DNSBL_ANYPOSTV_RETFIRST, querystr, scr->p, scr->s, NULL) == DNSBL_POSITIVE) { /* prepare description of why access is denied */ char** newstr; in->msgs = apr_array_make(scr->p, 1, sizeof(char*)); newstr = (char**)apr_array_push(in->msgs); *newstr = apr_psprintf(scr->p, "Envelope domain %s not " "permitted", querystr); return SMTPD_DENY; } } } /* default action */ return SMTPD_OK; } /* When mod_smtpd gets a connection it will invoke this callback, (smtpd_run_connect) and we will do a DNSBL check on the peer IP to see whether mail should be denied. If there is a whitelist match, it will override a blacklist. */ smtpd_retcode check_address(smtpd_conn_rec *scr, smtpd_return_data *in) { smtpd_rbl_config* cfg = ap_get_module_config(scr->s->module_config, &smtpd_rbl_module); int (*dnsbl_ip)(const char*, int, apr_sockaddr_t*, apr_pool_t*, server_rec*, apr_table_t**); dnsbl_ip = APR_RETRIEVE_OPTIONAL_FN(dnsbl_lookup_ip); if (dnsbl_ip && cfg) { if (cfg->whitelist_chain) { if (dnsbl_ip(cfg->whitelist_chain, DNSBL_ANYPOSTV_RETFIRST, scr->c->remote_addr, scr->p, scr->s, NULL) == DNSBL_POSITIVE) { return SMTPD_OK; /* connecting IP was whitelisted */ } } if (cfg->blacklist_chain) { if (dnsbl_ip(cfg->blacklist_chain, DNSBL_ANYPOSTV_RETFIRST, scr->c->remote_addr, scr->p, scr->s, NULL) == DNSBL_POSITIVE) { /* prepare description of why access is denied */ char** newstr; in->msgs = apr_array_make(scr->p, 1, sizeof(char*)); newstr = (char**)apr_array_push(in->msgs); *newstr = apr_psprintf(scr->p, "Client IP %s not permitted", scr->c->remote_ip); return SMTPD_DENY; } } } /* default action */ return SMTPD_OK; } /* Use hooks from mod_smtpd */ static void smtpd_rbl_register_hooks(apr_pool_t * p) { APR_OPTIONAL_HOOK(smtpd, mail, check_envelope, NULL, NULL, APR_HOOK_FIRST); APR_OPTIONAL_HOOK(smtpd, connect, check_address, NULL, NULL, APR_HOOK_FIRST); } static const char* set_whitelist(cmd_parms* cmd, void* dummy, const char* arg) { smtpd_rbl_config* cfg = ap_get_module_config(cmd->server->module_config, &smtpd_rbl_module); cfg->whitelist_chain = arg; return NULL; } static const char* set_blacklist(cmd_parms* cmd, void* dummy, const char* arg) { smtpd_rbl_config* cfg = ap_get_module_config(cmd->server->module_config, &smtpd_rbl_module); cfg->blacklist_chain = arg; return NULL; } static const command_rec smtpd_rbl_cmds[] = { AP_INIT_TAKE1("SmtpWhitelist", set_whitelist, NULL, RSRC_CONF, "Set SMTP whitelist chain name"), AP_INIT_TAKE1("SmtpBlacklist", set_blacklist, NULL, RSRC_CONF, "Set SMTP blacklist chain name"), {NULL} }; module AP_MODULE_DECLARE_DATA smtpd_rbl_module = { STANDARD20_MODULE_STUFF, NULL, NULL, smtpd_rbl_create_server_config, NULL, smtpd_rbl_cmds, smtpd_rbl_register_hooks };