summaryrefslogtreecommitdiff
path: root/indra/llmessage/llmail.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage/llmail.cpp')
-rw-r--r--indra/llmessage/llmail.cpp792
1 files changed, 396 insertions, 396 deletions
diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp
index 6414c2c016..fe01f2d4a4 100644
--- a/indra/llmessage/llmail.cpp
+++ b/indra/llmessage/llmail.cpp
@@ -1,396 +1,396 @@
-/**
- * @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$
- */
-
-#include "linden_common.h"
-
-#include "llmail.h"
-
-// APR on Windows needs full windows headers
-#include "llwin32headers.h"
-#include <string>
-#include <sstream>
-
-#include "apr_pools.h"
-#include "apr_network_io.h"
-
-#include "llapr.h"
-#include "llbase32.h" // IM-to-email address
-#include "llblowfishcipher.h"
-#include "llerror.h"
-#include "llhost.h"
-#include "llsd.h"
-#include "llstring.h"
-#include "lluuid.h"
-#include "net.h"
-
-//
-// constants
-//
-const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
-
-static bool gMailEnabled = true;
-static apr_pool_t* gMailPool;
-static apr_sockaddr_t* gSockAddr;
-static apr_socket_t* gMailSocket;
-
-bool connect_smtp();
-void disconnect_smtp();
-
-//#if LL_WINDOWS
-//SOCKADDR_IN gMailDstAddr, gMailSrcAddr, gMailLclAddr;
-//#else
-//struct sockaddr_in gMailDstAddr, gMailSrcAddr, gMailLclAddr;
-//#endif
-
-// Define this for a super-spammy mail mode.
-//#define LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND 1
-
-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;
-}
-
-void disconnect_smtp()
-{
- 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)
-{
- 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);
- }
-}
-
-// static
-void LLMail::enable(bool 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;
-
- if (c == '\xa' || c == '\xd' || c > '\x7f')
- {
- return false;
- }
- }
-
- 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)
-{
- 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)
-{
- 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;
-#endif
- 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)
-{
-#if LL_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;
-#endif
-}
+/**
+ * @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$
+ */
+
+#include "linden_common.h"
+
+#include "llmail.h"
+
+// APR on Windows needs full windows headers
+#include "llwin32headers.h"
+#include <string>
+#include <sstream>
+
+#include "apr_pools.h"
+#include "apr_network_io.h"
+
+#include "llapr.h"
+#include "llbase32.h" // IM-to-email address
+#include "llblowfishcipher.h"
+#include "llerror.h"
+#include "llhost.h"
+#include "llsd.h"
+#include "llstring.h"
+#include "lluuid.h"
+#include "net.h"
+
+//
+// constants
+//
+const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
+
+static bool gMailEnabled = true;
+static apr_pool_t* gMailPool;
+static apr_sockaddr_t* gSockAddr;
+static apr_socket_t* gMailSocket;
+
+bool connect_smtp();
+void disconnect_smtp();
+
+//#if LL_WINDOWS
+//SOCKADDR_IN gMailDstAddr, gMailSrcAddr, gMailLclAddr;
+//#else
+//struct sockaddr_in gMailDstAddr, gMailSrcAddr, gMailLclAddr;
+//#endif
+
+// Define this for a super-spammy mail mode.
+//#define LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND 1
+
+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;
+}
+
+void disconnect_smtp()
+{
+ 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)
+{
+ 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);
+ }
+}
+
+// static
+void LLMail::enable(bool 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;
+
+ if (c == '\xa' || c == '\xd' || c > '\x7f')
+ {
+ return false;
+ }
+ }
+
+ 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)
+{
+ 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)
+{
+ 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;
+#endif
+ 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)
+{
+#if LL_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;
+#endif
+}