X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fsmtp%2Fsmtp_clienthandlers.c;h=198649e1f2c00522b2f738b7ee04cbf15e1840ef;hb=b26e3e79fcb15dc1b46f4c7710a6bafdc6472950;hp=ebc6a7cb0d8a2262dafadc155d6630c8e66276e6;hpb=73422328a6781e5073a485cf85d54b43974153d9;p=citadel.git diff --git a/citadel/modules/smtp/smtp_clienthandlers.c b/citadel/modules/smtp/smtp_clienthandlers.c index ebc6a7cb0..198649e1f 100644 --- a/citadel/modules/smtp/smtp_clienthandlers.c +++ b/citadel/modules/smtp/smtp_clienthandlers.c @@ -19,19 +19,19 @@ * * Copyright (c) 1998-2012 by the citadel.org team * - * 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 3 of the License, or - * (at your option) any later version. + * This program is open source software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * + * * * 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 + * + * + * */ #include "sysdep.h" @@ -90,27 +90,34 @@ #define SMTP_ERROR(WHICH_ERR, ERRSTR) do { \ Msg->MyQEntry->Status = WHICH_ERR; \ - StrBufAppendBufPlain(Msg->MyQEntry->StatusMessage, \ + StrBufAppendBufPlain(Msg->MyQEntry->StatusMessage, \ HKEY(ERRSTR), 0); \ + StrBufTrim(Msg->MyQEntry->StatusMessage); \ return eAbort; } \ while (0) #define SMTP_VERROR(WHICH_ERR) do { \ Msg->MyQEntry->Status = WHICH_ERR; \ - StrBufPlain(Msg->MyQEntry->StatusMessage, \ - ChrPtr(Msg->IO.IOBuf) + 4, \ - StrLength(Msg->IO.IOBuf) - 4); \ + StrBufPlain(Msg->MyQEntry->StatusMessage, \ + ChrPtr(Msg->IO.IOBuf) + 4, \ + StrLength(Msg->IO.IOBuf) - 4); \ + StrBufTrim(Msg->MyQEntry->StatusMessage); \ return eAbort; } \ while (0) #define SMTP_IS_STATE(WHICH_STATE) (ChrPtr(Msg->IO.IOBuf)[0] == WHICH_STATE) #define SMTP_DBG_SEND() \ - EVS_syslog(LOG_DEBUG, "SMTP: > %s\n", ChrPtr(Msg->IO.SendBuf.Buf)) + EVS_syslog(LOG_DEBUG, "> %s\n", ChrPtr(Msg->IO.SendBuf.Buf)) #define SMTP_DBG_READ() \ - EVS_syslog(LOG_DEBUG, "SMTP: < %s\n", ChrPtr(Msg->IO.IOBuf)) + EVS_syslog(LOG_DEBUG, "< %s\n", ChrPtr(Msg->IO.IOBuf)) +/* + * if a Read handler wants to skip to a specific part use this macro. + * the -1 is here since the auto-forward following has to be taken into account. + */ +#define READ_NEXT_STATE(state) Msg->State = state - 1 /*****************************************************************************/ /* SMTP CLIENT STATE CALLBACKS */ @@ -120,6 +127,7 @@ eNextState SMTPC_read_greeting(SmtpOutMsg *Msg) /* Process the SMTP greeting from the server */ AsyncIO *IO = &Msg->IO; SMTP_DBG_READ(); + SetSMTPState(IO, eSTMPsmtp); if (!SMTP_IS_STATE('2')) { if (SMTP_IS_STATE('4')) @@ -149,11 +157,21 @@ eNextState SMTPC_read_EHLO_reply(SmtpOutMsg *Msg) SMTP_DBG_READ(); if (SMTP_IS_STATE('2')) { - Msg->State ++; + READ_NEXT_STATE(eSMTPAuth); if ((Msg->pCurrRelay == NULL) || (Msg->pCurrRelay->User == NULL)) - Msg->State ++; /* Skip auth... */ + READ_NEXT_STATE(eFROM); /* Skip auth... */ + if (Msg->pCurrRelay != NULL) + { + if (strstr(ChrPtr(Msg->IO.IOBuf), "LOGIN") != NULL) + Msg->SendLogin = 1; + else if ((Msg->MultiLineBuf != NULL) && + strstr(ChrPtr(Msg->MultiLineBuf), "LOGIN") != NULL) + { + Msg->SendLogin = 1; + } + } } /* else we fall back to 'helo' */ return eSendReply; @@ -181,9 +199,14 @@ eNextState SMTPC_read_HELO_reply(SmtpOutMsg *Msg) else SMTP_VERROR(5); } + if (Msg->pCurrRelay != NULL) + { + if (strstr(ChrPtr(Msg->IO.IOBuf), "LOGIN") != NULL) + Msg->SendLogin = 1; + } if ((Msg->pCurrRelay == NULL) || (Msg->pCurrRelay->User == NULL)) - Msg->State ++; /* Skip auth... */ + READ_NEXT_STATE(eFROM); /* Skip auth... */ return eSendReply; } @@ -196,25 +219,39 @@ eNextState SMTPC_send_auth(SmtpOutMsg *Msg) if ((Msg->pCurrRelay == NULL) || (Msg->pCurrRelay->User == NULL)) - Msg->State ++; /* Skip auth, shouldn't even come here!... */ + READ_NEXT_STATE(eFROM); /* Skip auth, shouldn't even come here!... */ else { /* Do an AUTH command if necessary */ - sprintf(buf, "%s%c%s%c%s", - Msg->pCurrRelay->User, '\0', - Msg->pCurrRelay->User, '\0', - Msg->pCurrRelay->Pass); - - CtdlEncodeBase64(encoded, buf, - strlen(Msg->pCurrRelay->User) * 2 + - strlen(Msg->pCurrRelay->Pass) + 2, 0); + if (Msg->SendLogin) + { + StrBufPlain(Msg->IO.SendBuf.Buf, + HKEY("AUTH LOGIN\r\n")); + } + else + { + sprintf(buf, "%s%c%s%c%s", + Msg->pCurrRelay->User, '\0', + Msg->pCurrRelay->User, '\0', + Msg->pCurrRelay->Pass); + + size_t len = CtdlEncodeBase64(encoded, buf, + strlen(Msg->pCurrRelay->User) * 2 + + strlen(Msg->pCurrRelay->Pass) + 2, 0); + + if (buf[len - 1] == '\n') { + buf[len - 1] = '\0'; + } - StrBufPrintf(Msg->IO.SendBuf.Buf, - "AUTH PLAIN %s\r\n", encoded); + StrBufPrintf(Msg->IO.SendBuf.Buf, + "AUTH PLAIN %s\r\n", + encoded); + } } SMTP_DBG_SEND(); return eReadMessage; } + eNextState SMTPC_read_auth_reply(SmtpOutMsg *Msg) { AsyncIO *IO = &Msg->IO; @@ -222,6 +259,108 @@ eNextState SMTPC_read_auth_reply(SmtpOutMsg *Msg) SMTP_DBG_READ(); + if (Msg->SendLogin) + { + if (!SMTP_IS_STATE('3')) + SMTP_VERROR(5); + } + else + { + if (!SMTP_IS_STATE('2')) { + if (SMTP_IS_STATE('4')) + SMTP_VERROR(4); + else + SMTP_VERROR(5); + } + READ_NEXT_STATE(eFROM); + } + return eSendReply; +} + + +eNextState SMTPC_send_authplain_1(SmtpOutMsg *Msg) +{ + AsyncIO *IO = &Msg->IO; + char buf[SIZ]; + char encoded[1024]; + long encodedlen; + + sprintf(buf, "%s", + Msg->pCurrRelay->User); + + encodedlen = CtdlEncodeBase64( + encoded, + Msg->pCurrRelay->User, + strlen(Msg->pCurrRelay->User), + 0); + if (encoded[encodedlen - 1] == '\n') { + encodedlen --; + encoded[encodedlen] = '\0'; + } + + StrBufPlain(Msg->IO.SendBuf.Buf, + encoded, + encodedlen); + + StrBufAppendBufPlain(Msg->IO.SendBuf.Buf, + HKEY("\r\n"), 0); + + SMTP_DBG_SEND(); + + return eReadMessage; +} +eNextState SMTPC_read_auth_plain_reply_1(SmtpOutMsg *Msg) +{ + AsyncIO *IO = &Msg->IO; + /* Do an AUTH command if necessary */ + + SMTP_DBG_READ(); + + if (!SMTP_IS_STATE('3')) + SMTP_VERROR(5); + return eSendReply; +} + + +eNextState SMTPC_send_authplain_2(SmtpOutMsg *Msg) +{ + AsyncIO *IO = &Msg->IO; + char buf[SIZ]; + char encoded[1024]; + long encodedlen; + + sprintf(buf, "%s", + Msg->pCurrRelay->Pass); + + encodedlen = CtdlEncodeBase64( + encoded, + Msg->pCurrRelay->Pass, + strlen(Msg->pCurrRelay->Pass), + 0); + + if (encoded[encodedlen - 1] == '\n') { + encodedlen --; + encoded[encodedlen] = '\0'; + } + + StrBufPlain(Msg->IO.SendBuf.Buf, + encoded, + encodedlen); + + StrBufAppendBufPlain(Msg->IO.SendBuf.Buf, + HKEY("\r\n"), 0); + + SMTP_DBG_SEND(); + + return eReadMessage; +} +eNextState SMTPC_read_auth_plain_reply_2(SmtpOutMsg *Msg) +{ + AsyncIO *IO = &Msg->IO; + /* Do an AUTH command if necessary */ + + SMTP_DBG_READ(); + if (!SMTP_IS_STATE('2')) { if (SMTP_IS_STATE('4')) SMTP_VERROR(4); @@ -302,11 +441,13 @@ eNextState SMTPC_read_DATAcmd_reply(SmtpOutMsg *Msg) SMTP_DBG_READ(); if (!SMTP_IS_STATE('3')) { + SetSMTPState(IO, eSTMPfailOne); if (SMTP_IS_STATE('4')) SMTP_VERROR(3); else SMTP_VERROR(5); } + SetSMTPState(IO, eSTMPsmtpdata); return eSendReply; } @@ -318,6 +459,10 @@ eNextState SMTPC_send_data_body(SmtpOutMsg *Msg) Buf = Msg->IO.SendBuf.Buf; Msg->IO.SendBuf.Buf = Msg->msgtext; Msg->msgtext = Buf; + /* + * sending the message itself doesn't use this state machine. + * so we have to operate it here by ourselves. + */ Msg->State ++; return eSendMore; @@ -350,10 +495,12 @@ eNextState SMTPC_read_data_body_reply(SmtpOutMsg *Msg) SMTP_VERROR(5); } + SetSMTPState(IO, eSTMPsmtpdone); /* We did it! */ StrBufPlain(Msg->MyQEntry->StatusMessage, &ChrPtr(Msg->IO.RecvBuf.Buf)[4], StrLength(Msg->IO.RecvBuf.Buf) - 4); + StrBufTrim(Msg->MyQEntry->StatusMessage); Msg->MyQEntry->Status = 2; return eSendReply; } @@ -373,9 +520,8 @@ eNextState SMTPC_read_QUIT_reply(SmtpOutMsg *Msg) AsyncIO *IO = &Msg->IO; SMTP_DBG_READ(); - EVS_syslog(LOG_INFO, - "SMTP client[%ld]: delivery to <%s> @ <%s> (%s) succeeded\n", - Msg->n, + EVS_syslog(LOG_DEBUG, + "delivery to <%s> @ <%s> (%s) succeeded\n", Msg->user, Msg->node, Msg->name); @@ -401,6 +547,8 @@ SMTPReadHandler ReadHandlers[eMaxSMTPC] = { SMTPC_read_EHLO_reply, SMTPC_read_HELO_reply, SMTPC_read_auth_reply, + SMTPC_read_auth_plain_reply_1, + SMTPC_read_auth_plain_reply_2, SMTPC_read_FROM_reply, SMTPC_read_RCPT_reply, SMTPC_read_DATAcmd_reply, @@ -413,6 +561,8 @@ SMTPSendHandler SendHandlers[eMaxSMTPC] = { SMTPC_send_EHLO, STMPC_send_HELO, SMTPC_send_auth, + SMTPC_send_authplain_1, + SMTPC_send_authplain_2, SMTPC_send_FROM, SMTPC_send_RCPT, SMTPC_send_DATAcmd, @@ -428,6 +578,8 @@ const double SMTP_C_ReadTimeouts[eMaxSMTPC] = { 30., /* EHLO */ 30., /* HELO */ 30., /* Auth */ + 30., /* Auth */ + 30., /* Auth */ 30., /* From */ 90., /* RCPT */ 30., /* DATA */ @@ -440,6 +592,8 @@ const double SMTP_C_SendTimeouts[eMaxSMTPC] = { 30., /* EHLO */ 30., /* HELO */ 30., /* Auth */ + 30., /* Auth */ + 30., /* Auth */ 30., /* From */ 30., /* RCPT */ 30., /* DATA */ @@ -453,12 +607,14 @@ const ConstStr ReadErrors[eMaxSMTPC + 1] = { {HKEY("Connection broken during SMTP EHLO")}, {HKEY("Connection broken during SMTP HELO")}, {HKEY("Connection broken during SMTP AUTH")}, + {HKEY("Connection broken during SMTP AUTH PLAIN I")}, + {HKEY("Connection broken during SMTP AUTH PLAIN II")}, {HKEY("Connection broken during SMTP MAIL FROM")}, {HKEY("Connection broken during SMTP RCPT")}, {HKEY("Connection broken during SMTP DATA")}, {HKEY("Connection broken during SMTP message transmit")}, - {HKEY("")},/* quit reply, don't care. */ - {HKEY("")},/* quit reply, don't care. */ + {HKEY("Connection broken during SMTP message transmit")},/* quit reply, don't care. */ + {HKEY("Connection broken during SMTP message transmit")},/* quit reply, don't care. */ {HKEY("")}/* quit reply, don't care. */ }; @@ -475,7 +631,7 @@ int smtp_resolve_recipients(SmtpOutMsg *Msg) int lp, rp; int i; - EVNCS_syslog(LOG_DEBUG, "SMTP: %s\n", __FUNCTION__); + EVNCS_syslog(LOG_DEBUG, "%s\n", __FUNCTION__); if ((Msg==NULL) || (Msg->MyQEntry == NULL) || @@ -490,9 +646,7 @@ int smtp_resolve_recipients(SmtpOutMsg *Msg) Msg->name); EVNCS_syslog(LOG_DEBUG, - "SMTP client[%ld]: Attempting delivery to " - "<%s> @ <%s> (%s)\n", - Msg->n, + "Attempting delivery to <%s> @ <%s> (%s)\n", Msg->user, Msg->node, Msg->name);