#include "policyd.h"
/*
*
*
* Policy Daemon
*
* policy daemon is used in conjuction with postfix to combat spam.
*
* Copyright (C) 2004 Cami Sardinha (cami@mweb.co.za)
*
*
* 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
*
*
*
*/
/*
* function: read_conf
* purpose: read config options from file and store memory
*/
void
read_conf(unsigned int prog)
{
memset(confbuf, 0x00, 256);
/* file should exist */
if((fd_config=freopen(configpath, "r", stdin)) == NULL)
{
fprintf(stderr, "fopen(): %s: %s\n", strerror(errno), configpath);
exit(-1);
}
/* cycle through file, grab config options */
while(fgets(confbuf, 256, fd_config) != NULL)
{
memset(extract_array[0], 0x00, 256);
/* SYSLOG FACILITY */
if(strncmp(confbuf, "SYSLOG_FACILITY=", 16) == 0)
{
extract(0, confbuf, 15);
SYSLOG_FACILITY=parse_syslog_priority(extract_array[0]);
}
/* DAEMON MODE */
if(strncmp(confbuf, "DAEMON=", 7) == 0)
{
extract(0, confbuf, 6);
DAEMON=atol(extract_array[0]);
}
/* CHROOT */
if(strncmp(confbuf, "CHROOT=", 7) == 0)
{
extract(0, confbuf, 6);
if((CHROOT=malloc(strlen(extract_array[0])+1)) != NULL)
strcpy(CHROOT, extract_array[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* UID */
if(strncmp(confbuf, "UID=", 4) == 0)
{
extract(0, confbuf, 3);
UID=atol(extract_array[0]);
}
/* GID */
if(strncmp(confbuf, "GID=", 4) == 0)
{
extract(0, confbuf, 3);
GID=atol(extract_array[0]);
}
/* DEBUG MODE */
if(strncmp(confbuf, "DEBUG=", 6) == 0)
{
extract(0, confbuf, 5);
DEBUG=atol(extract_array[0]);
}
/* PORT TO BIND TO */
if(strncmp(confbuf, "BINDPORT=", 9) == 0)
{
extract(0, confbuf, 8);
BINDPORT=atol(extract_array[0]);
}
/* HOST TO BIND TO */
if(strncmp(confbuf, "BINDHOST=", 9) == 0)
{
extract(0, confbuf, 8);
if((BINDHOST=malloc(strlen(extract_array[0])+1)) != NULL)
strcpy(BINDHOST,extract_array[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* CONNECTION ACL */
if(strncmp(confbuf, "CONN_ACL=", 9) == 0)
{
extract(0, confbuf, 8);
if((CONN_ACL=malloc(strlen(extract_array[0])+1)) != NULL)
strcpy(CONN_ACL,extract_array[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* PID TO WRITE TO */
if(strncmp(confbuf, "PIDFILE=", 8) == 0)
{
extract(0, confbuf, 7);
if((PIDFILE=malloc(strlen(extract_array[0])+1)) != NULL)
strcpy(PIDFILE,extract_array[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* GREYLISTING */
if(strncmp(confbuf, "GREYLISTING=", 12) == 0)
{
extract(0, confbuf, 11);
GREYLISTING=atol(extract_array[0]);
}
/* GREYLIST_HOSTADDR */
if(strncmp(confbuf, "GREYLIST_HOSTADDR=", 18) == 0)
{
extract(0, confbuf, 17);
GREYLIST_HOSTADDR=atol(extract_array[0]);
}
/* TRAINING_MODE */
if(strncmp(confbuf, "TRAINING_MODE=", 14) == 0)
{
extract(0, confbuf, 13);
TRAINING_MODE=atol(extract_array[0]);
}
/* TRAINING_POLICY_TIMEOUT */
if(strncmp(confbuf, "TRAINING_POLICY_TIMEOUT=", 24) == 0)
{
extract(0, confbuf, 23);
TRAINING_POLICY_TIMEOUT=extract_seconds(extract_array[0]);
}
/* GREYLIST_X_HEADER */
if(strncmp(confbuf, "GREYLIST_X_HEADER=", 18) == 0)
{
extract(0, confbuf, 17);
GREYLIST_X_HEADER=atol(extract_array[0]);
}
/* WHITELISTING */
if(strncmp(confbuf, "WHITELISTING=", 13) == 0)
{
extract(0, confbuf, 12);
WHITELISTING=atol(extract_array[0]);
}
/* AUTO_WHITELIST_EXPIRE */
if(strncmp(confbuf, "AUTO_WHITELIST_EXPIRE=", 22) == 0)
{
extract(0, confbuf, 21);
AUTO_WHITELIST_EXPIRE=extract_seconds(extract_array[0]);
}
/* AUTO_BLACKLIST_EXPIRE */
if(strncmp(confbuf, "AUTO_BLACKLIST_EXPIRE=", 22) == 0)
{
extract(0, confbuf, 21);
AUTO_BLACKLIST_EXPIRE=extract_seconds(extract_array[0]);
}
/* AUTO_WHITELIST_NETBLOCK */
if(strncmp(confbuf, "AUTO_WHITELIST_NETBLOCK=", 24) == 0)
{
extract(0, confbuf, 23);
AUTO_WHITELIST_NETBLOCK=atol(extract_array[0]);
}
/* AUTO_WHITELIST_NUMBER */
if(strncmp(confbuf, "AUTO_WHITELIST_NUMBER=", 22) == 0)
{
extract(0, confbuf, 21);
AUTO_WHITELIST_NUMBER=atol(extract_array[0]);
}
/* AUTO_BLACKLIST_NUMBER */
if(strncmp(confbuf, "AUTO_BLACKLIST_NUMBER=", 22) == 0)
{
extract(0, confbuf, 21);
AUTO_BLACKLIST_NUMBER=atol(extract_array[0]);
}
/* AUTO_WHITE_LISTING */
if(strncmp(confbuf, "AUTO_WHITE_LISTING=", 19) == 0)
{
extract(0, confbuf, 18);
AUTO_WHITE_LISTING=atol(extract_array[0]);
}
/* SPAMTRAP_AUTO_EXPIRE */
if(strncmp(confbuf, "SPAMTRAP_AUTO_EXPIRE=", 21) == 0)
{
extract(0, confbuf, 20);
SPAMTRAP_AUTO_EXPIRE=extract_seconds(extract_array[0]);
}
/* HELO CHECK */
if(strncmp(confbuf, "HELO_CHECK=", 11) == 0)
{
extract(0, confbuf, 10);
HELO_CHECK=atol(extract_array[0]);
}
/* HELO_MAX_COUNT */
if(strncmp(confbuf, "HELO_MAX_COUNT=", 15) == 0)
{
extract(0, confbuf, 14);
HELO_MAX_COUNT=atol(extract_array[0]);
}
/* HELO_BLACKLIST_AUTO_EXPIRE */
if(strncmp(confbuf, "HELO_BLACKLIST_AUTO_EXPIRE=", 27) == 0)
{
extract(0, confbuf, 26);
HELO_BLACKLIST_AUTO_EXPIRE=extract_seconds(extract_array[0]);
}
/* HELO_AUTO_EXPIRE */
if(strncmp(confbuf, "HELO_AUTO_EXPIRE=", 17) == 0)
{
extract(0, confbuf, 16);
HELO_AUTO_EXPIRE=extract_seconds(extract_array[0]);
}
/* BLACKLISTING */
if(strncmp(confbuf, "BLACKLISTING=", 13) == 0)
{
extract(0, confbuf, 12);
BLACKLISTING=atol(extract_array[0]);
}
/* AUTO_BLACK_LISTING */
if(strncmp(confbuf, "AUTO_BLACK_LISTING=", 19) == 0)
{
extract(0, confbuf, 18);
AUTO_BLACK_LISTING=atol(extract_array[0]);
}
/* BLACKLIST_HELO */
if(strncmp(confbuf, "BLACKLIST_HELO=", 15) == 0)
{
extract(0, confbuf, 14);
BLACKLIST_HELO=atol(extract_array[0]);
}
/* BLACKLIST_HELO_AUTO_EXPIRE */
if(strncmp(confbuf, "BLACKLIST_HELO_AUTO_EXPIRE=", 27) == 0)
{
extract(0, confbuf, 26);
BLACKLIST_HELO_AUTO_EXPIRE=extract_seconds(extract_array[0]);
}
/* SPAMTRAPPING */
if(strncmp(confbuf, "SPAMTRAPPING=", 13) == 0)
{
extract(0, confbuf, 12);
SPAMTRAPPING=atol(extract_array[0]);
}
/* BLACKLIST_TEMP_REJECT */
if(strncmp(confbuf, "BLACKLIST_TEMP_REJECT=", 22) == 0)
{
extract(0, confbuf, 21);
BLACKLIST_TEMP_REJECT=atol(extract_array[0]);
}
/* BLACKLIST_TIMEOUT */
if(strncmp(confbuf, "BLACKLIST_TIMEOUT=", 18) == 0)
{
extract(0, confbuf, 17);
BLACKLIST_TIMEOUT=extract_seconds(extract_array[0]);
}
/* BLACKLIST_NETBLOCK */
if(strncmp(confbuf, "BLACKLIST_NETBLOCK=", 19) == 0)
{
extract(0, confbuf, 18);
BLACKLIST_NETBLOCK=atol(extract_array[0]);
}
/* BLACKLIST SENDER */
if(strncmp(confbuf, "BLACKLISTSENDER=", 16) == 0)
{
extract(0, confbuf, 15);
BLACKLISTSENDER=atol(extract_array[0]);
}
/* BLACKLIST DNS NAME */
if(strncmp(confbuf, "BLACKLISTDNSNAME=", 17) == 0)
{
extract(0, confbuf, 16);
BLACKLISTDNSNAME=atol(extract_array[0]);
}
/* WHITELIST NULL SENDER */
if(strncmp(confbuf, "WHITELISTNULL=", 14) == 0)
{
extract(0, confbuf, 13);
WHITELISTNULL=atol(extract_array[0]);
}
/* WHITELIST SENDER */
if(strncmp(confbuf, "WHITELISTSENDER=", 16) == 0)
{
extract(0, confbuf, 15);
WHITELISTSENDER=atol(extract_array[0]);
}
/* WHITELIST DNS NAME */
if(strncmp(confbuf, "WHITELISTDNSNAME=", 17) == 0)
{
extract(0, confbuf, 16);
WHITELISTDNSNAME=atol(extract_array[0]);
}
/* SENDERTHROTTLE */
if(strncmp(confbuf, "SENDERTHROTTLE=", 15) == 0)
{
extract(0, confbuf, 14);
SENDERTHROTTLE=atol(extract_array[0]);
}
/* SENDER_THROTTLE_SASL */
if(strncmp(confbuf, "SENDER_THROTTLE_SASL=", 21) == 0)
{
extract(0, confbuf, 20);
SENDER_THROTTLE_SASL=atol(extract_array[0]);
}
/* SENDER_THROTTLE_HOST */
if(strncmp(confbuf, "SENDER_THROTTLE_HOST=", 21) == 0)
{
extract(0, confbuf, 20);
SENDER_THROTTLE_HOST=atol(extract_array[0]);
}
/* MAXIMUM SENDER MESSAGE LIMIT */
if(strncmp(confbuf, "SENDERMSGLIMIT=", 15) == 0)
{
extract(0, confbuf, 14);
SENDERMSGLIMIT=atol(extract_array[0]);
}
/* MAXIMUM SENDER RCPT LIMIT */
if(strncmp(confbuf, "SENDERRCPTLIMIT=", 16) == 0)
{
extract(0, confbuf, 15);
SENDERRCPTLIMIT=atol(extract_array[0]);
}
/* MAX SENDER VOLUME/QUOTA SENDER TIME LIMIT */
if(strncmp(confbuf, "SENDERQUOTALIMIT=", 17) == 0)
{
extract(0, confbuf, 16);
SENDERQUOTALIMIT=atol(extract_array[0]);
}
/* MAX MAIL SIZE PER SENDER */
if(strncmp(confbuf, "SENDERMSGSIZE=", 14) == 0)
{
extract(0, confbuf, 13);
SENDERMSGSIZE=atol(extract_array[0]);
}
/* MAX SENDER TIME LIMIT */
if(strncmp(confbuf, "SENDERTIMELIMIT=", 16) == 0)
{
extract(0, confbuf, 15);
SENDERTIMELIMIT=extract_seconds(extract_array[0]);
}
/* INACTIVE SENDER EXPIRATION TIME LIMIT */
if(strncmp(confbuf, "SENDER_INACTIVE_EXPIRE=", 23) == 0)
{
extract(0, confbuf, 22);
SENDER_INACTIVE_EXPIRE=extract_seconds(extract_array[0]);
}
/* SENDER_THROTTLE_AUTOBLACKLIST */
if(strncmp(confbuf, "SENDER_THROTTLE_AUTOBLACKLIST=", 30) == 0)
{
extract(0, confbuf, 29);
SENDER_THROTTLE_AUTOBLACKLIST=atol(extract_array[0]);
}
/* SENDER_THROTTLE_AUTOBLACKLIST_NUMBER */
if(strncmp(confbuf, "SENDER_THROTTLE_AUTOBLACKLIST_NUMBER=", 37) == 0)
{
extract(0, confbuf, 36);
SENDER_THROTTLE_AUTOBLACKLIST_NUMBER=atol(extract_array[0]);
}
/* SENDER_THROTTLE_AUTOBLACKLIST_EXPIRE */
if(strncmp(confbuf, "SENDER_THROTTLE_AUTOBLACKLIST_EXPIRE=", 37) == 0)
{
extract(0, confbuf, 36);
SENDER_THROTTLE_AUTOBLACKLIST_EXPIRE=extract_seconds(extract_array[0]);
}
/* RECIPIENTTHROTTLE */
if(strncmp(confbuf, "RECIPIENTTHROTTLE=", 18) == 0)
{
extract(0, confbuf, 17);
RECIPIENTTHROTTLE=atol(extract_array[0]);
}
/* MAX RECIPIENT MESSAGES LIMIT */
if(strncmp(confbuf, "RECIPIENTMSGLIMIT=", 18) == 0)
{
extract(0, confbuf, 17);
RECIPIENTMSGLIMIT=atol(extract_array[0]);
}
/* MAX RECIPIENT TIME LIMIT */
if(strncmp(confbuf, "RECIPIENTTIMELIMIT=", 19) == 0)
{
extract(0, confbuf, 18);
RECIPIENTTIMELIMIT=extract_seconds(extract_array[0]);
}
/* INACTIVE RECIPIENT EXPIRATION TIME LIMIT */
if(strncmp(confbuf, "RECIPIENT_INACTIVE_EXPIRE=", 26) == 0)
{
extract(0, confbuf, 25);
RECIPIENT_INACTIVE_EXPIRE=extract_seconds(extract_array[0]);
}
/* TRIPLET TIMEOUT */
if(strncmp(confbuf, "TRIPLET_TIME=", 13) == 0)
{
extract(0, confbuf, 12);
TRIPLET_TIME=extract_seconds(extract_array[0]);
}
/* TRIPLET_AUTH_TIMEOUT */
if(strncmp(confbuf, "TRIPLET_AUTH_TIMEOUT=", 21) == 0)
{
extract(0, confbuf, 20);
TRIPLET_AUTH_TIMEOUT=extract_seconds(extract_array[0]);
}
/* TRIPLET_UNAUTH_TIMEOUT */
if(strncmp(confbuf, "TRIPLET_UNAUTH_TIMEOUT=", 23) == 0)
{
extract(0, confbuf, 22);
TRIPLET_UNAUTH_TIMEOUT=extract_seconds(extract_array[0]);
}
/* OPT-IN / OPT-OUT */
if(strncmp(confbuf, "OPTINOUT=", 9) == 0)
{
extract(0, confbuf, 8);
OPTINOUT=atol(extract_array[0]);
}
/* OPT-IN / OPT-OUT */
if(strncmp(confbuf, "OPTINOUTALL=", 12) == 0)
{
extract(0, confbuf, 11);
OPTINOUTALL=atol(extract_array[0]);
}
/* FAILOVER MODE */
if(strncmp(confbuf, "FAILSAFE=", 9) == 0)
{
extract(0, confbuf, 8);
FAILSAFE=atol(extract_array[0]);
}
/* DATABASE_KEEPALIVE */
if(strncmp(confbuf, "DATABASE_KEEPALIVE=", 19) == 0)
{
extract(0, confbuf, 18);
DATABASE_KEEPALIVE=atol(extract_array[0]);
}
/* MYSQL HOST */
if(strncmp(confbuf, "MYSQLHOST=", 10) == 0)
{
extract_conf(0, confbuf, 9);
if((MYSQLHOST=malloc(strlen(extract_array_conf[0])+1)) != NULL)
strcpy(MYSQLHOST, extract_array_conf[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* MYSQL DATABASE */
if(strncmp(confbuf, "MYSQLDBASE=", 11) == 0)
{
extract_conf(0, confbuf, 10);
if((MYSQLDBASE=malloc(strlen(extract_array_conf[0])+1)) != NULL)
strcpy(MYSQLDBASE, extract_array_conf[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* MYSQL USER */
if(strncmp(confbuf, "MYSQLUSER=", 10) == 0)
{
extract_conf(0, confbuf, 9);
if((MYSQLUSER=malloc(strlen(extract_array_conf[0])+1)) != NULL)
strcpy(MYSQLUSER, extract_array_conf[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* MYSQL PASS */
if(strncmp(confbuf, "MYSQLPASS=", 10) == 0)
{
extract_conf(0, confbuf, 9);
if((MYSQLPASS=malloc(strlen(extract_array_conf[0])+1)) != NULL)
strcpy(MYSQLPASS, extract_array_conf[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* MYSQL OPTIONS */
if(strncmp(confbuf, "MYSQLOPT=", 9) == 0)
{
extract_conf(0, confbuf, 8);
if((MYSQLOPT=malloc(strlen(extract_array_conf[0])+1)) != NULL)
strcpy(MYSQLOPT, extract_array_conf[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* MYSQL PORT */
if(strncmp(confbuf, "MYSQLPORT=", 10) == 0)
{
extract(0, confbuf, 9);
MYSQLPORT=atol(extract_array[0]);
}
/* GREYLIST_REJECTION */
if(strncmp(confbuf, "GREYLIST_REJECTION=", 19) == 0)
{
extract_conf(0, confbuf, 18);
if((postfix_greylist=malloc(512)) != NULL)
snprintf(postfix_greylist, 512, "%s %s\n\n", POSTFIX_GREYLIST, extract_array_conf[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* BLACKLIST_REJECTION */
if(strncmp(confbuf, "BLACKLIST_REJECTION=", 20) == 0)
{
extract_conf(0, confbuf, 19);
if((postfix_blacklist=malloc(512)) != NULL)
{
if(BLACKLIST_TEMP_REJECT==1)
snprintf(postfix_blacklist, 512, "%s %s\n\n", POSTFIX_BLACKLIST_TEMP, extract_array_conf[0]);
else
snprintf(postfix_blacklist, 512, "%s %s\n\n", POSTFIX_BLACKLIST_PERM, extract_array_conf[0]);
}
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* THROTTLE BAD SIZE */
if(strncmp(confbuf, "SENDER_SIZE_REJECTION=", 22) == 0)
{
extract_conf(0, confbuf, 21);
if((postfix_bad_size=malloc(512)) != NULL)
snprintf(postfix_bad_size, 512, "%s %s\n\n", POSTFIX_BAD_SIZE, extract_array_conf[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* SPAMTRAP */
if(strncmp(confbuf, "SPAMTRAP_REJECTION=", 19) == 0)
{
extract_conf(0, confbuf, 18);
if((postfix_spamtrap=malloc(512)) != NULL)
snprintf(postfix_spamtrap, 512, "%s %s\n\n", POSTFIX_SPAMTRAP, extract_array_conf[0]);
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* MAX SENDER QUOTA EXCEEDED */
if(strncmp(confbuf, "SENDER_QUOTA_REJECTION=", 23) == 0)
{
extract_conf(0, confbuf, 22);
if((postfix_sender_quota_exceeded=malloc(512)) != NULL)
{
if(QUOTA_EXCEEDED_TEMP_REJECT==1)
snprintf(postfix_sender_quota_exceeded, 512, "%s %s\n\n", POSTFIX_QUOTA_EXCEEDED_TEMP, extract_array_conf[0]);
else
snprintf(postfix_sender_quota_exceeded, 512, "%s %s\n\n", POSTFIX_QUOTA_EXCEEDED_PERM, extract_array_conf[0]);
}
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* MAX RECIPIENT QUOTA EXCEEDED */
if(strncmp(confbuf, "RECIPIENT_QUOTA_REJECTION=", 26) == 0) {
extract_conf(0, confbuf, 25);
if((postfix_recipient_quota_exceeded=malloc(512)) != NULL)
{
if(QUOTA_EXCEEDED_TEMP_REJECT==1)
snprintf(postfix_recipient_quota_exceeded, 512, "%s %s\n\n", POSTFIX_QUOTA_EXCEEDED_TEMP, extract_array_conf[0]);
else
snprintf(postfix_recipient_quota_exceeded, 512, "%s %s\n\n", POSTFIX_QUOTA_EXCEEDED_PERM, extract_array_conf[0]);
}
else {
logmessage("malloc(): %s\n", strerror(errno));
exit(-1);
}
}
/* QUOTA_EXCEEDED_TEMP_REJECT */
if(strncmp(confbuf, "QUOTA_EXCEEDED_TEMP_REJECT=", 27) == 0)
{
extract(0, confbuf, 26);
QUOTA_EXCEEDED_TEMP_REJECT=atol(extract_array[0]);
}
memset(confbuf, 0x00, 256);
}
/* backward compatible with old configs */
if(!SYSLOG_FACILITY)
SYSLOG_FACILITY=LOG_MAIL|LOG_INFO;
/* close config file when we're done */
if(fclose(fd_config) != 0)
{
logmessage("fclose(): %s: %s\n", configpath, strerror(errno));
exit(-1);
}
/* background policyd */
if(DAEMON)
{
/* dont let cleanup run in the background */
if(prog == 0)
{
if(daemonize(0,0) == -1)
{
fprintf(stderr, "daemon(): %s\n", strerror(errno));
exit(-1);
}
}
}
/* dump all debugging info */
if(DEBUG > 0)
{
logmessage(" ---- DAEMON CONFIG ----\n");
logmessage("config: version> %s\n", VERSION);
logmessage("config: debug> %d\n", DEBUG);
logmessage("config: daemon mode> %d\n", DAEMON);
logmessage("config: bindhost> %s\n", BINDHOST);
logmessage("config: bindport> %d\n", BINDPORT);
logmessage("config: pidfile> %s\n", PIDFILE);
logmessage("config: syslog> %d\n", SYSLOG_FACILITY);
logmessage("config: chroot> %s\n", CHROOT);
logmessage("config: uid> %d\n", UID);
logmessage("config: gid> %d\n", GID);
logmessage("config: conn acl> %s\n", CONN_ACL);
logmessage("\n");
logmessage(" ---- DATABASE CONFIG ----\n");
logmessage("config: host> %s\n", MYSQLHOST);
logmessage("config: user> %s\n", MYSQLUSER);
logmessage("config: pass> %s\n", MYSQLPASS);
logmessage("config: database> %s\n", MYSQLDBASE);
logmessage("config: options> %s\n", MYSQLOPT);
logmessage("config: failsafe> %d\n", FAILSAFE);
logmessage("config: keep alive> %d\n", DATABASE_KEEPALIVE);
logmessage("config: version> %d\n", MYSQL_VERSION_ID);
logmessage("\n");
logmessage(" ---- WHITELISTING ----\n");
logmessage("config: whitelisting> %d\n", WHITELISTING);
logmessage("config: whitelistnullsender> %d\n", WHITELISTNULL);
logmessage("config: whitelistsender> %d\n", WHITELISTSENDER);
logmessage("config: whitelistdnsname> %d\n", WHITELISTDNSNAME);
logmessage("config: autowhitelisting> %d\n", AUTO_WHITE_LISTING);
logmessage("config: autowhitelist_number> %d\n", AUTO_WHITELIST_NUMBER);
logmessage("config: autowhitelist_netblock> %d\n", AUTO_WHITELIST_NETBLOCK);
logmessage("config: autowhitelist_expire> %d\n", AUTO_WHITELIST_EXPIRE);
logmessage("\n");
logmessage(" ---- BLACKLISTING ----\n");
logmessage("config: blacklisting> %d\n", BLACKLISTING);
logmessage("config: blacklisting_temp_reject> %d\n", BLACKLIST_TEMP_REJECT);
logmessage("config: blacklisting_netblock> %d\n", BLACKLIST_NETBLOCK);
logmessage("config: postfix_blacklist> %s\n", postfix_blacklist);
logmessage("config: autoblacklisting> %d\n", AUTO_BLACK_LISTING);
logmessage("config: autoblacklist_number> %d\n", AUTO_BLACKLIST_NUMBER);
logmessage("config: autoblacklist_expire> %d\n", AUTO_BLACKLIST_EXPIRE);
logmessage("config: blacklist_rejection> %s\n", postfix_blacklist);
logmessage("\n");
logmessage(" ---- HELO (HRP) ----\n");
logmessage("config: helo> %d\n", HELO_CHECK);
logmessage("config: helo_max_count> %d\n", HELO_MAX_COUNT);
logmessage("config: helo_blacklist_auto_expire> %d\n", HELO_BLACKLIST_AUTO_EXPIRE);
logmessage("config: helo_auto_expire> %d\n", HELO_AUTO_EXPIRE);
logmessage("\n");
logmessage(" ---- SPAMTRAP CONFIG ----\n");
logmessage("config: spamtrap> %d\n", SPAMTRAPPING);
logmessage("config: postfix_spamtrap> %s\n", postfix_spamtrap);
logmessage("config: spamtrapauto_expire> %d\n", SPAMTRAP_AUTO_EXPIRE);
logmessage("\n");
logmessage(" ---- GREYLISTING CONFIG ----\n");
logmessage("config: greylisting> %d\n", GREYLISTING);
logmessage("config: greylist_hostaddr> %d\n", GREYLIST_HOSTADDR);
logmessage("config: postfix_greylist> %s\n", postfix_greylist);
logmessage("config: greylist_x_header> %d\n", GREYLIST_X_HEADER);
logmessage("config: trainingmode> %d\n", TRAINING_MODE);
logmessage("config: training_policyd_timeout> %d\n", TRAINING_POLICY_TIMEOUT);
logmessage("config: triplet timeout> %d\n", TRIPLET_TIME);
logmessage("config: optin/optout> %d\n", OPTINOUT);
logmessage("config: optin all in> %d\n", OPTINOUTALL);
logmessage("config: triplet auth timeout> %d\n", TRIPLET_AUTH_TIMEOUT);
logmessage("config: triplet unauth timeout> %d\n", TRIPLET_UNAUTH_TIMEOUT);
logmessage("\n");
logmessage(" ---- SENDER THROTTLE CONFIG ----\n");
logmessage("config: sender throttle> %d\n", SENDERTHROTTLE);
logmessage("config: sender throttle sasl> %d\n", SENDER_THROTTLE_SASL);
logmessage("config: sender throttle host> %d\n", SENDER_THROTTLE_HOST);
logmessage("config: postfix_sender_quota_exceeded> %s\n", postfix_sender_quota_exceeded);
logmessage("config: quota_exceeded_temp_reject> %d\n", QUOTA_EXCEEDED_TEMP_REJECT);
logmessage("config: postfix_bad_size> %s\n", postfix_bad_size);
logmessage("config: sender msglimit> %d\n", SENDERMSGLIMIT);
logmessage("config: sender quotalimit> %d\n", SENDERQUOTALIMIT);
logmessage("config: sender timelimit> %d\n", SENDERTIMELIMIT);
logmessage("config: sender msgsize> %d\n", SENDERMSGSIZE);
logmessage("config: sender expire inactive> %d\n", SENDER_INACTIVE_EXPIRE);
logmessage("config: sender throttle autoblacklisting> %d\n", SENDER_THROTTLE_AUTOBLACKLIST);
logmessage("config: sender throttle autoblacklist number> %d\n", SENDER_THROTTLE_AUTOBLACKLIST_NUMBER);
logmessage("config: sender throttle autoblacklist expire> %d\n", SENDER_THROTTLE_AUTOBLACKLIST_EXPIRE);
logmessage("\n");
logmessage(" ---- RECIPIENT THROTTLE CONFIG ----\n");
logmessage("config: recipient throttle> %d\n", RECIPIENTTHROTTLE);
logmessage("config: recipient msglimit> %d\n", RECIPIENTMSGLIMIT);
logmessage("config: recipient timelimit> %d\n", RECIPIENTTIMELIMIT);
logmessage("config: recipient expire inactive> %d\n", RECIPIENT_INACTIVE_EXPIRE);
logmessage("config: postfix_recipient_quota_exceeded> %s\n", postfix_recipient_quota_exceeded);
logmessage("config: quota_exceeded_temp_reject> %d\n", QUOTA_EXCEEDED_TEMP_REJECT);
logmessage("\n");
}
if((SENDER_THROTTLE_HOST) && (SENDER_THROTTLE_SASL))
{
logmessage("FATAL: you may NOT have SENDER_THROTTLE_HOST and SENDER_THROTTLE_SASL enabled\n");
exit (-1);
}
/* quick acl check */
if((!CONN_ACL) || (!strlen(CONN_ACL)))
{
logmessage("FATAL: you did not upgrade correctly or have broken something. "
"Please read the Changelog.txt. You're missing the CONN_ACL setting\n");
exit (-1);
}
}
/*
* function: w_string_strip
* purpose:
* return:
*/
int
w_string_strip(void *str, char *token)
{
char *ptr;
ptr = strtok(str, token);
if(ptr != NULL)
{
return (1); /* found */
} else {
return (0); /* not found */
}
}
/*
* function: logmessage
* purpose: log messages to syslog or stdout/stderr
* return: nada
*/
void
logmessage(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if(DAEMON == 0)
{
vfprintf(stdout, fmt, ap);
fflush(stdout);
}
else
vsyslog(SYSLOG_FACILITY, fmt, ap);
va_end(ap);
}
/*
* function: usage
* purpose: print out usage information
* return: nada
*/
void
usage(char *usag)
{
logmessage("policyd %s\n", VERSION);
logmessage("usage: %s -c /path/to/policyd.conf\n", usag);
exit(-1);
}
/*
* function: extract_seconds
* purpose: convert token to seconds
* return: seconds
*/
int
extract_seconds(char *token)
{
char tmp[32];
unsigned int multiplier=0;
/* allow values of 0 */
if((isdigit(token[0]) != 0) && (atol(token) == 0))
return 0;
memset(tmp, 0x00, 32);
switch(token[strlen(token) - 1])
{
case 's':
multiplier = 1;
break;
case 'm':
multiplier = 60;
break;
case 'h':
multiplier = 60 * 60;
break;
case 'd':
multiplier = 60 * 60 * 24;
break;
case 'w':
multiplier = 60 * 60 * 24 * 7;
break;
case 'M':
multiplier = 60 * 60 * 24 * 31 ;
break;
case 'Y':
multiplier = 60 * 60 * 24 * 31 * 12;
break;
default:
logmessage("fatal: invalid time unit: %s\n", token);
exit(-1);
}
strncpy(tmp, token, sizeof(tmp) - 2);
return (atol(tmp) * multiplier);
}
/*
* function: extract
* purpose: extract policy variable
* return: policy variable (into an array)
*/
void
extract(unsigned int fd, char *token, unsigned int startlen)
{
unsigned int y, clen=startlen, tlen;
memset(extract_array[fd], 0x00, 64);
tlen=strlen(token);
for( ; clen <= tlen && clen <= 63 ; clen++) {
if(token[clen]=='=') {
for(clen++,y=0; clen<=tlen&&clen<=63;clen++) {
/* we only want characters [A-Z][a-z][0-9]/@ and . */
if((isalnum(token[clen]) != 0)
|| (token[clen] == '@')
|| (token[clen] == '|')
|| (token[clen] == '.')
|| (token[clen] == '_')
|| (token[clen] == '-')
|| (token[clen] == ' ')
|| (token[clen] == '/')) {
extract_array[fd][y]=token[clen]; y++;
}
}
}
}
}
/*
* function: extract_conf
* purpose: extract policy variable
* return: policy variable (into an array)
*/
void
extract_conf(unsigned int fd, char *token, unsigned int startlen)
{
unsigned int y, clen=startlen, tlen;
memset(extract_array_conf[fd], 0x00, 512);
tlen=strlen(token);
for( ; clen <= tlen && clen <= 511 ; clen++) {
if(token[clen]=='=') {
for(clen++,y=0; clen<=tlen&&clen<=511;clen++) {
/* we only want characters [A-Z][a-z][0-9]/@ and . */
if((isalnum(token[clen]) != 0) || isascii(token[clen] != 0)) {
if((token[clen] != '"') && (token[clen] != '\n')) {
extract_array_conf[fd][y]=token[clen]; y++; }
}
}
}
}
}
/*
* function: extract_ip
* purpose: extract ip address from policy variable
* return: policy variable (into an array)
*/
void
extract_ip(unsigned int fd, char *token)
{
unsigned int x=15, y=0, z=0, len;
memset(extract_ip_array[fd], 0x00, 64);
len=strlen(token);
for(x=15,z=0,y=0;x<len||x<64;x++) {
if(token[x] == '\n') break;
/* we only want characters [0-9] and . */
if((isdigit(token[x]) != 0) || (token[x] == '.'))
{
if(token[x] == '.') z++;
if(z == GREYLIST_HOSTADDR) break;
extract_ip_array[fd][y]=token[x]; y++;
}
}
}
/*
* function: extract_ip_array
* purpose: extract ip address from policy variable
* return: policy variable (into an array)
*/
void
extract_ipfill(unsigned int fd, char *token)
{
unsigned int x=15, y=0, z=0, len, w=5;
memset(extract_ip_array[fd], 0x00, 64);
len=strlen(token);
for(x=15,z=0,y=0;x<len||x<64;x++) {
if(token[x] == '\n') break;
/* we only want characters [0-9] and . */
if((isdigit(token[x]) != 0) || (token[x] == '.'))
{
if(token[x] == '.')
{
if(z == 0)
snprintf(host_array[fd][w], 64, "%s.%%.%%.%%", extract_ip_array[fd]);
if(z == 1)
snprintf(host_array[fd][w], 64, "%s.%%.%%", extract_ip_array[fd]);
if(z == 2)
snprintf(host_array[fd][w], 64, "%s.%%", extract_ip_array[fd]);
z++; w--;
}
if(z == GREYLIST_HOSTADDR)
break;
extract_ip_array[fd][y]=token[x];
y++;
}
}
}
/*
* function: fold
* purpose: shut down all open connections and close policyd gracefully
* return: nada
*/
void
fold()
{
logmessage("shutting down..\n");
shutdown(msock, SHUT_RDWR);
shutdown(ssock, SHUT_RDWR);
exit(0);
}
/*
* function: gettime
* purpose: get current time
* return: return current time
*/
int
gettime(void)
{
/* get current time */
if(gettimeofday(&timevalue, NULL) != 0)
{
logmessage("gettimeofday(): %s\n", strerror(errno));
exit(-1);
}
return (timevalue.tv_sec);
}
/*
* function: drop_privs
* purpose: drop privledges
* return: nada
*/
void
drop_privs(void)
{
/*
* 1) quick sanity check
* 2) ensure backward compatibility with old configs
*/
if(PIDFILE)
{
/* write to pid file */
if((pidfile=fopen(PIDFILE, "w")) == NULL)
{
fprintf(stderr, "fopen(): %s: %s\n", strerror(errno), PIDFILE);
exit(-1);
}
fprintf(pidfile, "%d\n", (unsigned int)getpid());
/* we're done, clean up */
if(fclose(pidfile) != 0)
{
logmessage("fclose(): %s: %s\n", PIDFILE, strerror(errno));
exit(-1);
}
}
/* change root */
if(chdir(CHROOT) == -1)
{
logmessage("chdir(): %s\n", strerror(errno));
exit(-1);
}
/* chroot */
if(chroot(".") == -1)
{
logmessage("chroot(): %s\n", strerror(errno));
exit(-1);
}
/* change gid */
if(setgid(GID) == -1)
{
logmessage("setgid(): %s\n", strerror(errno));
exit(-1);
}
/* change uid */
if(setuid(UID) == -1)
{
logmessage("setuid(): %s\n", strerror(errno));
exit(-1);
}
}
/*
* function: policy_reply
* purpose: reply/talk to Postfix
* return: 0=sucessfull write(), 1=failed write()
*/
void
policy_reply(unsigned int fd, int code, int status)
{
/* keep gcc quiet for now */
status = 0;
switch (code)
{
/* accept: always allow */
case 0:
/* dump greylisting information into mail? */
if((GREYLISTING==1) && (GREYLIST_X_HEADER==1))
{
/* whitelisted */
snprintf(xgreylist_array[fd], 128, "%s host: %s\n\n",
POSTFIX_X_HEADER, host_array[fd][2]);
/* if not whitelisted, greylist.c already filled in all the details */
buf_write(fd, xgreylist_array[fd], strlen(xgreylist_array[fd]));
} else {
buf_write(fd, POSTFIX_GOOD, strlen(POSTFIX_GOOD));
}
break;
/* reject: greylisting */
case -1:
buf_write(fd, postfix_greylist, strlen(postfix_greylist));
break;
/* reject: blacklisted */
case -2:
buf_write(fd, postfix_blacklist, strlen(postfix_blacklist));
break;
/* reject: message size too big */
case -3:
buf_write(fd, postfix_bad_size, strlen(postfix_bad_size));
break;
/* reject: spam trap address */
case -4:
buf_write(fd, postfix_spamtrap, strlen(postfix_spamtrap));
break;
/* reject: max sender quota exceeded */
case -5:
buf_write(fd, postfix_sender_quota_exceeded, strlen(postfix_sender_quota_exceeded));
break;
/* reject: helo checking */
case -6:
buf_write(fd, postfix_blacklist, strlen(postfix_blacklist));
break;
/* reject: max recipient quota exceeded */
case -7:
buf_write(fd, postfix_recipient_quota_exceeded, strlen(postfix_recipient_quota_exceeded));
break;
/* reject: max recipient quota exceeded */
case -8:
buf_write(fd, POSTFIX_MODULE_FAILURE, strlen(POSTFIX_MODULE_FAILURE));
break;
/* something bad happened */
default:
logmessage("WARNING: policy_reply called with unknown code\n");
buf_write(fd, POSTFIX_MODULE_FAILURE, strlen(POSTFIX_MODULE_FAILURE));
break;
}
}
/*
* function: db_failure
* purpose: handle database failures so policyd isnt a single point of failure.
* return: -20 for failures (talk to Postfix first)
*/
int
db_failure(unsigned int fd, char *module)
{
if(FAILSAFE==1)
{
/* do not fail */
logmessage("rcpt=%lu, %s=bypass, host=%s (%s), from=%s, to=%s, size=%s\n",
rcpt_count, /* recipient count */
module, /* module name */
host_array[fd][2], /* host */
host_array[fd][0], /* hostname */
triplet_array[fd][1], /* from */
triplet_array[fd][2], /* rcpt */
triplet_array[fd][3] /* size */
);
mysql_failure_count++;
policy_reply(fd, 0, 0);
return (-20);
}
if(FAILSAFE==0)
{
/* fail as requested */
logmessage("rcpt=%lu, %s=failed, host=%s (%s), from=%s, to=%s, size=%s\n",
rcpt_count, /* recipient count */
module, /* module name */
host_array[fd][2], /* host */
host_array[fd][0], /* hostname */
triplet_array[fd][1], /* from */
triplet_array[fd][2], /* rcpt */
triplet_array[fd][3] /* size */
);
policy_reply(fd, -1, 0);
return (-20);
}
return (0); /* not reached */
}
void
sigalrm_handler (void)
{
alarm (0); /* reset alarm timer */
siglongjmp (sjmp, 1); /* jump back */
}
/* EOF */
syntax highlighted by Code2HTML, v. 0.9.1