mirror of
https://bitbucket.org/jsuto/piler.git
synced 2025-06-13 12:17:02 +02:00
switched to preforking daemon
This commit is contained in:
@ -80,6 +80,7 @@ install-piler:
|
||||
$(INSTALL) -m 0755 piler $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 0755 pilerconf $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 0755 pilerget $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 0755 pilerimport $(DESTDIR)$(bindir)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a libpiler.so* piler pilerconf pilerget pilerimport pilertest
|
||||
|
@ -68,9 +68,9 @@ struct _parse_rule config_parse_rules[] =
|
||||
{ "listen_addr", "string", (void*) string_parser, offsetof(struct __config, listen_addr), "127.0.0.1", MAXVAL-1},
|
||||
{ "listen_port", "integer", (void*) int_parser, offsetof(struct __config, listen_port), "10025", sizeof(int)},
|
||||
{ "locale", "string", (void*) string_parser, offsetof(struct __config, locale), "", MAXVAL-1},
|
||||
{ "max_connections", "integer", (void*) int_parser, offsetof(struct __config, max_connections), "30", sizeof(int)},
|
||||
{ "max_requests_per_child", "integer", (void*) int_parser, offsetof(struct __config, max_requests_per_child), "200", sizeof(int)},
|
||||
{ "max_requests_per_child", "integer", (void*) int_parser, offsetof(struct __config, max_requests_per_child), "1000", sizeof(int)},
|
||||
{ "memcached_servers", "string", (void*) string_parser, offsetof(struct __config, memcached_servers), "127.0.0.1", MAXVAL-1},
|
||||
{ "memcached_to_db_interval", "integer", (void*) int_parser, offsetof(struct __config, memcached_to_db_interval), "900", sizeof(int)},
|
||||
{ "memcached_ttl", "integer", (void*) int_parser, offsetof(struct __config, memcached_ttl), "86400", sizeof(int)},
|
||||
{ "mydomains", "string", (void*) string_parser, offsetof(struct __config, mydomains), "", MAXVAL-1},
|
||||
{ "mysqlhost", "string", (void*) string_parser, offsetof(struct __config, mysqlhost), "", MAXVAL-1},
|
||||
@ -86,6 +86,7 @@ struct _parse_rule config_parse_rules[] =
|
||||
{ "queuedir", "string", (void*) string_parser, offsetof(struct __config, queuedir), QUEUE_DIR, MAXVAL-1},
|
||||
{ "session_timeout", "integer", (void*) int_parser, offsetof(struct __config, session_timeout), "420", sizeof(int)},
|
||||
{ "sqlite3_pragma", "string", (void*) string_parser, offsetof(struct __config, sqlite3_pragma), "", MAXVAL-1},
|
||||
{ "update_counters_to_memcached", "integer", (void*) int_parser, offsetof(struct __config, update_counters_to_memcached), "0", sizeof(int)},
|
||||
{ "username", "string", (void*) string_parser, offsetof(struct __config, username), "piler", MAXVAL-1},
|
||||
{ "use_antivirus", "integer", (void*) int_parser, offsetof(struct __config, use_antivirus), "1", sizeof(int)},
|
||||
{ "verbosity", "integer", (void*) int_parser, offsetof(struct __config, verbosity), "1", sizeof(int)},
|
||||
|
@ -27,7 +27,6 @@ struct __config {
|
||||
|
||||
int number_of_worker_processes;
|
||||
int max_requests_per_child;
|
||||
int max_connections;
|
||||
|
||||
int backlog;
|
||||
|
||||
@ -61,6 +60,9 @@ struct __config {
|
||||
char sqlite3[MAXVAL];
|
||||
char sqlite3_pragma[MAXVAL];
|
||||
|
||||
int update_counters_to_memcached;
|
||||
int memcached_to_db_interval;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -11,14 +11,14 @@
|
||||
|
||||
#define PROGNAME "piler"
|
||||
|
||||
#define VERSION "0.1.11"
|
||||
#define VERSION "0.1.12"
|
||||
|
||||
#define PROGINFO VERSION ", Janos SUTO <sj@acts.hu>\n\n" CONFIGURE_PARAMS "\n"
|
||||
|
||||
#define HOSTID "mailarchiver"
|
||||
|
||||
#define CONFIG_FILE CONFDIR "/piler.conf"
|
||||
#define WORK_DIR DATADIR "/spool/piler/tmp"
|
||||
#define WORK_DIR DATADIR "/piler/tmp"
|
||||
#define QUEUE_DIR DATADIR "/piler/store"
|
||||
|
||||
#define CLAMD_SOCKET "/tmp/clamd"
|
||||
|
@ -42,7 +42,7 @@ struct __counters loadCounters(struct session_data *sdata, struct __config *cfg)
|
||||
}
|
||||
|
||||
|
||||
void updateCounters(struct session_data *sdata, struct __data *data, struct __counters *counters, struct __config *cfg){
|
||||
void update_counters(struct session_data *sdata, struct __data *data, struct __counters *counters, struct __config *cfg){
|
||||
char buf[MAXBUFSIZE];
|
||||
#ifdef HAVE_MEMCACHED
|
||||
unsigned long long mc, rcvd;
|
||||
@ -57,10 +57,9 @@ void updateCounters(struct session_data *sdata, struct __data *data, struct __co
|
||||
if(memcached_increment(&(data->memc), MEMCACHED_MSGS_RCVD, strlen(MEMCACHED_MSGS_RCVD), counters->c_rcvd, &mc) == MEMCACHED_SUCCESS){
|
||||
rcvd = mc;
|
||||
|
||||
if(counters->c_ham > 0) memcached_increment(&(data->memc), MEMCACHED_MSGS_HAM, strlen(MEMCACHED_MSGS_HAM), counters->c_ham, &mc);
|
||||
if(counters->c_virus > 0) memcached_increment(&(data->memc), MEMCACHED_MSGS_VIRUS, strlen(MEMCACHED_MSGS_VIRUS), counters->c_virus, &mc);
|
||||
if(counters->c_duplicate > 0) memcached_increment(&(data->memc), MEMCACHED_MSGS_DUPLICATE, strlen(MEMCACHED_MSGS_DUPLICATE), counters->c_duplicate, &mc);
|
||||
if(counters->c_duplicate > 0) memcached_increment(&(data->memc), MEMCACHED_MSGS_IGNORE, strlen(MEMCACHED_MSGS_IGNORE), counters->c_ignore, &mc);
|
||||
if(counters->c_ignore > 0) memcached_increment(&(data->memc), MEMCACHED_MSGS_IGNORE, strlen(MEMCACHED_MSGS_IGNORE), counters->c_ignore, &mc);
|
||||
|
||||
|
||||
bzero(&c, sizeof(c));
|
||||
@ -80,7 +79,7 @@ void updateCounters(struct session_data *sdata, struct __data *data, struct __co
|
||||
if(sdata->now - mc > cfg->memcached_to_db_interval && c.c_rcvd > 0 && c.c_rcvd >= rcvd){
|
||||
snprintf(buf, SMALLBUFSIZE-1, "%ld", sdata->now); memcached_set(&(data->memc), MEMCACHED_COUNTERS_LAST_UPDATE, strlen(MEMCACHED_COUNTERS_LAST_UPDATE), buf, strlen(buf), 0, 0);
|
||||
|
||||
snprintf(buf, SMALLBUFSIZE-1, "UPDATE `%s` SET rcvd=%llu, virus=%llu, duplicate=%llu, ignore=%llu", c.c_rcvd, c.c_virus, c.c_duplicate, c.c_ignore);
|
||||
snprintf(buf, SMALLBUFSIZE-1, "UPDATE `%s` SET rcvd=%llu, virus=%llu, duplicate=%llu, ignore=%llu", SQL_COUNTER_TABLE, c.c_rcvd, c.c_virus, c.c_duplicate, c.c_ignore);
|
||||
|
||||
//if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: update counters: %s", sdata->ttmpfile, buf);
|
||||
|
||||
|
204
src/memcached.c
204
src/memcached.c
@ -1,204 +0,0 @@
|
||||
/*
|
||||
* memcached.c, SJ
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <syslog.h>
|
||||
#include <piler.h>
|
||||
|
||||
|
||||
int getUserdataFromMemcached(struct session_data *sdata, struct __data *data, char *email, struct __config *cfg){
|
||||
unsigned int len=0;
|
||||
uint32_t flags = 0;
|
||||
char key[SMALLBUFSIZE], *s=NULL, *p;
|
||||
|
||||
//if(data->memc.initialised == 0) return 0;
|
||||
|
||||
snprintf(key, SMALLBUFSIZE-1, "%s:%s", MEMCACHED_CLAPF_PREFIX, email);
|
||||
|
||||
s = memcached_get(&(data->memc), key, &len, &flags);
|
||||
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: memcached user query=%s, data=%s (%d)", sdata->ttmpfile, key, s, len);
|
||||
|
||||
if(len > 0){
|
||||
/* 1000:8:sj:acts.hu:1 */
|
||||
|
||||
if(len == 1 && s[0] == 'U'){
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: %s is unknown", sdata->ttmpfile, email);
|
||||
return 1;
|
||||
}
|
||||
|
||||
p = strchr(s, ':');
|
||||
if(p){ *p = '\0'; sdata->uid = atol(s); s = p+1; }
|
||||
|
||||
p = strchr(s, ':');
|
||||
if(p){ *p = '\0'; sdata->gid = atol(s); s = p+1; }
|
||||
|
||||
p = strchr(s, ':');
|
||||
if(p){ *p = '\0'; snprintf(sdata->name, SMALLBUFSIZE-1, "%s", s); s = p+1; }
|
||||
|
||||
p = strchr(s, ':');
|
||||
if(p){ *p = '\0'; snprintf(sdata->domain, SMALLBUFSIZE-1, "%s", s); s = p+1; }
|
||||
|
||||
sdata->policy_group = atoi(s);
|
||||
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: memcached parsed user data: uid: %ld, gid: %ld, name: %s, domain: %s, policy group: %d", sdata->ttmpfile, sdata->uid, sdata->gid, sdata->name, sdata->domain, sdata->policy_group);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int putUserdataToMemcached(struct session_data *sdata, struct __data *data, char *email, struct __config *cfg){
|
||||
uint32_t flags = 0;
|
||||
char key[SMALLBUFSIZE], value[SMALLBUFSIZE];
|
||||
|
||||
snprintf(key, SMALLBUFSIZE-1, "%s:%s", MEMCACHED_CLAPF_PREFIX, email);
|
||||
if(sdata->uid == 0)
|
||||
strcpy(value, "U");
|
||||
else
|
||||
snprintf(value, SMALLBUFSIZE-1, "%ld:%ld:%s:%s:%d", sdata->uid, sdata->gid, sdata->name, sdata->domain, sdata->policy_group);
|
||||
|
||||
if(memcached_add(&(data->memc), key, strlen(key), value, strlen(value), cfg->memcached_ttl, flags) == MEMCACHED_SUCCESS) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int getPolicyFromMemcached(struct session_data *sdata, struct __data *data, struct __config *cfg, struct __config *my_cfg){
|
||||
unsigned int len=0;
|
||||
uint32_t flags = 0;
|
||||
char key[SMALLBUFSIZE], *s=NULL, *p;
|
||||
|
||||
if(sdata->policy_group <= 0) return 0;
|
||||
|
||||
snprintf(key, SMALLBUFSIZE-1, "%s:%d", MEMCACHED_CLAPF_PREFIX, sdata->policy_group);
|
||||
|
||||
s = memcached_get(&(data->memc), key, &len, &flags);
|
||||
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: memcached policy query=%s, data=%s (%d)", sdata->ttmpfile, key, s, len);
|
||||
|
||||
if(len > 0){
|
||||
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->deliver_infected_email = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->silently_discard_infected_email = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->use_antispam = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; snprintf(my_cfg->spam_subject_prefix, MAXVAL-1, "%s", s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->enable_auto_white_list = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->max_message_size_to_filter = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; snprintf(my_cfg->rbl_domain, MAXVAL-1, "%s", s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; snprintf(my_cfg->surbl_domain, MAXVAL-1, "%s", s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->spam_overall_limit = atof(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->spaminess_oblivion_limit = atof(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->replace_junk_characters = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->invalid_junk_limit = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->invalid_junk_line = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->penalize_images = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->penalize_embed_images = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->penalize_octet_stream = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->training_mode = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->initial_1000_learning = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->store_metadata = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->store_only_spam = atoi(s); s = p+1; }
|
||||
p = strchr(s, ':'); if(p){ *p = '\0'; my_cfg->message_from_a_zombie = atoi(s); }
|
||||
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: memcached parsed policy data: spam limit: %.4f, oblivion: %.4f, subject prefix: *%s*, rbl: *%s*, training mode: %d, meta: %d",
|
||||
sdata->ttmpfile, my_cfg->spam_overall_limit, my_cfg->spaminess_oblivion_limit, my_cfg->spam_subject_prefix, my_cfg->rbl_domain, my_cfg->training_mode, my_cfg->store_metadata);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int putPolicyToMemcached(struct session_data *sdata, struct __data *data, struct __config *my_cfg){
|
||||
uint32_t flags = 0;
|
||||
char key[SMALLBUFSIZE], value[SMALLBUFSIZE];
|
||||
|
||||
if(sdata->policy_group <= 0) return 0;
|
||||
|
||||
snprintf(key, SMALLBUFSIZE-1, "%s:%d", MEMCACHED_CLAPF_PREFIX, sdata->policy_group);
|
||||
|
||||
snprintf(value, SMALLBUFSIZE-1, "%d:%d:%d:%s:%d:%ld:%s:%s:%.4f:%.4f:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
|
||||
my_cfg->deliver_infected_email,
|
||||
my_cfg->silently_discard_infected_email,
|
||||
my_cfg->use_antispam,
|
||||
my_cfg->spam_subject_prefix,
|
||||
my_cfg->enable_auto_white_list,
|
||||
my_cfg->max_message_size_to_filter,
|
||||
my_cfg->rbl_domain,
|
||||
my_cfg->surbl_domain,
|
||||
my_cfg->spam_overall_limit,
|
||||
my_cfg->spaminess_oblivion_limit,
|
||||
my_cfg->replace_junk_characters,
|
||||
my_cfg->invalid_junk_limit,
|
||||
my_cfg->invalid_junk_line,
|
||||
my_cfg->penalize_images,
|
||||
my_cfg->penalize_embed_images,
|
||||
my_cfg->penalize_octet_stream,
|
||||
my_cfg->training_mode,
|
||||
my_cfg->initial_1000_learning,
|
||||
my_cfg->store_metadata,
|
||||
my_cfg->store_only_spam,
|
||||
my_cfg->message_from_a_zombie
|
||||
);
|
||||
|
||||
|
||||
if(memcached_add(&(data->memc), key, strlen(key), value, strlen(value), my_cfg->memcached_ttl, flags) == MEMCACHED_SUCCESS) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int getWBLFromMemcached(struct session_data *sdata, struct __data *data, struct __config *cfg){
|
||||
unsigned int len=0;
|
||||
uint32_t flags = 0;
|
||||
char key[SMALLBUFSIZE], *s=NULL, *p;
|
||||
|
||||
snprintf(key, SMALLBUFSIZE-1, "%s:wbl%ld", MEMCACHED_CLAPF_PREFIX, sdata->uid);
|
||||
|
||||
s = memcached_get(&(data->memc), key, &len, &flags);
|
||||
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: memcached wbl query=%s, data=%s (%d)", sdata->ttmpfile, key, s, len);
|
||||
|
||||
if(len > 0){
|
||||
/* whiteemail1,whiteemail2:blackemail1,blackemail2 */
|
||||
|
||||
p = strchr(s, ':');
|
||||
if(p){
|
||||
*p = '\0';
|
||||
snprintf(sdata->whitelist, MAXBUFSIZE-1, "%s", s);
|
||||
snprintf(sdata->blacklist, MAXBUFSIZE-1, "%s", p+1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int putWBLToMemcached(struct session_data *sdata, struct __data *data, struct __config *cfg){
|
||||
uint32_t flags = 0;
|
||||
char key[SMALLBUFSIZE], value[2*MAXBUFSIZE];
|
||||
|
||||
if(sdata->uid <= 0) return 0;
|
||||
|
||||
snprintf(key, SMALLBUFSIZE-1, "%s:wbl%ld", MEMCACHED_CLAPF_PREFIX, sdata->uid);
|
||||
snprintf(value, 2*MAXBUFSIZE-1, "%s:%s", sdata->whitelist, sdata->blacklist);
|
||||
|
||||
if(memcached_add(&(data->memc), key, strlen(key), value, strlen(value), cfg->memcached_ttl, flags) == MEMCACHED_SUCCESS) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ int store_meta_data(struct session_data *sdata, struct _state *state, struct __c
|
||||
}
|
||||
|
||||
|
||||
int processMessage(struct session_data *sdata, struct _state *state, struct __config *cfg){
|
||||
int process_message(struct session_data *sdata, struct _state *state, struct __config *cfg){
|
||||
int i, rc;
|
||||
|
||||
/* discard if existing message_id */
|
||||
|
@ -80,65 +80,79 @@ void init_state(struct _state *state){
|
||||
}
|
||||
|
||||
|
||||
unsigned long parse_date_header(char *s){
|
||||
char *p;
|
||||
unsigned long parse_date_header(char *datestr){
|
||||
int n=0;
|
||||
char *p, *q, *r, s[SMALLBUFSIZE];
|
||||
unsigned long ts=0;
|
||||
struct tm tm;
|
||||
|
||||
s += 5;
|
||||
p = s;
|
||||
datestr += 5;
|
||||
p = datestr;
|
||||
|
||||
if(*p == ' '){ p++; s++; }
|
||||
|
||||
p = strchr(s, ',');
|
||||
if(!p) goto ENDE;
|
||||
for(; *datestr; datestr++){
|
||||
if(isspace(*datestr)) *datestr = ' ';
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
if(strcmp(s, "Mon") == 0) tm.tm_wday = 1;
|
||||
else if(strcmp(s, "Tue") == 0) tm.tm_wday = 2;
|
||||
else if(strcmp(s, "Wed") == 0) tm.tm_wday = 3;
|
||||
else if(strcmp(s, "Thu") == 0) tm.tm_wday = 4;
|
||||
else if(strcmp(s, "Fri") == 0) tm.tm_wday = 5;
|
||||
else if(strcmp(s, "Sat") == 0) tm.tm_wday = 6;
|
||||
else if(strcmp(s, "Sun") == 0) tm.tm_wday = 0;
|
||||
s += 5;
|
||||
|
||||
p = strchr(s, ' '); if(!p) goto ENDE;
|
||||
*p = '\0'; tm.tm_mday = atoi(s); s += 3;
|
||||
if(*p == ' '){ p++; }
|
||||
|
||||
p = strchr(s, ' '); if(!p) goto ENDE;
|
||||
*p = '\0';
|
||||
if(strcmp(s, "Jan") == 0) tm.tm_mon = 0;
|
||||
else if(strcmp(s, "Feb") == 0) tm.tm_mon = 1;
|
||||
else if(strcmp(s, "Mar") == 0) tm.tm_mon = 2;
|
||||
else if(strcmp(s, "Apr") == 0) tm.tm_mon = 3;
|
||||
else if(strcmp(s, "May") == 0) tm.tm_mon = 4;
|
||||
else if(strcmp(s, "Jun") == 0) tm.tm_mon = 5;
|
||||
else if(strcmp(s, "Jul") == 0) tm.tm_mon = 6;
|
||||
else if(strcmp(s, "Aug") == 0) tm.tm_mon = 7;
|
||||
else if(strcmp(s, "Sep") == 0) tm.tm_mon = 8;
|
||||
else if(strcmp(s, "Oct") == 0) tm.tm_mon = 9;
|
||||
else if(strcmp(s, "Nov") == 0) tm.tm_mon = 10;
|
||||
else if(strcmp(s, "Dec") == 0) tm.tm_mon = 11;
|
||||
s = p+1;
|
||||
do {
|
||||
p = split_str(p, " ", s, sizeof(s)-1);
|
||||
if(strlen(s) > 0){
|
||||
n++;
|
||||
|
||||
p = strchr(s, ' '); if(!p) goto ENDE;
|
||||
tm.tm_year = atoi(s) - 1900; s = p+1;
|
||||
q = strchr(s, ','); if(q) *q='\0';
|
||||
|
||||
p = strchr(s, ':'); if(!p) goto ENDE;
|
||||
*p = '\0'; tm.tm_hour = atoi(s); s = p+1;
|
||||
if(strlen(s) <= 2){ tm.tm_mday = atoi(s); continue; }
|
||||
|
||||
p = strchr(s, ':'); if(!p) goto ENDE;
|
||||
*p = '\0'; tm.tm_min = atoi(s); s = p+1;
|
||||
if(strlen(s) == 4){ tm.tm_year = atoi(s) - 1900; continue; }
|
||||
|
||||
p = strchr(s, ' '); if(!p) goto ENDE;
|
||||
*p = '\0'; tm.tm_sec = atoi(s); s = p+1;
|
||||
if(strlen(s) == 3){
|
||||
if(strcmp(s, "Mon") == 0) tm.tm_wday = 1;
|
||||
else if(strcmp(s, "Tue") == 0) tm.tm_wday = 2;
|
||||
else if(strcmp(s, "Wed") == 0) tm.tm_wday = 3;
|
||||
else if(strcmp(s, "Thu") == 0) tm.tm_wday = 4;
|
||||
else if(strcmp(s, "Fri") == 0) tm.tm_wday = 5;
|
||||
else if(strcmp(s, "Sat") == 0) tm.tm_wday = 6;
|
||||
else if(strcmp(s, "Sun") == 0) tm.tm_wday = 0;
|
||||
|
||||
|
||||
if(strcmp(s, "Jan") == 0) tm.tm_mon = 0;
|
||||
else if(strcmp(s, "Feb") == 0) tm.tm_mon = 1;
|
||||
else if(strcmp(s, "Mar") == 0) tm.tm_mon = 2;
|
||||
else if(strcmp(s, "Apr") == 0) tm.tm_mon = 3;
|
||||
else if(strcmp(s, "May") == 0) tm.tm_mon = 4;
|
||||
else if(strcmp(s, "Jun") == 0) tm.tm_mon = 5;
|
||||
else if(strcmp(s, "Jul") == 0) tm.tm_mon = 6;
|
||||
else if(strcmp(s, "Aug") == 0) tm.tm_mon = 7;
|
||||
else if(strcmp(s, "Sep") == 0) tm.tm_mon = 8;
|
||||
else if(strcmp(s, "Oct") == 0) tm.tm_mon = 9;
|
||||
else if(strcmp(s, "Nov") == 0) tm.tm_mon = 10;
|
||||
else if(strcmp(s, "Dec") == 0) tm.tm_mon = 11;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(strlen(s) == 8){
|
||||
r = &s[0];
|
||||
|
||||
q = strchr(r, ':'); if(!q) break;
|
||||
*q = '\0'; tm.tm_hour = atoi(r); r = q+1;
|
||||
|
||||
q = strchr(r, ':'); if(!q) break;
|
||||
*q = '\0'; tm.tm_min = atoi(r); r = q+1;
|
||||
|
||||
tm.tm_sec = atoi(r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while(p);
|
||||
|
||||
tm.tm_isdst = -1;
|
||||
|
||||
ts = mktime(&tm);
|
||||
|
||||
ENDE:
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
280
src/piler.c
280
src/piler.c
@ -28,16 +28,216 @@ extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
int sd;
|
||||
int nconn = 0;
|
||||
int quit = 0;
|
||||
int received_sighup = 0;
|
||||
char *configfile = CONFIG_FILE;
|
||||
struct __config cfg;
|
||||
struct __data data;
|
||||
struct passwd *pwd;
|
||||
|
||||
struct child children[MAXCHILDREN];
|
||||
|
||||
|
||||
signal_func *set_signal_handler(int signo, signal_func * func);
|
||||
static void takesig(int sig);
|
||||
static void child_sighup_handler(int sig);
|
||||
static void child_main(struct child *ptr);
|
||||
static pid_t child_make(struct child *ptr);
|
||||
int search_slot_by_pid(pid_t pid);
|
||||
void kill_children(int sig);
|
||||
void clean_exit();
|
||||
void initialise_configuration();
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* most of the preforking code was taken from the tinyproxy project
|
||||
*/
|
||||
|
||||
signal_func *set_signal_handler(int signo, signal_func * func){
|
||||
struct sigaction act, oact;
|
||||
|
||||
act.sa_handler = func;
|
||||
sigemptyset (&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
|
||||
if(sigaction(signo, &act, &oact) < 0) return SIG_ERR;
|
||||
|
||||
return oact.sa_handler;
|
||||
}
|
||||
|
||||
|
||||
static void takesig(int sig){
|
||||
int i, status;
|
||||
pid_t pid;
|
||||
|
||||
switch(sig){
|
||||
case SIGHUP:
|
||||
initialise_configuration();
|
||||
kill_children(SIGHUP);
|
||||
break;
|
||||
|
||||
case SIGTERM:
|
||||
case SIGKILL:
|
||||
quit = 1;
|
||||
clean_exit();
|
||||
break;
|
||||
|
||||
case SIGCHLD:
|
||||
while((pid = waitpid (-1, &status, WNOHANG)) > 0){
|
||||
|
||||
//syslog(LOG_PRIORITY, "child (pid: %d) has died", pid);
|
||||
|
||||
if(quit == 0){
|
||||
i = search_slot_by_pid(pid);
|
||||
if(i >= 0){
|
||||
children[i].status = READY;
|
||||
children[i].pid = child_make(&children[i]);
|
||||
}
|
||||
else syslog(LOG_PRIORITY, "error: couldn't find slot for pid %d", pid);
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void child_sighup_handler(int sig){
|
||||
if(sig == SIGHUP){
|
||||
received_sighup = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void child_main(struct child *ptr){
|
||||
int new_sd;
|
||||
unsigned int clen;
|
||||
struct sockaddr_in client_addr;
|
||||
|
||||
ptr->messages = 0;
|
||||
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child (pid: %d) started main()", getpid());
|
||||
|
||||
while(1){
|
||||
if(received_sighup == 1){
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child (pid: %d) caught HUP signal", getpid());
|
||||
break;
|
||||
}
|
||||
|
||||
ptr->status = READY;
|
||||
|
||||
clen = sizeof(client_addr);
|
||||
|
||||
new_sd = accept(sd, (struct sockaddr *)&client_addr, &clen);
|
||||
|
||||
if(new_sd == -1) continue;
|
||||
|
||||
ptr->status = BUSY;
|
||||
|
||||
syslog(LOG_PRIORITY, "child (pid: %d) connection from %s", getpid(), inet_ntoa(client_addr.sin_addr));
|
||||
|
||||
sig_block(SIGHUP);
|
||||
ptr->messages += handle_smtp_session(new_sd, &data, &cfg);
|
||||
sig_unblock(SIGHUP);
|
||||
|
||||
close(new_sd);
|
||||
|
||||
if(cfg.max_requests_per_child > 0 && ptr->messages >= cfg.max_requests_per_child){
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child (pid: %d) served enough: %d", getpid(), ptr->messages);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ptr->status = UNDEF;
|
||||
|
||||
#ifdef HAVE_MEMCACHED
|
||||
memcached_shutdown(&(data.memc));
|
||||
#endif
|
||||
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child decides to exit (pid: %d)", getpid());
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static pid_t child_make(struct child *ptr){
|
||||
pid_t pid;
|
||||
|
||||
if((pid = fork()) > 0) return pid;
|
||||
|
||||
if(pid == -1) return -1;
|
||||
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "forked a child (pid: %d)", getpid());
|
||||
|
||||
/* reset signals */
|
||||
|
||||
set_signal_handler(SIGCHLD, SIG_DFL);
|
||||
set_signal_handler(SIGTERM, SIG_DFL);
|
||||
set_signal_handler(SIGHUP, child_sighup_handler);
|
||||
|
||||
child_main(ptr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int child_pool_create(){
|
||||
int i;
|
||||
|
||||
for(i=0; i<MAXCHILDREN; i++){
|
||||
children[i].pid = 0;
|
||||
children[i].messages = 0;
|
||||
children[i].status = UNDEF;
|
||||
}
|
||||
|
||||
for(i=0; i<cfg.number_of_worker_processes; i++){
|
||||
children[i].status = READY;
|
||||
children[i].pid = child_make(&children[i]);
|
||||
|
||||
if(children[i].pid == -1){
|
||||
syslog(LOG_PRIORITY, "error: failed to fork a child");
|
||||
clean_exit();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int search_slot_by_pid(pid_t pid){
|
||||
int i;
|
||||
|
||||
for(i=0; i<MAXCHILDREN; i++){
|
||||
if(children[i].pid == pid) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void kill_children(int sig){
|
||||
int i;
|
||||
|
||||
for(i=0; i<MAXCHILDREN; i++){
|
||||
if(children[i].status != UNDEF && children[i].pid > 1){
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "sending signal to child (pid: %d)", children[i].pid);
|
||||
kill(children[i].pid, sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clean_exit(){
|
||||
if(sd != -1) close(sd);
|
||||
|
||||
kill_children(SIGTERM);
|
||||
|
||||
free_rule(data.rules);
|
||||
|
||||
syslog(LOG_PRIORITY, "%s has been terminated", PROGNAME);
|
||||
@ -54,20 +254,14 @@ void fatal(char *s){
|
||||
}
|
||||
|
||||
|
||||
void sigchld(){
|
||||
int pid, wstat;
|
||||
|
||||
while((pid = wait_nohang(&wstat)) > 0){
|
||||
if(nconn > 0) nconn--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void initialise_configuration(){
|
||||
struct session_data sdata;
|
||||
|
||||
cfg = read_config(configfile);
|
||||
|
||||
if(cfg.number_of_worker_processes < 5) cfg.number_of_worker_processes = 5;
|
||||
if(cfg.number_of_worker_processes > MAXCHILDREN) cfg.number_of_worker_processes = MAXCHILDREN;
|
||||
|
||||
if(strlen(cfg.username) > 1){
|
||||
pwd = getpwnam(cfg.username);
|
||||
if(!pwd) fatal(ERR_NON_EXISTENT_USER);
|
||||
@ -112,9 +306,8 @@ void initialise_configuration(){
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int i, new_sd, yes=1, pid, daemonise=0;
|
||||
unsigned int clen;
|
||||
struct sockaddr_in client_addr, serv_addr;
|
||||
int i, yes=1, daemonise=0;
|
||||
struct sockaddr_in serv_addr;
|
||||
struct in_addr addr;
|
||||
|
||||
while((i = getopt(argc, argv, "c:dvVh")) > 0){
|
||||
@ -141,22 +334,13 @@ int main(int argc, char **argv){
|
||||
|
||||
(void) openlog(PROGNAME, LOG_PID, LOG_MAIL);
|
||||
|
||||
sig_catch(SIGINT, clean_exit);
|
||||
sig_catch(SIGQUIT, clean_exit);
|
||||
sig_catch(SIGKILL, clean_exit);
|
||||
sig_catch(SIGTERM, clean_exit);
|
||||
sig_catch(SIGHUP, initialise_configuration);
|
||||
|
||||
|
||||
data.rules = NULL;
|
||||
|
||||
|
||||
sig_block(SIGCHLD);
|
||||
sig_catch(SIGCHLD, sigchld);
|
||||
|
||||
|
||||
initialise_configuration();
|
||||
|
||||
set_signal_handler (SIGPIPE, SIG_IGN);
|
||||
|
||||
|
||||
if(read_key(&cfg)) fatal(ERR_READING_KEY);
|
||||
|
||||
@ -193,51 +377,17 @@ int main(int argc, char **argv){
|
||||
write_pid_file(cfg.pidfile);
|
||||
|
||||
|
||||
/* main accept loop */
|
||||
child_pool_create();
|
||||
|
||||
for(;;){
|
||||
set_signal_handler(SIGCHLD, takesig);
|
||||
set_signal_handler(SIGTERM, takesig);
|
||||
set_signal_handler(SIGKILL, takesig);
|
||||
set_signal_handler(SIGHUP, takesig);
|
||||
|
||||
/* let new connections wait if we are too busy now */
|
||||
|
||||
if(nconn >= cfg.max_connections) sig_pause();
|
||||
for(;;){ sleep(1); }
|
||||
|
||||
clen = sizeof(client_addr);
|
||||
|
||||
sig_unblock(SIGCHLD);
|
||||
new_sd = accept(sd, (struct sockaddr *)&client_addr, &clen);
|
||||
sig_block(SIGCHLD);
|
||||
|
||||
if(new_sd == -1) continue;
|
||||
|
||||
pid = fork();
|
||||
|
||||
if(pid == 0){
|
||||
sig_uncatch(SIGCHLD);
|
||||
sig_unblock(SIGCHLD);
|
||||
|
||||
sig_uncatch(SIGINT);
|
||||
sig_uncatch(SIGQUIT);
|
||||
sig_uncatch(SIGKILL);
|
||||
sig_uncatch(SIGTERM);
|
||||
sig_block(SIGHUP);
|
||||
|
||||
syslog(LOG_PRIORITY, "connection from client: %s", inet_ntoa(client_addr.sin_addr));
|
||||
|
||||
handle_smtp_session(new_sd, &data, &cfg);
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
else if(pid > 0){
|
||||
nconn++;
|
||||
}
|
||||
|
||||
else {
|
||||
syslog(LOG_PRIORITY, "%s", ERR_FORK_FAILED);
|
||||
}
|
||||
|
||||
close(new_sd);
|
||||
}
|
||||
clean_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <parser.h>
|
||||
#include <errmsg.h>
|
||||
#include <smtpcodes.h>
|
||||
#include <session.h>
|
||||
#include <decoder.h>
|
||||
#include <list.h>
|
||||
#include <rules.h>
|
||||
@ -33,7 +32,9 @@ int do_av_check(struct session_data *sdata, char *rcpttoemail, char *fromemail,
|
||||
int make_digests(struct session_data *sdata, struct __config *cfg);
|
||||
void digest_file(char *filename, char *digest);
|
||||
|
||||
int processMessage(struct session_data *sdata, struct _state *sstate, struct __config *cfg);
|
||||
int handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg);
|
||||
|
||||
int process_message(struct session_data *sdata, struct _state *sstate, struct __config *cfg);
|
||||
int store_file(struct session_data *sdata, char *filename, int startpos, int len, struct __config *cfg);
|
||||
int store_attachments(struct session_data *sdata, struct _state *state, struct __config *cfg);
|
||||
int query_attachments(struct session_data *sdata, struct ptr_array *ptr_arr, struct __config *cfg);
|
||||
@ -42,7 +43,7 @@ struct __config read_config(char *configfile);
|
||||
|
||||
void check_and_create_directories(struct __config *cfg, uid_t uid, gid_t gid);
|
||||
|
||||
void updateCounters(struct session_data *sdata, struct __data *data, struct __counters *counters, struct __config *cfg);
|
||||
void update_counters(struct session_data *sdata, struct __data *data, struct __counters *counters, struct __config *cfg);
|
||||
|
||||
#endif /* _PILER_H */
|
||||
|
||||
|
@ -48,15 +48,6 @@ int import_message(char *filename, struct session_data *sdata, struct __data *da
|
||||
|
||||
if(sdata->sent > sdata->now) sdata->sent = sdata->now;
|
||||
|
||||
/*printf("message-id: %s\n", state.message_id);
|
||||
printf("from: *%s*\n", state.b_from);
|
||||
printf("to: *%s*\n", state.b_to);
|
||||
printf("subject: *%s*\n", state.b_subject);
|
||||
printf("attachments:%s\n", sdata->attachments);
|
||||
printf("direction: %d\n", sdata->direction);*/
|
||||
|
||||
|
||||
|
||||
|
||||
rule = check_againt_ruleset(data->rules, &state, st.st_size);
|
||||
|
||||
@ -68,7 +59,7 @@ int import_message(char *filename, struct session_data *sdata, struct __data *da
|
||||
|
||||
make_digests(sdata, cfg);
|
||||
|
||||
rc = processMessage(sdata, &state, cfg);
|
||||
rc = process_message(sdata, &state, cfg);
|
||||
|
||||
ENDE:
|
||||
unlink(sdata->tmpframe);
|
||||
@ -87,8 +78,6 @@ ENDE:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <piler.h>
|
||||
|
||||
|
||||
void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
|
||||
int handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
|
||||
int i, ret, pos, n, inj=ERR, state, prevlen=0;
|
||||
char *p, buf[MAXBUFSIZE], puf[MAXBUFSIZE], resp[MAXBUFSIZE], prevbuf[MAXBUFSIZE], last2buf[2*MAXBUFSIZE+1];
|
||||
char rctptoemail[SMALLBUFSIZE], fromemail[SMALLBUFSIZE], virusinfo[SMALLBUFSIZE], reason[SMALLBUFSIZE];
|
||||
@ -31,9 +31,6 @@ void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
|
||||
struct timeval tv1, tv2;
|
||||
|
||||
|
||||
alarm(cfg->session_timeout);
|
||||
sig_catch(SIGALRM, killChild);
|
||||
|
||||
state = SMTP_STATE_INIT;
|
||||
|
||||
init_session_data(&sdata);
|
||||
@ -60,8 +57,6 @@ void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
|
||||
syslog(LOG_PRIORITY, "%s", ERR_MYSQL_CONNECT);
|
||||
#endif
|
||||
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: fork()", sdata.ttmpfile);
|
||||
|
||||
|
||||
gettimeofday(&tv1, &tz);
|
||||
|
||||
@ -206,7 +201,7 @@ void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
|
||||
counters.c_ignore++;
|
||||
}
|
||||
else {
|
||||
inj = processMessage(&sdata, &sstate, cfg);
|
||||
inj = process_message(&sdata, &sstate, cfg);
|
||||
}
|
||||
|
||||
}
|
||||
@ -248,8 +243,6 @@ void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
|
||||
unlink(sdata.tmpframe);
|
||||
|
||||
|
||||
alarm(cfg->session_timeout);
|
||||
|
||||
/* if we have nothing after the trailing (.), we can read
|
||||
the next command from the network */
|
||||
|
||||
@ -467,26 +460,15 @@ AFTER_PERIOD:
|
||||
|
||||
QUITTING:
|
||||
|
||||
updateCounters(&sdata, data, &counters, cfg);
|
||||
update_counters(&sdata, data, &counters, cfg);
|
||||
|
||||
#ifdef NEED_MYSQL
|
||||
mysql_close(&(sdata.mysql));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMCACHED
|
||||
memcached_shutdown(&(data->memc));
|
||||
#endif
|
||||
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child has finished");
|
||||
|
||||
if(cfg->verbosity >= _LOG_INFO) syslog(LOG_PRIORITY, "processed %llu messages", counters.c_rcvd);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void killChild(){
|
||||
syslog(LOG_PRIORITY, "child is killed by force");
|
||||
exit(0);
|
||||
return (int)counters.c_rcvd;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
/*
|
||||
* session.h, SJ
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg);
|
||||
void initSessionData(struct session_data *sdata);
|
||||
void killChild();
|
||||
|
@ -75,6 +75,8 @@ int main(int argc, char **argv){
|
||||
printf("subject: *%s*\n", state.b_subject);
|
||||
//printf("body: *%s*\n", state.b_body);
|
||||
|
||||
printf("sent: %ld\n", sdata.sent);
|
||||
|
||||
make_digests(&sdata, &cfg);
|
||||
|
||||
printf("hdr len: %d\n", sdata.hdr_len);
|
||||
|
Reference in New Issue
Block a user