Files
smmapdfw/smmapdfw/recpverify_worker/recpveri_worker.c
whottgen 97f9dc139f changes
2007-06-06 09:07:27 +00:00

304 lines
8.6 KiB
C

/*
Copyright (C) 2004, Wolfgang Hottgenroth
This file is part of smmapdfw.
smmapdfw 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.
smmapdfw 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 smmapdfw. If not, write to the Free Software Foundation, 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include "containers_public.h"
#include "smmapd.h"
#include "smtp.h"
#include "htdns.h"
#include "htmalloc.h"
#include "htbuffer.h"
#include "stats.h"
#define SMM_LOCAL_PERM_NOK 101
#define SMM_LOCAL_TEMP_NOK 102
#define SMM_LOCAL_OK 103
counterDef_t *recpveri_counterDefs = NULL;
void recpveri_setupCounterList() {
recpveri_counterDefs = addOneCounterDef(recpveri_counterDefs, SMM_TYPE_COUNTER, "RecpVeri: checker");
recpveri_counterDefs = addOneCounterDef(recpveri_counterDefs, SMM_TYPE_COUNTER, "RecpVeri: illegal input");
recpveri_counterDefs = addOneCounterDef(recpveri_counterDefs, SMM_TYPE_COUNTER, "RecpVeri: dns failure");
recpveri_counterDefs = addOneCounterDef(recpveri_counterDefs, SMM_TYPE_COUNTER, "RecpVeri: returned OK");
recpveri_counterDefs = addOneCounterDef(recpveri_counterDefs, SMM_TYPE_COUNTER, "RecpVeri: returned NOK");
recpveri_counterDefs = addOneCounterDef(recpveri_counterDefs, SMM_TYPE_COUNTER, "RecpVeri: returned TNOK");
};
#define STAT_CNT_RECPVERI_WORKER 0
#define STAT_CNT_RECPVERI_ILLEGAL_INPUT 1
#define STAT_CNT_RECPVERI_DNS_FAILURE 2
#define STAT_CNT_RECPVERI_RETURNED_OK 3
#define STAT_CNT_RECPVERI_RETURNED_NOK 4
#define STAT_CNT_RECPVERI_RETURNED_TNOK 5
struct recpveri_container_handle_s {
cfgl_t *cfg;
statCounter_t *statCounter;
int timeout;
char *sender_address;
char *ehlo_arg;
int smtp_port;
};
typedef struct recpveri_container_handle_s recpveri_container_handle_t;
struct recpveri_work_handle_s {
int id;
recpveri_container_handle_t *rvch;
};
typedef struct recpveri_work_handle_s recpveri_work_handle_t;
int recpveri_init(cfgl_t *cfg, void **handle);
int recpveri_destroy(void *handle);
/* int recpveri_work_setup(void *handle, void **work_handle); */
int recpveri_work(void *handle, void *work_handle, char *input, htbuffer_t *output);
/* int recpveri_work_destroy(void *handle, void *work_handle); */
class_descriptor_t recpvericheck = {
"recpvericheck",
&recpveri_init,
&recpveri_destroy,
NULL, /* &recpveri_work_setup, */
&recpveri_work,
NULL /* &recpveri_work_destroy */
};
int recpveri_init(cfgl_t *cfg, void **handle) {
recpveri_container_handle_t *rvch;
rvch = (recpveri_container_handle_t*) htmalloc(sizeof(recpveri_container_handle_t));
rvch->cfg = cfg;
rvch->timeout = atoi(findcfglx(rvch->cfg, "timeout", "5"));
rvch->sender_address = findcfglx(rvch->cfg, "sender_address", "<>");
rvch->ehlo_arg = findcfglx(rvch->cfg, "ehlo_arg", "local");
rvch->smtp_port = atoi(findcfglx(rvch->cfg, "smtp_port", "25"));
recpveri_setupCounterList();
rvch->statCounter = initStatCounter("recpveri", recpveri_counterDefs);
*handle = rvch;
return 0;
}
int recpveri_destroy(void *handle) {
recpveri_container_handle_t *rvch = (recpveri_container_handle_t*)handle;
free(rvch);
return 0;
}
int recpveri_work(void *handle, void *work_handle, char *input, htbuffer_t *output) {
static const char *DEFAULT_ANSWER = "default answer";
static const char *ILLEGAL_INPUT = "illegal input (must be 'mailaddress mailserver')";
static const char *UNEXPECTED_ERROR = "unexpected error in smtp dialog";
static const char *TIMEOUT_ERROR = "timeout on smtp dialog";
static const char *GO_AHEAD = "go ahead";
static const char *DNS_ERROR = "mailserver could not be found in dns";
static int log_id = 0;
recpveri_container_handle_t *rvch = (recpveri_container_handle_t*) handle;
int result = SMM_TEMP_NOK;
char *mailaddress, *mailserver, *response_text, *tmp_arg;
smtp_t *smtp;
a_rdata_t **a_rdata;
int ip_address, done=0, err;
enum {
CONNECT, EHLO, MAILFROM, RCPTTO, RSET, QUIT, END
} state = CONNECT;
log_id++;
syslog(LOG_DEBUG, "recpveri_work: (%04x) going to check %s", log_id, input);
incStatCounter(rvch->statCounter, STAT_CNT_RECPVERI_WORKER);
mailaddress = input;
if (NULL == (mailserver = strchr(mailaddress, ' '))) {
// snprintf(output, ANSWER_BUFSIZE, ILLEGAL_INPUT);
htbuffer_strcpy(output, ILLEGAL_INPUT);
incStatCounter(rvch->statCounter, STAT_CNT_RECPVERI_ILLEGAL_INPUT);
return SMM_PERM_NOK;
}
*mailserver = '\0';
mailserver++;
a_rdata = get_a_rrs(mailserver);
if (NULL == a_rdata) {
syslog(LOG_DEBUG, "recpveri_work: (%04x) mailserver %s could not be found in dns",
log_id, mailserver);
// snprintf(output, ANSWER_BUFSIZE, DEPOT_DNS_ERROR);
htbuffer_strcpy(output, DNS_ERROR);
incStatCounter(rvch->statCounter, STAT_CNT_RECPVERI_DNS_FAILURE);
return SMM_TEMP_NOK;
}
ip_address = (*a_rdata)->address;
free_rrs((void**)a_rdata);
syslog(LOG_DEBUG, "recpveri_work: (%04x) mailaddress %s, mailserver %s", log_id,
mailaddress, mailserver);
smtp = smtp_init(ip_address, rvch->smtp_port, rvch->timeout);
while ((END != state) && (0 == done)) {
syslog(LOG_DEBUG, "recpveri_work: (%04x) smtp dialog state %d", log_id, state);
switch(state) {
case CONNECT:
err = smtp_connect(smtp);
break;
case EHLO:
err = smtp_ehlo(smtp, rvch->ehlo_arg);
break;
case MAILFROM:
err = smtp_mailfrom(smtp, rvch->sender_address);
break;
case RCPTTO:
tmp_arg = (char*) htmalloc(sizeof(char) * (strlen(mailaddress)+5));
*tmp_arg = '\0';
strcat(tmp_arg, "<");
strcat(tmp_arg, mailaddress);
strcat(tmp_arg, ">");
err = smtp_rcptto(smtp, tmp_arg);
free(tmp_arg);
break;
case RSET:
err = smtp_rset(smtp);
break;
case QUIT:
err = smtp_quit(smtp);
break;
}
state++;
switch(err) {
case SMTP_TIMEOUT:
syslog(LOG_DEBUG, "recpveri_work: (%04x) timeout in smtp dialog", log_id);
result = SMM_LOCAL_TEMP_NOK;
response_text = (char*)TIMEOUT_ERROR;
done = 1;
break;
case 0:
/* evaluate smtp_response, return or continue */
err = smtp_response(smtp, &response_text);
if (-1 == err) {
syslog(LOG_DEBUG, "recpveri_work: (%04x) response could not be parsed", log_id);
result = SMM_LOCAL_TEMP_NOK;
response_text = (char*)UNEXPECTED_ERROR;
done = 1;
break;
}
syslog(LOG_DEBUG, "recpveri_work: (%04x) response: %d, %s", log_id,
err, response_text);
switch(err/100) {
case 4:
result = SMM_LOCAL_TEMP_NOK;
done = 1;
break;
case 5:
result = SMM_LOCAL_PERM_NOK;
done = 1;
break;
case 2:
if (END == state) {
result = SMM_LOCAL_OK;
response_text = (char*)GO_AHEAD;
done = 1;
break;
}
}
break;
default:
syslog(LOG_DEBUG, "recpveri_work: (%04x) unexpected error in smtp dialog", log_id);
result = SMM_LOCAL_TEMP_NOK;
response_text = (char*)UNEXPECTED_ERROR;
done = 1;
break;
}
}
smtp_close(smtp);
switch (result) {
case SMM_LOCAL_TEMP_NOK:
htbuffer_strcat(output, "<TNOK><");
htbuffer_strcat(output, response_text);
htbuffer_strcat(output, ">");
//snprintf(output, ANSWER_BUFSIZE, "<TNOK><%s>", response_text);
result = SMM_OK;
incStatCounter(rvch->statCounter, STAT_CNT_RECPVERI_RETURNED_TNOK);
break;
case SMM_LOCAL_PERM_NOK:
htbuffer_strcat(output, "<NOK><");
htbuffer_strcat(output, response_text);
htbuffer_strcat(output, ">");
//snprintf(output, ANSWER_BUFSIZE, "<NOK><%s>", response_text);
result = SMM_OK;
incStatCounter(rvch->statCounter, STAT_CNT_RECPVERI_RETURNED_NOK);
break;
case SMM_LOCAL_OK:
htbuffer_strcat(output, "<OK><");
htbuffer_strcat(output, response_text);
htbuffer_strcat(output, ">");
//snprintf(output, ANSWER_BUFSIZE, "<OK><%s>", response_text);
result = SMM_OK;
incStatCounter(rvch->statCounter, STAT_CNT_RECPVERI_RETURNED_OK);
break;
default:
htbuffer_strcpy(output, response_text);
//snprintf(output, ANSWER_BUFSIZE, response_text);
break;
}
smtp_destroy(smtp);
syslog(LOG_DEBUG, "recpveri_work: (%04x) result %d, %s", log_id,
result, output->buf);
return result;
}