summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer Jackson <spencer.jackson@mongodb.com>2017-08-24 18:03:27 -0400
committerSpencer Jackson <spencer.jackson@mongodb.com>2017-08-31 10:24:52 -0400
commitebd0ec786e6986ecd407c48928e6866736675021 (patch)
treef5cc2e38086bab8ea445ec93acae7d0e8c7e6a08
parent2730bd049022954bc7cd43392be20e6d54cf330d (diff)
downloadmongo-ebd0ec786e6986ecd407c48928e6866736675021.tar.gz
SERVER-30821: Allow configurable use of secure memory
-rw-r--r--src/mongo/base/SConscript1
-rw-r--r--src/mongo/base/secure_allocator.cpp3
-rw-r--r--src/mongo/base/secure_allocator.h405
-rw-r--r--src/mongo/base/secure_allocator_test.cpp51
-rw-r--r--src/mongo/crypto/mechanism_scram.h9
-rw-r--r--src/mongo/db/auth/authorization_manager.h2
-rw-r--r--src/mongo/db/auth/sasl_plain_server_conversation.cpp4
-rw-r--r--src/mongo/db/server_options.h14
-rw-r--r--src/mongo/db/server_options_helpers.cpp5
9 files changed, 299 insertions, 195 deletions
diff --git a/src/mongo/base/SConscript b/src/mongo/base/SConscript
index af40fdab72a..db569f842a5 100644
--- a/src/mongo/base/SConscript
+++ b/src/mongo/base/SConscript
@@ -73,6 +73,7 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/server_options_core',
'$BUILD_DIR/mongo/util/processinfo',
'$BUILD_DIR/mongo/util/secure_zero_memory',
],
diff --git a/src/mongo/base/secure_allocator.cpp b/src/mongo/base/secure_allocator.cpp
index 982b24a12ef..68f8c190238 100644
--- a/src/mongo/base/secure_allocator.cpp
+++ b/src/mongo/base/secure_allocator.cpp
@@ -379,4 +379,7 @@ void deallocate(void* ptr, std::size_t bytes) {
}
} // namespace secure_allocator_details
+
+constexpr StringData SecureAllocatorAuthDomainTrait::DomainType;
+
} // namespace mongo
diff --git a/src/mongo/base/secure_allocator.h b/src/mongo/base/secure_allocator.h
index a642b47abb8..97b386c6168 100644
--- a/src/mongo/base/secure_allocator.h
+++ b/src/mongo/base/secure_allocator.h
@@ -37,6 +37,7 @@
#include <vector>
#include "mongo/base/static_assert.h"
+#include "mongo/db/server_options.h"
#include "mongo/stdx/type_traits.h"
#include "mongo/util/assert_util.h"
@@ -47,6 +48,21 @@ namespace secure_allocator_details {
void* allocate(std::size_t bytes, std::size_t alignOf);
void deallocate(void* ptr, std::size_t bytes);
+inline void* allocateWrapper(std::size_t bytes, std::size_t alignOf, bool secure) {
+ if (secure) {
+ return allocate(bytes, alignOf);
+ } else {
+ return mongoMalloc(bytes);
+ }
+}
+inline void deallocateWrapper(void* ptr, std::size_t bytes, bool secure) {
+ if (secure) {
+ return deallocate(ptr, bytes);
+ } else {
+ return free(ptr);
+ }
+}
+
} // namespace secure_allocator_details
/**
@@ -70,221 +86,248 @@ void deallocate(void* ptr, std::size_t bytes);
*
* See also: http://howardhinnant.github.io/allocator_boilerplate.html
*/
-template <typename T>
-struct SecureAllocator {
- /**
- * We only support trivially copyable types to avoid situations where the
- * SecureAllocator is used in containers with complex types that do their
- * own allocation. I.e. one could otherwise have a:
- *
- * std::vector<std::string, SecureAllocator<std::string>>
- *
- * where the vectors were stored securely, but the strings spilled to the
- * heap
- *
- */
- MONGO_STATIC_ASSERT_MSG(std::is_trivially_copyable<T>::value,
- "SecureAllocator can only be used with trivially copyable types");
-
- // NOTE: The standard doesn't seem to require these, but libstdc++
- // definitly wants them.
- using reference = T&;
- using const_reference = const T&;
-
-
- // NOTE: These members are defined in the same order as specified
- // in the "Allocator Requirements" section of the standard. Please
- // retain this ordering.
-
- using pointer = T*;
- using const_pointer = const T*;
- using void_pointer = void*;
- using const_void_pointer = const void*;
- using value_type = T;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
-
- template <typename U>
- struct rebind {
- using other = SecureAllocator<U>;
- };
+template <typename DomainTraits>
+struct SecureAllocatorDomain {
+ template <typename T>
+ struct SecureAllocator {
+ /**
+ * We only support trivially copyable types to avoid situations where the
+ * SecureAllocator is used in containers with complex types that do their
+ * own allocation. I.e. one could otherwise have a:
+ *
+ * std::vector<std::string, SecureAllocator<std::string>>
+ *
+ * where the vectors were stored securely, but the strings spilled to the
+ * heap
+ *
+ */
+ MONGO_STATIC_ASSERT_MSG(std::is_trivially_copyable<T>::value,
+ "SecureAllocator can only be used with trivially copyable types");
+
+ // NOTE: The standard doesn't seem to require these, but libstdc++
+ // definitly wants them.
+ using reference = T&;
+ using const_reference = const T&;
+
+
+ // NOTE: These members are defined in the same order as specified
+ // in the "Allocator Requirements" section of the standard. Please
+ // retain this ordering.
+
+ using pointer = T*;
+ using const_pointer = const T*;
+ using void_pointer = void*;
+ using const_void_pointer = const void*;
+ using value_type = T;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+
+ template <typename U>
+ struct rebind {
+ using other = SecureAllocator<U>;
+ };
+
+ pointer allocate(size_type n) {
+ return static_cast<pointer>(secure_allocator_details::allocateWrapper(
+ sizeof(value_type) * n, std::alignment_of<T>::value, DomainTraits::peg()));
+ }
- pointer allocate(size_type n) {
- return static_cast<pointer>(secure_allocator_details::allocate(
- sizeof(value_type) * n, std::alignment_of<T>::value));
- }
+ pointer allocate(size_type n, const_void_pointer) {
+ return allocate(n);
+ }
- pointer allocate(size_type n, const_void_pointer) {
- return allocate(n);
- }
+ void deallocate(pointer ptr, size_type n) {
+ return secure_allocator_details::deallocateWrapper(
+ static_cast<void*>(ptr), sizeof(value_type) * n, DomainTraits::peg());
+ }
- void deallocate(pointer ptr, size_type n) {
- return secure_allocator_details::deallocate(static_cast<void*>(ptr),
- sizeof(value_type) * n);
- }
+ size_type max_size() {
+ return std::numeric_limits<size_type>::max();
+ }
- size_type max_size() {
- return std::numeric_limits<size_type>::max();
- }
+ SecureAllocator() = default;
- SecureAllocator() = default;
+ template <typename U>
+ SecureAllocator(const SecureAllocator<U>& other) {}
- template <typename U>
- SecureAllocator(const SecureAllocator<U>& other) {}
+ template <typename U, typename... Args>
+ void construct(U* p, Args&&... args) {
+ ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
+ }
- template <typename U, typename... Args>
- void construct(U* p, Args&&... args) {
- ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
- }
+ template <typename U>
+ void destroy(U* p) {
+ p->~U();
+ }
- template <typename U>
- void destroy(U* p) {
- p->~U();
- }
+ SecureAllocator select_on_container_copy_construction() {
+ // SecureAllocator is stateless, so just return a default
+ // constructed instance.
+ return SecureAllocator();
+ }
- SecureAllocator select_on_container_copy_construction() {
- // SecureAllocator is stateless, so just return a default
- // constructed instance.
- return SecureAllocator();
+ // For background:
+ //
+ // http://stackoverflow.com/questions/27471053/example-usage-of-propagate-on-container-move-assignment
+ //
+ // https://foonathan.github.io/blog/2015/10/05/allocatorawarecontainer-propagation-pitfalls.html
+ //
+ // This allocator is stateless, so we can avoid a runtime check
+ // (even though it would probably be optimized out based on the
+ // constrexpr-esque nature of our equality comparison operator),
+ // so we can set all of these to true.
+ using propagate_on_container_copy_assignment = std::true_type;
+ using propagate_on_container_move_assignment = std::true_type;
+ using propagate_on_container_swap = std::true_type;
+
+ using is_always_equal = std::true_type;
+ };
+
+ template <typename T, typename U>
+ friend bool operator==(const SecureAllocator<T>& lhs, const SecureAllocator<U>& rhs) {
+ // Note: If you change this, you must re-evaluate the select_ and
+ // propagate_ methods and typedefs above.
+ return true;
}
- // For background:
- //
- // http://stackoverflow.com/questions/27471053/example-usage-of-propagate-on-container-move-assignment
- //
- // https://foonathan.github.io/blog/2015/10/05/allocatorawarecontainer-propagation-pitfalls.html
- //
- // This allocator is stateless, so we can avoid a runtime check
- // (even though it would probably be optimized out based on the
- // constrexpr-esque nature of our equality comparison operator),
- // so we can set all of these to true.
- using propagate_on_container_copy_assignment = std::true_type;
- using propagate_on_container_move_assignment = std::true_type;
- using propagate_on_container_swap = std::true_type;
-
- using is_always_equal = std::true_type;
-};
+ template <typename T, typename U>
+ friend bool operator!=(const SecureAllocator<T>& lhs, const SecureAllocator<U>& rhs) {
+ return !(lhs == rhs);
+ }
-template <typename T, typename U>
-bool operator==(const SecureAllocator<T>& lhs, const SecureAllocator<U>& rhs) {
- // Note: If you change this, you must re-evaluate the select_ and
- // propagate_ methods and typedefs above.
- return true;
-}
+ /**
+ * SecureHandle offers a smart pointer-ish interface to a type.
+ *
+ * It attempts to solve the problem of using container types with small object optimizations
+ * that
+ * might accidentally leave important data on the stack if they're too small to spill to the
+ * heap.
+ * It uses the secure allocator for allocations and deallocations.
+ *
+ * This type is meant to offer more value like semantics than a unique_ptr:
+ * - SecureHandle's are only default constructible if their T is
+ * - You can construct a SecureHandle like the underlying value:
+ * SecureHandle<Mytype> type(foo, bar baz);
+ * - SecureHandle's are copyable if their T's are
+ * - only moving can produce a non-usable T
+ *
+ * While still being cheap and convenient like a unique_ptr:
+ * - SecureHandle's move by pointer to their secure storage
+ * - T& operator*()
+ * - T* operator->()
+ *
+ * In a moved from state, SecureHandle's may be copy or move assigned and the destructor may
+ * run,
+ * but all other operations will invariant.
+ */
+ template <typename T>
+ class SecureHandle {
+ public:
+ // NOTE: (jcarey)
+ //
+ // We have the default ctor and the perfect forwarding ctor because msvc 2013 ice's on some
+ // default constructed types without it (sfinae was falling over for some reason).
+ //
+ // For non-default constructible t's, we'll fail to substitute the forwarded call to new
+ SecureHandle() : _t(_new()) {}
+
+ // Generic constructor that forwards to the underlying T if the first arg isn't a
+ // SecureHandle
+ template <
+ typename Arg,
+ typename... Args,
+ stdx::enable_if_t<!std::is_same<SecureHandle<T>, typename std::decay<Arg>::type>::value,
+ int> = 0>
+ SecureHandle(Arg&& arg, Args&&... args)
+ : _t(_new(std::forward<Arg>(arg), std::forward<Args>(args)...)) {}
+
+ SecureHandle(const SecureHandle& other) : _t(_new(*other)) {}
+
+ SecureHandle& operator=(const SecureHandle& other) {
+ if (_t) {
+ *_t = *other;
+ } else {
+ _t = _new(*other);
+ }
-template <typename T, typename U>
-bool operator!=(const SecureAllocator<T>& lhs, const SecureAllocator<U>& rhs) {
- return !(lhs == rhs);
-}
+ return *this;
+ }
-/**
- * SecureHandle offers a smart pointer-ish interface to a type.
- *
- * It attempts to solve the problem of using container types with small object optimizations that
- * might accidentally leave important data on the stack if they're too small to spill to the heap.
- * It uses the secure allocator for allocations and deallocations.
- *
- * This type is meant to offer more value like semantics than a unique_ptr:
- * - SecureHandle's are only default constructible if their T is
- * - You can construct a SecureHandle like the underlying value:
- * SecureHandle<Mytype> type(foo, bar baz);
- * - SecureHandle's are copyable if their T's are
- * - only moving can produce a non-usable T
- *
- * While still being cheap and convenient like a unique_ptr:
- * - SecureHandle's move by pointer to their secure storage
- * - T& operator*()
- * - T* operator->()
- *
- * In a moved from state, SecureHandle's may be copy or move assigned and the destructor may run,
- * but all other operations will invariant.
- */
-template <typename T>
-class SecureHandle {
-public:
- // NOTE: (jcarey)
- //
- // We have the default ctor and the perfect forwarding ctor because msvc 2013 ice's on some
- // default constructed types without it (sfinae was falling over for some reason).
- //
- // For non-default constructible t's, we'll fail to substitute the forwarded call to new
- SecureHandle() : _t(_new()) {}
-
- // Generic constructor that forwards to the underlying T if the first arg isn't a SecureHandle
- template <
- typename Arg,
- typename... Args,
- stdx::enable_if_t<!std::is_same<SecureHandle<T>, typename std::decay<Arg>::type>::value,
- int> = 0>
- SecureHandle(Arg&& arg, Args&&... args)
- : _t(_new(std::forward<Arg>(arg), std::forward<Args>(args)...)) {}
-
- SecureHandle(const SecureHandle& other) : _t(_new(*other)) {}
-
- SecureHandle& operator=(const SecureHandle& other) {
- if (_t) {
- *_t = *other;
- } else {
- _t = _new(*other);
+ SecureHandle(SecureHandle&& other) : _t(other._t) {
+ other._t = nullptr;
}
- return *this;
- }
+ SecureHandle& operator=(SecureHandle&& other) {
+ if (&other == this) {
+ return *this;
+ }
- SecureHandle(SecureHandle&& other) : _t(other._t) {
- other._t = nullptr;
- }
+ _delete();
+
+ _t = other._t;
+ other._t = nullptr;
- SecureHandle& operator=(SecureHandle&& other) {
- if (&other == this) {
return *this;
}
- _delete();
+ ~SecureHandle() {
+ _delete();
+ }
- _t = other._t;
- other._t = nullptr;
+ T& operator*() const {
+ invariant(_t);
- return *this;
- }
+ return *_t;
+ }
- ~SecureHandle() {
- _delete();
- }
+ T* operator->() const {
+ invariant(_t);
- T& operator*() const {
- invariant(_t);
+ return _t;
+ }
- return *_t;
- }
+ private:
+ template <typename... Args>
+ static T* _new(Args&&... args) {
+ return ::new (secure_allocator_details::allocateWrapper(
+ sizeof(T), std::alignment_of<T>::value, DomainTraits::peg()))
+ T(std::forward<Args>(args)...);
+ }
- T* operator->() const {
- invariant(_t);
+ void _delete() {
+ if (_t) {
+ _t->~T();
+ secure_allocator_details::deallocateWrapper(_t, sizeof(T), DomainTraits::peg());
+ }
+ }
- return _t;
- }
+ T* _t;
+ };
-private:
- template <typename... Args>
- static T* _new(Args&&... args) {
- return ::new (secure_allocator_details::allocate(sizeof(T), std::alignment_of<T>::value))
- T(std::forward<Args>(args)...);
- }
+ template <typename T>
+ using SecureVector = SecureHandle<std::vector<T, SecureAllocator<T>>>;
- void _delete() {
- if (_t) {
- _t->~T();
- secure_allocator_details::deallocate(_t, sizeof(T));
- }
+ using SecureString =
+ SecureHandle<std::basic_string<char, std::char_traits<char>, SecureAllocator<char>>>;
+};
+
+struct SecureAllocatorDefaultDomainTrait {
+ constexpr static bool peg() {
+ return true;
}
+};
- T* _t;
+struct SecureAllocatorAuthDomainTrait {
+ static constexpr StringData DomainType = "auth"_sd;
};
-template <typename T>
-using SecureVector = SecureHandle<std::vector<T, SecureAllocator<T>>>;
+using SecureAllocatorAuthDomain =
+ SecureAllocatorDomain<TraitNamedDomain<SecureAllocatorAuthDomainTrait>>;
-using SecureString =
- SecureHandle<std::basic_string<char, std::char_traits<char>, SecureAllocator<char>>>;
+using SecureAllocatorDefaultDomain = SecureAllocatorDomain<SecureAllocatorDefaultDomainTrait>;
+
+template <typename T>
+using SecureVector = SecureAllocatorDefaultDomain::SecureVector<T>;
+using SecureString = SecureAllocatorDefaultDomain::SecureString;
} // namespace mongo
diff --git a/src/mongo/base/secure_allocator_test.cpp b/src/mongo/base/secure_allocator_test.cpp
index 750dc8c5c78..9bc65d585fe 100644
--- a/src/mongo/base/secure_allocator_test.cpp
+++ b/src/mongo/base/secure_allocator_test.cpp
@@ -37,7 +37,7 @@
namespace mongo {
TEST(SecureAllocator, SecureVector) {
- SecureVector<int> vec;
+ SecureAllocatorDefaultDomain::SecureVector<int> vec;
vec->push_back(1);
vec->push_back(2);
@@ -50,19 +50,19 @@ TEST(SecureAllocator, SecureVector) {
}
TEST(SecureAllocator, SecureString) {
- SecureString str;
+ SecureAllocatorDefaultDomain::SecureString str;
str->resize(2000, 'x');
- ASSERT_EQUALS(0, str->compare(*SecureString(2000, 'x')));
+ ASSERT_EQUALS(0, str->compare(*SecureAllocatorDefaultDomain::SecureString(2000, 'x')));
- SecureString str2(str);
+ SecureAllocatorDefaultDomain::SecureString str2(str);
ASSERT_NOT_EQUALS(&*str, &*str2);
str2 = str;
ASSERT_NOT_EQUALS(&*str, &*str2);
auto strPtr = &*str;
auto str2Ptr = &*str2;
- SecureString str3(std::move(str));
+ SecureAllocatorDefaultDomain::SecureString str3(std::move(str));
ASSERT_EQUALS(strPtr, &*str3);
str3 = std::move(str2);
ASSERT_EQUALS(str2Ptr, &*str3);
@@ -72,8 +72,8 @@ TEST(SecureAllocator, SecureString) {
// design (page per object), you couldn't make more than 8-50 objects before running out of lockable
// pages.
TEST(SecureAllocator, ManySecureBytes) {
- std::array<SecureHandle<char>, 4096> chars;
- std::vector<SecureHandle<char>> e_chars(4096, 'e');
+ std::array<SecureAllocatorDefaultDomain::SecureHandle<char>, 4096> chars;
+ std::vector<SecureAllocatorDefaultDomain::SecureHandle<char>> e_chars(4096, 'e');
}
TEST(SecureAllocator, NonDefaultConstructibleWorks) {
@@ -82,7 +82,42 @@ TEST(SecureAllocator, NonDefaultConstructibleWorks) {
Foo() = delete;
};
- SecureHandle<Foo> foo(10);
+ SecureAllocatorDefaultDomain::SecureHandle<Foo> foo(10);
+}
+
+TEST(SecureAllocator, allocatorCanBeDisabled) {
+ static size_t pegInvokationCountLast;
+ static size_t pegInvokationCount;
+ pegInvokationCountLast = 0;
+ pegInvokationCount = 0;
+ struct UnsecureAllocatorTrait {
+ static bool peg() {
+ pegInvokationCount++;
+
+ return false;
+ }
+ };
+ using UnsecureAllocatorDomain = SecureAllocatorDomain<UnsecureAllocatorTrait>;
+
+ {
+ std::vector<UnsecureAllocatorDomain::SecureHandle<char>> more_e_chars(4096, 'e');
+ ASSERT_GT(pegInvokationCount, pegInvokationCountLast);
+ pegInvokationCountLast = pegInvokationCount;
+
+ UnsecureAllocatorDomain::SecureString str;
+ ASSERT_GT(pegInvokationCount, pegInvokationCountLast);
+ pegInvokationCountLast = pegInvokationCount;
+
+ str->resize(2000, 'x');
+ ASSERT_GT(pegInvokationCount, pegInvokationCountLast);
+ pegInvokationCountLast = pegInvokationCount;
+
+ ASSERT_EQUALS(0, str->compare(*UnsecureAllocatorDomain::SecureString(2000, 'x')));
+ ASSERT_GT(pegInvokationCount, pegInvokationCountLast);
+ pegInvokationCountLast = pegInvokationCount;
+ }
+
+ ASSERT_GT(pegInvokationCount, pegInvokationCountLast);
}
} // namespace mongo
diff --git a/src/mongo/crypto/mechanism_scram.h b/src/mongo/crypto/mechanism_scram.h
index b12cebbf2e1..97875394df1 100644
--- a/src/mongo/crypto/mechanism_scram.h
+++ b/src/mongo/crypto/mechanism_scram.h
@@ -33,6 +33,7 @@
#include "mongo/base/secure_allocator.h"
#include "mongo/base/status.h"
#include "mongo/crypto/sha1_block.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/jsobj.h"
namespace mongo {
@@ -97,7 +98,7 @@ public:
// to a callback, which fills the memory.
template <typename T>
explicit SCRAMSecrets(T initializationFun)
- : _ptr(std::make_shared<SecureHandle<SCRAMSecretsHolder>>()) {
+ : _ptr(std::make_shared<SecureAllocatorAuthDomain::SecureHandle<SCRAMSecretsHolder>>()) {
initializationFun((*this)->clientKey, (*this)->storedKey, (*this)->serverKey);
}
@@ -106,20 +107,20 @@ public:
return static_cast<bool>(_ptr);
}
- const SecureHandle<SCRAMSecretsHolder>& operator*() const& {
+ const SecureAllocatorAuthDomain::SecureHandle<SCRAMSecretsHolder>& operator*() const& {
invariant(_ptr);
return *_ptr;
}
void operator*() && = delete;
- const SecureHandle<SCRAMSecretsHolder>& operator->() const& {
+ const SecureAllocatorAuthDomain::SecureHandle<SCRAMSecretsHolder>& operator->() const& {
invariant(_ptr);
return *_ptr;
}
void operator->() && = delete;
private:
- std::shared_ptr<SecureHandle<SCRAMSecretsHolder>> _ptr;
+ std::shared_ptr<SecureAllocatorAuthDomain::SecureHandle<SCRAMSecretsHolder>> _ptr;
};
/*
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index 578d9b384e5..8087bdbe849 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -32,6 +32,7 @@
#include <string>
#include "mongo/base/disallow_copying.h"
+#include "mongo/base/secure_allocator.h"
#include "mongo/base/status.h"
#include "mongo/bson/mutable/element.h"
#include "mongo/bson/oid.h"
@@ -44,6 +45,7 @@
#include "mongo/db/auth/user_name_hash.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/namespace_string.h"
+#include "mongo/db/server_options.h"
#include "mongo/platform/unordered_map.h"
#include "mongo/stdx/condition_variable.h"
#include "mongo/stdx/functional.h"
diff --git a/src/mongo/db/auth/sasl_plain_server_conversation.cpp b/src/mongo/db/auth/sasl_plain_server_conversation.cpp
index 03b58dc1819..ecd24a4ac98 100644
--- a/src/mongo/db/auth/sasl_plain_server_conversation.cpp
+++ b/src/mongo/db/auth/sasl_plain_server_conversation.cpp
@@ -50,7 +50,7 @@ StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::st
// Expecting user input on the form: [authz-id]\0authn-id\0pwd
std::string input = inputData.toString();
- SecureString pwd = "";
+ SecureAllocatorAuthDomain::SecureString pwd = "";
try {
size_t firstNull = inputData.find('\0');
if (firstNull == std::string::npos) {
@@ -78,7 +78,7 @@ StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::st
str::stream()
<< "SASL authorization identity must match authentication identity");
}
- pwd = SecureString(input.substr(secondNull + 1).c_str());
+ pwd = SecureAllocatorAuthDomain::SecureString(input.substr(secondNull + 1).c_str());
if (pwd->empty()) {
return Status(ErrorCodes::AuthenticationFailed,
str::stream()
diff --git a/src/mongo/db/server_options.h b/src/mongo/db/server_options.h
index b4efdde5300..fe66db0f8c2 100644
--- a/src/mongo/db/server_options.h
+++ b/src/mongo/db/server_options.h
@@ -174,7 +174,21 @@ struct ServerGlobalParams {
// "3.2" feature compatibility mode.
AtomicWord<bool> validateFeaturesAsMaster{true};
} featureCompatibility;
+
+ std::vector<std::string> disabledSecureAllocatorDomains;
};
extern ServerGlobalParams serverGlobalParams;
+
+template <typename NameTrait>
+struct TraitNamedDomain {
+ static bool peg() {
+ const auto& dsmd = serverGlobalParams.disabledSecureAllocatorDomains;
+ const auto contains = [&](StringData dt) {
+ return std::find(dsmd.begin(), dsmd.end(), dt) != dsmd.end();
+ };
+ static const bool ret = !(contains("*"_sd) || contains(NameTrait::DomainType));
+ return ret;
+ }
+};
}
diff --git a/src/mongo/db/server_options_helpers.cpp b/src/mongo/db/server_options_helpers.cpp
index 11a4f37008a..3b671684d73 100644
--- a/src/mongo/db/server_options_helpers.cpp
+++ b/src/mongo/db/server_options_helpers.cpp
@@ -1101,4 +1101,9 @@ Status storeServerOptions(const moe::Environment& params) {
return Status::OK();
}
+ExportedServerParameter<std::vector<std::string>, ServerParameterType::kStartupOnly>
+ SecureAllocatorDomains(ServerParameterSet::getGlobal(),
+ "disabledSecureAllocatorDomains",
+ &serverGlobalParams.disabledSecureAllocatorDomains);
+
} // namespace mongo