/* 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 #include #include #include "containers_public.h" #include "smmapd.h" #include "smtp.h" #include "htdns.h" #define SMM_LOCAL_PERM_NOK 101 #define SMM_LOCAL_TEMP_NOK 102 #define SMM_LOCAL_OK 103 struct cyrus_container_handle_s { cfgl_t *cfg; int timeout; char *sender_address; char *lhlo_arg; int lmtp_port; }; typedef struct cyrus_container_handle_s cyrus_container_handle_t; struct cyrus_work_handle_s { int id; cyrus_container_handle_t *cch; }; typedef struct cyrus_work_handle_s cyrus_work_handle_t; int cyrus_init(cfgl_t *cfg, void **handle); int cyrus_destroy(void *handle); /* int cyrus_work_setup(void *handle, void **work_handle); */ int cyrus_work(void *handle, void *work_handle, char *input, char *output); /* int cyrus_work_destroy(void *handle, void *work_handle); */ class_descriptor_t cyruscheck = { "cyruscheck", &cyrus_init, &cyrus_destroy, NULL, /* &cyrus_work_setup, */ &cyrus_work, NULL /* &cyrus_work_destroy */ }; int cyrus_init(cfgl_t *cfg, void **handle) { cyrus_container_handle_t *cch; cch = (cyrus_container_handle_t*) malloc(sizeof(cyrus_container_handle_t)); cch->cfg = cfg; cch->timeout = atoi(findcfglx(cch->cfg, "timeout", "5")); cch->sender_address = findcfglx(cch->cfg, "sender_address", "<>"); cch->lhlo_arg = findcfglx(cch->cfg, "lhlo_arg", "local"); cch->lmtp_port = atoi(findcfglx(cch->cfg, "lmtp_port", "24")); *handle = cch; return 0; } int cyrus_destroy(void *handle) { cyrus_container_handle_t *cch = (cyrus_container_handle_t*)handle; free(cch); return 0; } int cyrus_work(void *handle, void *work_handle, char *input, char *output) { static const char *DEFAULT_ANSWER = "default answer"; static const char *ILLEGAL_INPUT = "illegal input (must be 'depot_uid depot_host')"; static const char *UNEXPECTED_ERROR = "unexpected error in lmtp dialog"; static const char *TIMEOUT_ERROR = "timeout on lmtp dialog"; static const char *GO_AHEAD = "go ahead"; static const char *DEPOT_DNS_ERROR = "depot could not be found in dns"; static int log_id = 0; cyrus_container_handle_t *cch = (cyrus_container_handle_t*) handle; int result = SMM_TEMP_NOK; char *depot_uid, *depot_host, *response_text, *tmp_arg; smtp_t *lmtp; a_rdata_t **a_rdata; int ip_address, done=0, err; enum { CONNECT, LHLO, MAILFROM, RCPTTO, RSET, QUIT, END } state = CONNECT; log_id++; syslog(LOG_DEBUG, "cyrus_work: (%04x) going to check %s", log_id, input); depot_uid = input; if (NULL == (depot_host = strchr(depot_uid, ' '))) { snprintf(output, ANSWER_BUFSIZE, ILLEGAL_INPUT); return SMM_PERM_NOK; } *depot_host = '\0'; depot_host++; a_rdata = get_a_rrs(depot_host); if (NULL == a_rdata) { syslog(LOG_DEBUG, "cyrus_work: (%04x) depot_host %s could not be found in dns", log_id, depot_host); snprintf(output, ANSWER_BUFSIZE, DEPOT_DNS_ERROR); return SMM_TEMP_NOK; } ip_address = (*a_rdata)->address; free_rrs((void**)a_rdata); syslog(LOG_DEBUG, "cyrus_work: (%04x) depot_uid %s, depot_host %s", log_id, depot_uid, depot_host); lmtp = smtp_init(ip_address, cch->lmtp_port, cch->timeout); while ((END != state) && (0 == done)) { syslog(LOG_DEBUG, "cyrus_work: (%04x) lmtp dialog state %d", log_id, state); switch(state) { case CONNECT: err = smtp_connect(lmtp); break; case LHLO: err = smtp_lhlo(lmtp, cch->lhlo_arg); break; case MAILFROM: err = smtp_mailfrom(lmtp, cch->sender_address); break; case RCPTTO: tmp_arg = (char*) malloc(sizeof(char) * (strlen(depot_uid)+5)); *tmp_arg = '\0'; strcat(tmp_arg, "<"); strcat(tmp_arg, depot_uid); strcat(tmp_arg, ">"); err = smtp_rcptto(lmtp, tmp_arg); free(tmp_arg); break; case RSET: err = smtp_rset(lmtp); break; case QUIT: err = smtp_quit(lmtp); break; } state++; switch(err) { case SMTP_TIMEOUT: syslog(LOG_DEBUG, "cyrus_work: (%04x) timeout in lmtp 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(lmtp, &response_text); if (-1 == err) { syslog(LOG_DEBUG, "cyrus_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, "cyrus_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, "cyrus_work: (%04x) unexpected error in lmtp dialog", log_id); result = SMM_LOCAL_TEMP_NOK; response_text = (char*)UNEXPECTED_ERROR; done = 1; break; } } smtp_close(lmtp); switch (result) { case SMM_LOCAL_TEMP_NOK: snprintf(output, ANSWER_BUFSIZE, "<%s>", response_text); result = SMM_OK; break; case SMM_LOCAL_PERM_NOK: snprintf(output, ANSWER_BUFSIZE, "<%s>", response_text); result = SMM_OK; break; case SMM_LOCAL_OK: snprintf(output, ANSWER_BUFSIZE, "<%s>", response_text); result = SMM_OK; break; default: snprintf(output, ANSWER_BUFSIZE, response_text); break; } smtp_destroy(lmtp); syslog(LOG_DEBUG, "cyrus_work: (%04x) result %d, %s", log_id, result, output); return result; }