/** * This function will take the FILE and process it via a * Remote SMTP server... **/ int processRemote(const char *smtp_serv, int smtp_port, dstrbuf *msg) { dsocket *sd; int retval=0, bytes; char *smtp_auth=NULL; char *email_addr=NULL; char *use_tls=NULL; char *user=NULL, *pass=NULL; struct prbar *bar=NULL; char nodename[MAXBUF] = { 0 }; char *ptr = msg->str; struct addr *next=NULL; email_addr = getConfValue("MY_EMAIL"); if (gethostname(nodename, sizeof(nodename) - 1) < 0) { snprintf(nodename, sizeof(nodename) - 1, "geek"); } /* Get other possible configuration values */ smtp_auth = getConfValue("SMTP_AUTH"); if (smtp_auth) { user = getConfValue("SMTP_AUTH_USER"); if (!user) { fatal("You must set SMTP_AUTH_USER in order to user SMTP_AUTH\n"); return ERROR; } pass = getSmtpPass(); if (!pass) { fatal("Failed to get SMTP Password.\n"); return ERROR; } } bar = prbarInit(msg->len); if (Mopts.verbose) { printf("Connecting to server %s on port %d\n", smtp_serv, smtp_port); } sd = dnetConnect(smtp_serv, smtp_port); if (sd == NULL) { fatal("Could not connect to server: %s on port: %d", smtp_serv, smtp_port); return ERROR; } /* Start SMTP Communications */ if (smtpInit(sd, nodename) == ERROR) { printSmtpError(); goto end; } /* Use TLS? */ use_tls = getConfValue("USE_TLS"); #ifndef HAVE_LIBSSL if (use_tls) { warning("No SSL support compiled in. Disabling TLS.\n"); use_tls = NULL; } #endif if (use_tls && strcasecmp(use_tls, "true") == 0) { if (smtpStartTls(sd) != ERROR) { dnetUseTls(sd); dnetVerifyCert(sd); if (smtpInitAfterTLS(sd, nodename) == ERROR) { printSmtpError(); goto end; } } else { printSmtpError(); goto end; } } /* See if we're using SMTP_AUTH. */ if (smtp_auth) { retval = smtpInitAuth(sd, smtp_auth, user, pass); if (retval == ERROR) { printSmtpError(); goto end; } } retval = smtpSetMailFrom(sd, email_addr); if (retval == ERROR) { printSmtpError(); goto end; } while ((next = (struct addr *)dlGetNext(Mopts.to)) != NULL) { retval = smtpSetRcpt(sd, next->email); if (retval == ERROR) { printSmtpError(); goto end; } } while ((next = (struct addr *)dlGetNext(Mopts.cc)) != NULL) { retval = smtpSetRcpt(sd, next->email); if (retval == ERROR) { printSmtpError(); goto end; } } while ((next = (struct addr *)dlGetNext(Mopts.bcc)) != NULL) { retval = smtpSetRcpt(sd, next->email); if (retval == ERROR) { printSmtpError(); goto end; } } retval = smtpStartData(sd); if (retval == ERROR) { printSmtpError(); goto end; } while (*ptr != '\0') { bytes = strlen(ptr); if (bytes > CHUNK_BYTES) { bytes = CHUNK_BYTES; } retval = smtpSendData(sd, ptr, bytes); if (retval == ERROR) { goto end; } if (Mopts.verbose && bar != NULL) { prbarPrint(bytes, bar); } ptr += bytes; } retval = smtpEndData(sd); if (retval != ERROR) { retval = smtpQuit(sd); } end: prbarDestroy(bar); dnetClose(sd); return retval; }
error_t smtpSendMail(const SmtpAuthInfo *authInfo, const SmtpMail *mail) { error_t error; uint_t i; uint_t replyCode; IpAddr serverIpAddr; SmtpClientContext *context; //Check parameters if(!authInfo || !mail) return ERROR_INVALID_PARAMETER; //Make sure the server name is valid if(!authInfo->serverName) return ERROR_INVALID_PARAMETER; //Debug message TRACE_INFO("Sending a mail to %s port %" PRIu16 "...\r\n", authInfo->serverName, authInfo->serverPort); //The specified SMTP server can be either an IP or a host name error = getHostByName(authInfo->interface, authInfo->serverName, &serverIpAddr, 0); //Unable to resolve server name? if(error) return ERROR_NAME_RESOLUTION_FAILED; //Allocate a memory buffer to hold the SMTP client context context = osAllocMem(sizeof(SmtpClientContext)); //Failed to allocate memory? if(!context) return ERROR_OUT_OF_MEMORY; //Open a TCP socket context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Failed to open socket? if(!context->socket) { //Free previously allocated resources osFreeMem(context); //Report an error return ERROR_OPEN_FAILED; } #if (SMTP_TLS_SUPPORT == ENABLED) //Do not use SSL/TLS for the moment context->tlsContext = NULL; #endif //Start of exception handling block do { //Bind the socket to a particular network interface? if(authInfo->interface) { //Associate the socket with the relevant interface error = socketBindToInterface(context->socket, authInfo->interface); //Any error to report? if(error) break; } //Set timeout for blocking operations error = socketSetTimeout(context->socket, SMTP_DEFAULT_TIMEOUT); //Any error to report? if(error) break; //Connect to the SMTP server error = socketConnect(context->socket, &serverIpAddr, authInfo->serverPort); //Connection to server failed? if(error) break; #if (SMTP_TLS_SUPPORT == ENABLED) //Open a secure SSL/TLS session? if(authInfo->useTls) { //Initialize TLS context context->tlsContext = tlsInit(); //Initialization failed? if(!context->tlsContext) { //Unable to allocate memory error = ERROR_OUT_OF_MEMORY; //Stop immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(context->tlsContext, context->socket); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext); //Any error to report? if(error) break; //Perform TLS handshake error = tlsConnect(context->tlsContext); //Failed to established a TLS session? if(error) break; } #endif //Wait for the connection greeting reply error = smtpSendCommand(context, NULL, &replyCode, NULL); //Any communication error to report? if(error) break; //Check whether the greeting message was properly received if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Clear security features context->authLoginSupported = FALSE; context->authPlainSupported = FALSE; context->authCramMd5Supported = FALSE; context->startTlsSupported = FALSE; //Send EHLO command and parse server response error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n", &replyCode, smtpEhloReplyCallback); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } #if (SMTP_TLS_SUPPORT == ENABLED) //Check whether the STARTTLS command is supported if(context->startTlsSupported && !context->tlsContext) { //Send STARTTLS command error = smtpSendCommand(context, "STARTTLS\r\n", &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Initialize TLS context context->tlsContext = tlsInit(); //Initialization failed? if(!context->tlsContext) { //Unable to allocate memory error = ERROR_OUT_OF_MEMORY; //Stop immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(context->tlsContext, context->socket); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext); //Any error to report? if(error) break; //Perform TLS handshake error = tlsConnect(context->tlsContext); //Failed to established a TLS session? if(error) break; //Clear security features context->authLoginSupported = FALSE; context->authPlainSupported = FALSE; context->authCramMd5Supported = FALSE; //Send EHLO command and parse server response error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n", &replyCode, smtpEhloReplyCallback); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } } #endif //Authentication requires a valid user name and password if(authInfo->userName && authInfo->password) { #if (SMTP_LOGIN_AUTH_SUPPORT == ENABLED) //LOGIN authentication mechanism supported? if(context->authLoginSupported) { //Perform LOGIN authentication error = smtpSendAuthLogin(context, authInfo); //Authentication failed? if(error) break; } else #endif #if (SMTP_PLAIN_AUTH_SUPPORT == ENABLED) //PLAIN authentication mechanism supported? if(context->authPlainSupported) { //Perform PLAIN authentication error = smtpSendAuthPlain(context, authInfo); //Authentication failed? if(error) break; } else #endif #if (SMTP_CRAM_MD5_AUTH_SUPPORT == ENABLED) //CRAM-MD5 authentication mechanism supported? if(context->authCramMd5Supported) { //Perform CRAM-MD5 authentication error = smtpSendAuthCramMd5(context, authInfo); //Authentication failed? if(error) break; } else #endif //No authentication mechanism supported? { //Skip authentication step } } //Format the MAIL FROM command (a null return path must be accepted) if(mail->from.addr) sprintf(context->buffer, "MAIL FROM:<%s>\r\n", mail->from.addr); else strcpy(context->buffer, "MAIL FROM:<>\r\n"); //Send the command to the server error = smtpSendCommand(context, context->buffer, &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } //Format the RCPT TO command for(i = 0; i < mail->recipientCount; i++) { //Skip recipient addresses that are not valid if(!mail->recipients[i].addr) continue; //Format the RCPT TO command sprintf(context->buffer, "RCPT TO:<%s>\r\n", mail->recipients[i].addr); //Send the command to the server error = smtpSendCommand(context, context->buffer, &replyCode, NULL); //Any communication error to report? if(error) break; //Check SMTP response code if(!SMTP_REPLY_CODE_2YZ(replyCode)) { //An unexpected response was received... error = ERROR_UNEXPECTED_RESPONSE; //Stop immediately break; } } //Propagate exception if necessary if(error) break; //Send message body error = smtpSendData(context, mail); //Any error to report? if(error) break; //End of exception handling block } while(0); //Check status code if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE || error == ERROR_AUTHENTICATION_FAILED) { //Properly disconnect from the SMTP server smtpSendCommand(context, "QUIT\r\n", &replyCode, NULL); } #if (SMTP_TLS_SUPPORT == ENABLED) //Gracefully close SSL/TLS session if(context->tlsContext != NULL) tlsFree(context->tlsContext); #endif //Close socket socketClose(context->socket); //Clean up previously allocated resources osFreeMem(context); //Return status code return error; }