304 lines
8.6 KiB
C
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;
|
|
}
|
|
|