diff options
Diffstat (limited to 'indra/llmessage/llmail.cpp')
-rw-r--r-- | indra/llmessage/llmail.cpp | 560 |
1 files changed, 280 insertions, 280 deletions
diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index fcda2a85f6..4e5cf8ed48 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmail.cpp * @brief smtp helper functions. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,7 +37,7 @@ #include "apr_network_io.h" #include "llapr.h" -#include "llbase32.h" // IM-to-email address +#include "llbase32.h" // IM-to-email address #include "llblowfishcipher.h" #include "llerror.h" #include "llhost.h" @@ -58,7 +58,7 @@ static apr_socket_t* gMailSocket; bool connect_smtp(); void disconnect_smtp(); - + //#if LL_WINDOWS //SOCKADDR_IN gMailDstAddr, gMailSrcAddr, gMailLclAddr; //#else @@ -70,327 +70,327 @@ void disconnect_smtp(); bool connect_smtp() { - // Prepare an soket to talk smtp - apr_status_t status; - status = apr_socket_create( - &gMailSocket, - gSockAddr->sa.sin.sin_family, - SOCK_STREAM, - APR_PROTO_TCP, - gMailPool); - if(ll_apr_warn_status(status)) return false; - status = apr_socket_connect(gMailSocket, gSockAddr); - if(ll_apr_warn_status(status)) - { - status = apr_socket_close(gMailSocket); - ll_apr_warn_status(status); - return false; - } - return true; + // Prepare an soket to talk smtp + apr_status_t status; + status = apr_socket_create( + &gMailSocket, + gSockAddr->sa.sin.sin_family, + SOCK_STREAM, + APR_PROTO_TCP, + gMailPool); + if(ll_apr_warn_status(status)) return false; + status = apr_socket_connect(gMailSocket, gSockAddr); + if(ll_apr_warn_status(status)) + { + status = apr_socket_close(gMailSocket); + ll_apr_warn_status(status); + return false; + } + return true; } void disconnect_smtp() { - if(gMailSocket) - { - apr_status_t status = apr_socket_close(gMailSocket); - ll_apr_warn_status(status); - gMailSocket = NULL; - } + if(gMailSocket) + { + apr_status_t status = apr_socket_close(gMailSocket); + ll_apr_warn_status(status); + gMailSocket = NULL; + } } // Returns TRUE on success. // message should NOT be SMTP escaped. // static BOOL LLMail::send( - const char* from_name, - const char* from_address, - const char* to_name, - const char* to_address, - const char* subject, - const char* message, - const LLSD& headers) + const char* from_name, + const char* from_address, + const char* to_name, + const char* to_address, + const char* subject, + const char* message, + const LLSD& headers) { - std::string header = buildSMTPTransaction( - from_name, - from_address, - to_name, - to_address, - subject, - headers); - if(header.empty()) - { - return FALSE; - } - - std::string message_str; - if(message) - { - message_str = message; - } - bool rv = send(header, message_str, to_address, from_address); - if(rv) return TRUE; - return FALSE; + std::string header = buildSMTPTransaction( + from_name, + from_address, + to_name, + to_address, + subject, + headers); + if(header.empty()) + { + return FALSE; + } + + std::string message_str; + if(message) + { + message_str = message; + } + bool rv = send(header, message_str, to_address, from_address); + if(rv) return TRUE; + return FALSE; } // static void LLMail::init(const std::string& hostname, apr_pool_t* pool) { - gMailSocket = NULL; - if(hostname.empty() || !pool) - { - gMailPool = NULL; - gSockAddr = NULL; - } - else - { - gMailPool = pool; - - // collect all the information into a socaddr sturcture. the - // documentation is a bit unclear, but I either have to - // specify APR_UNSPEC or not specify any flags. I am not sure - // which option is better. - apr_status_t status = apr_sockaddr_info_get( - &gSockAddr, - hostname.c_str(), - APR_UNSPEC, - 25, - APR_IPV4_ADDR_OK, - gMailPool); - ll_apr_warn_status(status); - } + gMailSocket = NULL; + if(hostname.empty() || !pool) + { + gMailPool = NULL; + gSockAddr = NULL; + } + else + { + gMailPool = pool; + + // collect all the information into a socaddr sturcture. the + // documentation is a bit unclear, but I either have to + // specify APR_UNSPEC or not specify any flags. I am not sure + // which option is better. + apr_status_t status = apr_sockaddr_info_get( + &gSockAddr, + hostname.c_str(), + APR_UNSPEC, + 25, + APR_IPV4_ADDR_OK, + gMailPool); + ll_apr_warn_status(status); + } } // static void LLMail::enable(bool mail_enabled) { - gMailEnabled = mail_enabled; + gMailEnabled = mail_enabled; } // Test a subject line for RFC2822 compliance. static bool valid_subject_chars(const char *subject) { - for (; *subject != '\0'; subject++) - { - unsigned char c = *subject; + for (; *subject != '\0'; subject++) + { + unsigned char c = *subject; - if (c == '\xa' || c == '\xd' || c > '\x7f') - { - return false; - } - } + if (c == '\xa' || c == '\xd' || c > '\x7f') + { + return false; + } + } - return true; + return true; } // static std::string LLMail::buildSMTPTransaction( - const char* from_name, - const char* from_address, - const char* to_name, - const char* to_address, - const char* subject, - const LLSD& headers) + const char* from_name, + const char* from_address, + const char* to_name, + const char* to_address, + const char* subject, + const LLSD& headers) { - if(!from_address || !to_address) - { - LL_INFOS() << "send_mail build_smtp_transaction reject: missing to and/or" - << " from address." << LL_ENDL; - return std::string(); - } - if(!valid_subject_chars(subject)) - { - LL_INFOS() << "send_mail build_smtp_transaction reject: bad subject header: " - << "to=<" << to_address - << ">, from=<" << from_address << ">" - << LL_ENDL; - return std::string(); - } - std::ostringstream from_fmt; - if(from_name && from_name[0]) - { - // "My Name" <myaddress@example.com> - from_fmt << "\"" << from_name << "\" <" << from_address << ">"; - } - else - { - // <myaddress@example.com> - from_fmt << "<" << from_address << ">"; - } - std::ostringstream to_fmt; - if(to_name && to_name[0]) - { - to_fmt << "\"" << to_name << "\" <" << to_address << ">"; - } - else - { - to_fmt << "<" << to_address << ">"; - } - std::ostringstream header; - header - << "HELO lindenlab.com\r\n" - << "MAIL FROM:<" << from_address << ">\r\n" - << "RCPT TO:<" << to_address << ">\r\n" - << "DATA\r\n" - << "From: " << from_fmt.str() << "\r\n" - << "To: " << to_fmt.str() << "\r\n" - << "Subject: " << subject << "\r\n"; - - if(headers.isMap()) - { - LLSD::map_const_iterator iter = headers.beginMap(); - LLSD::map_const_iterator end = headers.endMap(); - for(; iter != end; ++iter) - { - header << (*iter).first << ": " << ((*iter).second).asString() - << "\r\n"; - } - } - - header << "\r\n"; - return header.str(); + if(!from_address || !to_address) + { + LL_INFOS() << "send_mail build_smtp_transaction reject: missing to and/or" + << " from address." << LL_ENDL; + return std::string(); + } + if(!valid_subject_chars(subject)) + { + LL_INFOS() << "send_mail build_smtp_transaction reject: bad subject header: " + << "to=<" << to_address + << ">, from=<" << from_address << ">" + << LL_ENDL; + return std::string(); + } + std::ostringstream from_fmt; + if(from_name && from_name[0]) + { + // "My Name" <myaddress@example.com> + from_fmt << "\"" << from_name << "\" <" << from_address << ">"; + } + else + { + // <myaddress@example.com> + from_fmt << "<" << from_address << ">"; + } + std::ostringstream to_fmt; + if(to_name && to_name[0]) + { + to_fmt << "\"" << to_name << "\" <" << to_address << ">"; + } + else + { + to_fmt << "<" << to_address << ">"; + } + std::ostringstream header; + header + << "HELO lindenlab.com\r\n" + << "MAIL FROM:<" << from_address << ">\r\n" + << "RCPT TO:<" << to_address << ">\r\n" + << "DATA\r\n" + << "From: " << from_fmt.str() << "\r\n" + << "To: " << to_fmt.str() << "\r\n" + << "Subject: " << subject << "\r\n"; + + if(headers.isMap()) + { + LLSD::map_const_iterator iter = headers.beginMap(); + LLSD::map_const_iterator end = headers.endMap(); + for(; iter != end; ++iter) + { + header << (*iter).first << ": " << ((*iter).second).asString() + << "\r\n"; + } + } + + header << "\r\n"; + return header.str(); } // static bool LLMail::send( - const std::string& header, - const std::string& raw_message, - const char* from_address, - const char* to_address) + const std::string& header, + const std::string& raw_message, + const char* from_address, + const char* to_address) { - if(!from_address || !to_address) - { - LL_INFOS() << "send_mail reject: missing to and/or from address." - << LL_ENDL; - return false; - } - - // remove any "." SMTP commands to prevent injection (DEV-35777) - // we don't need to worry about "\r\n.\r\n" because of the - // "\n" --> "\n\n" conversion going into rfc2822_msg below - std::string message = raw_message; - std::string bad_string = "\n.\n"; - std::string good_string = "\n..\n"; - while (1) - { - int index = message.find(bad_string); - if (index == std::string::npos) break; - message.replace(index, bad_string.size(), good_string); - } - - // convert all "\n" into "\r\n" - std::ostringstream rfc2822_msg; - for(U32 i = 0; i < message.size(); ++i) - { - switch(message[i]) - { - case '\0': - break; - case '\n': - // *NOTE: this is kinda busted if we're fed \r\n - rfc2822_msg << "\r\n"; - break; - default: - rfc2822_msg << message[i]; - break; - } - } - - if(!gMailEnabled) - { - LL_INFOS() << "send_mail reject: mail system is disabled: to=<" - << to_address << ">, from=<" << from_address - << ">" << LL_ENDL; - // Any future interface to SMTP should return this as an - // error. --mark - return true; - } - if(!gSockAddr) - { - LL_WARNS() << "send_mail reject: mail system not initialized: to=<" - << to_address << ">, from=<" << from_address - << ">" << LL_ENDL; - return false; - } - - if(!connect_smtp()) - { - LL_WARNS() << "send_mail reject: SMTP connect failure: to=<" - << to_address << ">, from=<" << from_address - << ">" << LL_ENDL; - return false; - } - - std::ostringstream smtp_fmt; - smtp_fmt << header << rfc2822_msg.str() << "\r\n" << ".\r\n" << "QUIT\r\n"; - std::string smtp_transaction = smtp_fmt.str(); - size_t original_size = smtp_transaction.size(); - apr_size_t send_size = original_size; - apr_status_t status = apr_socket_send( - gMailSocket, - smtp_transaction.c_str(), - (apr_size_t*)&send_size); - disconnect_smtp(); - if(ll_apr_warn_status(status)) - { - LL_WARNS() << "send_mail socket failure: unable to write " - << "to=<" << to_address - << ">, from=<" << from_address << ">" - << ", bytes=" << original_size - << ", sent=" << send_size << LL_ENDL; - return false; - } - if(send_size >= LL_MAX_KNOWN_GOOD_MAIL_SIZE) - { - LL_WARNS() << "send_mail message has been shown to fail in testing " - << "when sending messages larger than " << LL_MAX_KNOWN_GOOD_MAIL_SIZE - << " bytes. The next log about success is potentially a lie." << LL_ENDL; - } - LL_DEBUGS() << "send_mail success: " - << "to=<" << to_address - << ">, from=<" << from_address << ">" - << ", bytes=" << original_size - << ", sent=" << send_size << LL_ENDL; + if(!from_address || !to_address) + { + LL_INFOS() << "send_mail reject: missing to and/or from address." + << LL_ENDL; + return false; + } + + // remove any "." SMTP commands to prevent injection (DEV-35777) + // we don't need to worry about "\r\n.\r\n" because of the + // "\n" --> "\n\n" conversion going into rfc2822_msg below + std::string message = raw_message; + std::string bad_string = "\n.\n"; + std::string good_string = "\n..\n"; + while (1) + { + int index = message.find(bad_string); + if (index == std::string::npos) break; + message.replace(index, bad_string.size(), good_string); + } + + // convert all "\n" into "\r\n" + std::ostringstream rfc2822_msg; + for(U32 i = 0; i < message.size(); ++i) + { + switch(message[i]) + { + case '\0': + break; + case '\n': + // *NOTE: this is kinda busted if we're fed \r\n + rfc2822_msg << "\r\n"; + break; + default: + rfc2822_msg << message[i]; + break; + } + } + + if(!gMailEnabled) + { + LL_INFOS() << "send_mail reject: mail system is disabled: to=<" + << to_address << ">, from=<" << from_address + << ">" << LL_ENDL; + // Any future interface to SMTP should return this as an + // error. --mark + return true; + } + if(!gSockAddr) + { + LL_WARNS() << "send_mail reject: mail system not initialized: to=<" + << to_address << ">, from=<" << from_address + << ">" << LL_ENDL; + return false; + } + + if(!connect_smtp()) + { + LL_WARNS() << "send_mail reject: SMTP connect failure: to=<" + << to_address << ">, from=<" << from_address + << ">" << LL_ENDL; + return false; + } + + std::ostringstream smtp_fmt; + smtp_fmt << header << rfc2822_msg.str() << "\r\n" << ".\r\n" << "QUIT\r\n"; + std::string smtp_transaction = smtp_fmt.str(); + size_t original_size = smtp_transaction.size(); + apr_size_t send_size = original_size; + apr_status_t status = apr_socket_send( + gMailSocket, + smtp_transaction.c_str(), + (apr_size_t*)&send_size); + disconnect_smtp(); + if(ll_apr_warn_status(status)) + { + LL_WARNS() << "send_mail socket failure: unable to write " + << "to=<" << to_address + << ">, from=<" << from_address << ">" + << ", bytes=" << original_size + << ", sent=" << send_size << LL_ENDL; + return false; + } + if(send_size >= LL_MAX_KNOWN_GOOD_MAIL_SIZE) + { + LL_WARNS() << "send_mail message has been shown to fail in testing " + << "when sending messages larger than " << LL_MAX_KNOWN_GOOD_MAIL_SIZE + << " bytes. The next log about success is potentially a lie." << LL_ENDL; + } + LL_DEBUGS() << "send_mail success: " + << "to=<" << to_address + << ">, from=<" << from_address << ">" + << ", bytes=" << original_size + << ", sent=" << send_size << LL_ENDL; #if LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND - LL_INFOS() << rfc2822_msg.str() << LL_ENDL; + LL_INFOS() << rfc2822_msg.str() << LL_ENDL; #endif - return true; + return true; } // static std::string LLMail::encryptIMEmailAddress(const LLUUID& from_agent_id, - const LLUUID& to_agent_id, - U32 time, - const U8* secret, - size_t secret_size) + const LLUUID& to_agent_id, + U32 time, + const U8* secret, + size_t secret_size) { #if LL_WINDOWS - return "blowfish-not-supported-on-windows"; + return "blowfish-not-supported-on-windows"; #else - size_t data_size = 4 + UUID_BYTES + UUID_BYTES; - // Convert input data into a binary blob - std::vector<U8> data; - data.resize(data_size); - // *NOTE: This may suffer from endian issues. Could be htolememcpy. - memcpy(&data[0], &time, 4); - memcpy(&data[4], &from_agent_id.mData[0], UUID_BYTES); - memcpy(&data[4 + UUID_BYTES], &to_agent_id.mData[0], UUID_BYTES); - - // Encrypt the blob - LLBlowfishCipher cipher(secret, secret_size); - size_t encrypted_size = cipher.requiredEncryptionSpace(data.size()); - U8* encrypted = new U8[encrypted_size]; - cipher.encrypt(&data[0], data_size, encrypted, encrypted_size); - - std::string address = LLBase32::encode(encrypted, encrypted_size); - - // Make it more pretty for humans. - LLStringUtil::toLower(address); - - delete [] encrypted; - - return address; + size_t data_size = 4 + UUID_BYTES + UUID_BYTES; + // Convert input data into a binary blob + std::vector<U8> data; + data.resize(data_size); + // *NOTE: This may suffer from endian issues. Could be htolememcpy. + memcpy(&data[0], &time, 4); + memcpy(&data[4], &from_agent_id.mData[0], UUID_BYTES); + memcpy(&data[4 + UUID_BYTES], &to_agent_id.mData[0], UUID_BYTES); + + // Encrypt the blob + LLBlowfishCipher cipher(secret, secret_size); + size_t encrypted_size = cipher.requiredEncryptionSpace(data.size()); + U8* encrypted = new U8[encrypted_size]; + cipher.encrypt(&data[0], data_size, encrypted, encrypted_size); + + std::string address = LLBase32::encode(encrypted, encrypted_size); + + // Make it more pretty for humans. + LLStringUtil::toLower(address); + + delete [] encrypted; + + return address; #endif } |