int tryLogin(int hSocket, _MODULE_DATA* _psSessionData, sLogin** psLogin, char* szLogin, char* szPassword) { int nRet; unsigned char* bufReceive = NULL; int nReceiveBufferSize = 0; switch(_psSessionData->nAuthType) { case AUTH_LOGIN: writeError(ERR_DEBUG_MODULE, "[%s] Sending LOGIN Authentication.", MODULE_NAME); nRet = sendAuthLogin(hSocket, _psSessionData, szLogin, szPassword); break; case AUTH_PLAIN: writeError(ERR_DEBUG_MODULE, "[%s] Sending PLAIN Authentication.", MODULE_NAME); nRet = sendAuthPlain(hSocket, _psSessionData, szLogin, szPassword); break; case AUTH_NTLM: writeError(ERR_DEBUG_MODULE, "[%s] Sending NTLM Authentication.", MODULE_NAME); nRet = sendAuthNTLM(hSocket, _psSessionData, szLogin, szPassword); break; default: break; } if (nRet == FAILURE) { writeError(ERR_ERROR, "[%s] Failed during sending of authentication data.", MODULE_NAME); (*psLogin)->iResult = LOGIN_RESULT_UNKNOWN; setPassResult(*psLogin, szPassword); return MSTATE_EXITING; } /* Exchange 2003 Server Response Messages NO Logon failure: unknown user name or bad password. NO The specified authentication package is not supported. NO Clear text passwords have been disabled for this protocol. NO Cleartext login on this server requires the use of transport level security (SSL/TLS) */ writeError(ERR_DEBUG_MODULE, "[%s] Retrieving server response.", MODULE_NAME); nReceiveBufferSize = 0; if ((medusaReceiveRegex(hSocket, &bufReceive, &nReceiveBufferSize, ".*\r\n") == FAILURE) || (bufReceive == NULL)) { writeError(ERR_ERROR, "[%s] Failed: Unexpected or no data received.", MODULE_NAME); (*psLogin)->iResult = LOGIN_RESULT_ERROR; nRet = MSTATE_EXITING; } else if (strstr(bufReceive,"OK") != NULL) { writeError(ERR_DEBUG_MODULE, "[%s] Login attempt successful.", MODULE_NAME); (*psLogin)->iResult = LOGIN_RESULT_SUCCESS; nRet = MSTATE_EXITING; } else if (strstr(bufReceive,"NO Clear text passwords have been disabled for this protocol.") != NULL) { writeError(ERR_ERROR, "[%s] Server reports that clear-text passwords have been disabled.", MODULE_NAME); (*psLogin)->iResult = LOGIN_RESULT_ERROR; nRet = MSTATE_EXITING; } else if (strstr(bufReceive,"NO Cleartext login on this server requires the use of transport level security (SSL/TLS)") != NULL) { writeError(ERR_ERROR, "[%s] Server reports that clear-text passwords are only allowed over SSL/TLS.", MODULE_NAME); (*psLogin)->iResult = LOGIN_RESULT_ERROR; nRet = MSTATE_EXITING; } else if (strstr(bufReceive,"NO The specified authentication package is not supported.") != NULL) { writeError(ERR_ERROR, "[%s] Server reports that the specified authentication package is not supported.", MODULE_NAME); (*psLogin)->iResult = LOGIN_RESULT_ERROR; nRet = MSTATE_EXITING; } else if (strstr(bufReceive,"NO") != NULL) { writeError(ERR_DEBUG_MODULE, "[%s] Login attempt failed.", MODULE_NAME); (*psLogin)->iResult = LOGIN_RESULT_FAIL; nRet = MSTATE_RUNNING; } else if (strstr(bufReceive,"BAD") != NULL) { writeError(ERR_ERROR, "[%s] IMAP server responded that the command was unknown or the arguments were invalid.", MODULE_NAME); (*psLogin)->iResult = LOGIN_RESULT_ERROR; nRet = MSTATE_EXITING; } else { writeError(ERR_ERROR, "[%s] Unknown IMAP server response: %s", MODULE_NAME, bufReceive); (*psLogin)->iResult = LOGIN_RESULT_ERROR; nRet = MSTATE_EXITING; } FREE(bufReceive); setPassResult((*psLogin), szPassword); return(nRet); }
// main logic of the component - a slot triggered upon data entering the socket // comments inline... void QwwSmtpClientPrivate::_q_readFromSocket() { while (socket->canReadLine()) { QString line = socket->readLine(); qDebug() << "SMTP <<<" << line.toUtf8().constData(); QRegExp rx("(\\d+)-(.*)\n"); // multiline response (aka 250-XYZ) QRegExp rxlast("(\\d+) (.*)\n"); // single or last line response (aka 250 XYZ) bool mid = rx.exactMatch(line); bool last = rxlast.exactMatch(line); // multiline if (mid){ int status = rx.cap(1).toInt(); SMTPCommand &cmd = commandqueue.head(); switch (cmd.type) { // trying to connect case SMTPCommand::Connect: { int stage = cmd.extra.toInt(); // stage 0 completed with success - socket is connected and EHLO was sent if(stage==1 && status==250){ QString arg = rx.cap(2).trimmed(); parseOption(arg); // we're probably receiving options } } break; // trying to establish deferred SSL handshake case SMTPCommand::StartTLS: { int stage = cmd.extra.toInt(); // stage 0 (negotiation) completed ok if(stage==1 && status==250){ QString arg = rx.cap(2).trimmed(); parseOption(arg); // we're probably receiving options } } default: break; } } else // single line if (last) { int status = rxlast.cap(1).toInt(); SMTPCommand &cmd = commandqueue.head(); switch (cmd.type) { // trying to connect case SMTPCommand::Connect: { int stage = cmd.extra.toInt(); // connection established, server sent its banner if (stage==0 && status==220) { sendEhlo(); // connect ok, send ehlo } // server responded to EHLO if (stage==1 && status==250){ // success (EHLO) parseOption(rxlast.cap(2).trimmed()); // we're probably receiving the last option errorString.clear(); setState(QwwSmtpClient::Connected); processNextCommand(); } // server responded to HELO (EHLO failed) if (state==2 && status==250) { // success (HELO) errorString.clear(); setState(QwwSmtpClient::Connected); processNextCommand(); } // EHLO failed, reason given in errorString if (stage==1 && (status==554 || status==501 || status==502 || status==421)) { errorString = rxlast.cap(2).trimmed(); sendHelo(); // ehlo failed, send helo cmd.extra = 2; } //abortDialog(); } break; // trying to establish a delayed SSL handshake case SMTPCommand::StartTLS: { int stage = cmd.extra.toInt(); // received an invitation from the server to enter TLS mode if (stage==0 && status==220) { qDebug() << "SMTP ** startClientEncruption"; socket->startClientEncryption(); } // TLS established, connection is encrypted, EHLO was sent else if (stage==1 && status==250) { setState(QwwSmtpClient::Connected); parseOption(rxlast.cap(2).trimmed()); // we're probably receiving options errorString.clear(); emit q->tlsStarted(); processNextCommand(); } // starttls failed else { qDebug() << "TLS failed at stage " << stage << ": " << line; errorString = "TLS failed"; emit q->done(false); } } break; // trying to authenticate the client to the server case SMTPCommand::Authenticate: { int stage = cmd.extra.toInt(); if (stage==0 && status==334) { // AUTH mode was accepted by the server, 1st challenge sent QwwSmtpClient::AuthMode authmode = (QwwSmtpClient::AuthMode)cmd.data.toList().at(0).toInt(); errorString.clear(); switch (authmode) { case QwwSmtpClient::AuthPlain: sendAuthPlain(cmd.data.toList().at(1).toString(), cmd.data.toList().at(2).toString()); break; case QwwSmtpClient::AuthLogin: sendAuthLogin(cmd.data.toList().at(1).toString(), cmd.data.toList().at(2).toString(), 1); break; default: qWarning("I shouldn't be here"); setState(QwwSmtpClient::Connected); processNextCommand(); break; } cmd.extra = stage+1; } else if (stage==1 && status==334) { // AUTH mode and user names were acccepted by the server, 2nd challenge sent QwwSmtpClient::AuthMode authmode = (QwwSmtpClient::AuthMode)cmd.data.toList().at(0).toInt(); errorString.clear(); switch (authmode) { case QwwSmtpClient::AuthPlain: // auth failed setState(QwwSmtpClient::Connected); processNextCommand(); break; case QwwSmtpClient::AuthLogin: sendAuthLogin(cmd.data.toList().at(1).toString(), cmd.data.toList().at(2).toString(), 2); break; default: qWarning("I shouldn't be here"); setState(QwwSmtpClient::Connected); processNextCommand(); break; } } else if (stage==2 && status==334) { // auth failed errorString = rxlast.cap(2).trimmed(); setState(QwwSmtpClient::Connected); processNextCommand(); } else if (status==235) { // auth ok errorString.clear(); emit q->authenticated(); setState(QwwSmtpClient::Connected); processNextCommand(); } else { errorString = rxlast.cap(2).trimmed(); setState(QwwSmtpClient::Connected); emit q->done(false); } } break; // trying to send mail case SMTPCommand::Mail: case SMTPCommand::MailBurl: { int stage = cmd.extra.toInt(); // temporary failure upon receiving the sender address (greylisting probably) if (status==421 && stage==0) { errorString = rxlast.cap(2).trimmed(); // temporary envelope failure (greylisting) setState(QwwSmtpClient::Connected); processNextCommand(false); } if (status==250 && stage==0) { // sender accepted errorString.clear(); sendRcpt(); } else if (status==250 && stage==1) { // all receivers accepted if (cmd.type == SMTPCommand::MailBurl) { errorString.clear(); QByteArray url = cmd.data.toList().at(2).toByteArray(); qDebug() << "SMTP >>> BURL" << url << "LAST"; socket->write("BURL " + url + " LAST\r\n"); cmd.extra=2; } else { errorString.clear(); qDebug() << "SMTP >>> DATA"; socket->write("DATA\r\n"); cmd.extra=2; } } else if ((cmd.type == SMTPCommand::Mail && status==354 && stage==2)) { // DATA command accepted errorString.clear(); QByteArray toBeWritten = cmd.data.toList().at(2).toString().toUtf8(); qDebug() << "SMTP >>>" << toBeWritten << "\r\n.\r\n"; socket->write(toBeWritten); // expecting data to be already escaped (CRLF.CRLF) socket->write("\r\n.\r\n"); // termination token - CRLF.CRLF cmd.extra=3; } else if ((cmd.type == SMTPCommand::MailBurl && status==354 && stage==2)) { // BURL succeeded setState(QwwSmtpClient::Connected); errorString.clear(); processNextCommand(); } else if ((cmd.type == SMTPCommand::Mail && status==250 && stage==3)) { // mail queued setState(QwwSmtpClient::Connected); errorString.clear(); processNextCommand(); } else { // something went wrong errorString = rxlast.cap(2).trimmed(); setState(QwwSmtpClient::Connected); emit q->done(false); processNextCommand(); } } default: break; } } else { qDebug() << "None of two regular expressions matched the input" << line; } } }