diff options
Diffstat (limited to 'src/Platform.cc')
| -rw-r--r-- | src/Platform.cc | 144 |
1 files changed, 109 insertions, 35 deletions
diff --git a/src/Platform.cc b/src/Platform.cc index 0e1912da..94ec86f2 100644 --- a/src/Platform.cc +++ b/src/Platform.cc @@ -35,29 +35,29 @@ #include "Platform.h" #include <stdlib.h> /* _fmode */ -#include <fcntl.h> /* _O_BINARY */ +#include <fcntl.h> /* _O_BINARY */ #include <locale.h> // For setlocale, LC_* #include <iostream> #ifdef HAVE_OPENSSL -# include <openssl/err.h> -# include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/ssl.h> #endif // HAVE_OPENSSL #ifdef HAVE_LIBGCRYPT -# include <gcrypt.h> +#include <gcrypt.h> #endif // HAVE_LIBGCRYPT #ifdef HAVE_LIBGNUTLS -# include <gnutls/gnutls.h> +#include <gnutls/gnutls.h> #endif // HAVE_LIBGNUTLS #ifdef ENABLE_ASYNC_DNS -# include <ares.h> +#include <ares.h> #endif // ENABLE_ASYNC_DNS #ifdef HAVE_LIBSSH2 -# include <libssh2.h> +#include <libssh2.h> #endif // HAVE_LIBSSH2 #include "a2netcompat.h" @@ -68,36 +68,104 @@ #include "OptionParser.h" #include "prefs.h" #ifdef HAVE_LIBGMP -# include "a2gmp.h" +#include "a2gmp.h" #endif // HAVE_LIBGMP #include "LogFactory.h" +#include "util.h" namespace aria2 { #ifdef HAVE_LIBGNUTLS namespace { - void gnutls_log_callback(int level, const char *str) - { - using namespace aria2; - // GnuTLS adds a newline. Drop it. - std::string msg(str); - msg.resize(msg.size() - 1); - A2_LOG_DEBUG(fmt("GnuTLS: <%d> %s", level, msg.c_str())); - } +void gnutls_log_callback(int level, const char* str) +{ + using namespace aria2; + // GnuTLS adds a newline. Drop it. + std::string msg(str); + msg.resize(msg.size() - 1); + A2_LOG_DEBUG(fmt("GnuTLS: <%d> %s", level, msg.c_str())); +} } #endif // HAVE_LIBGNUTLS bool Platform::initialized_ = false; -Platform::Platform() -{ - setUp(); -} +Platform::Platform() { setUp(); } + +Platform::~Platform() { tearDown(); } -Platform::~Platform() +#ifdef __MINGW32__ +namespace { +bool gainPrivilege(LPCTSTR privName) { - tearDown(); + LUID luid; + TOKEN_PRIVILEGES tp; + + if (!LookupPrivilegeValue(nullptr, privName, &luid)) { + auto errNum = GetLastError(); + A2_LOG_WARN(fmt("Lookup for privilege name %s failed. cause: %s", privName, + util::formatLastError(errNum).c_str())); + return false; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + HANDLE token; + if (!OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { + auto errNum = GetLastError(); + A2_LOG_WARN(fmt("Getting process token failed. cause: %s", + util::formatLastError(errNum).c_str())); + return false; + } + + auto tokenCloser = defer(token, CloseHandle); + + if (!AdjustTokenPrivileges(token, FALSE, &tp, 0, NULL, NULL)) { + auto errNum = GetLastError(); + A2_LOG_WARN(fmt("Gaining privilege %s failed. cause: %s", privName, + util::formatLastError(errNum).c_str())); + return false; + } + + // Check privilege was really gained + DWORD bufsize = 0; + GetTokenInformation(token, TokenPrivileges, nullptr, 0, &bufsize); + if (bufsize == 0) { + A2_LOG_WARN("Checking privilege failed."); + return false; + } + + auto buf = make_unique<char[]>(bufsize); + if (!GetTokenInformation(token, TokenPrivileges, buf.get(), bufsize, + &bufsize)) { + auto errNum = GetLastError(); + A2_LOG_WARN(fmt("Checking privilege failed. cause: %s", + util::formatLastError(errNum).c_str())); + return false; + } + + auto privs = reinterpret_cast<TOKEN_PRIVILEGES*>(buf.get()); + for (size_t i = 0; i < privs->PrivilegeCount; ++i) { + auto& priv = privs->Privileges[i]; + if (memcmp(&priv.Luid, &luid, sizeof(luid)) != 0) { + continue; + } + if (priv.Attributes == SE_PRIVILEGE_ENABLED) { + return true; + } + + break; + } + + A2_LOG_WARN(fmt("Gaining privilege %s failed.", privName)); + + return false; } +} // namespace +#endif // __MINGW32__ bool Platform::setUp() { @@ -109,10 +177,10 @@ bool Platform::setUp() global::initGmp(); #endif // HAVE_LIBGMP #ifdef ENABLE_NLS - setlocale (LC_CTYPE, ""); - setlocale (LC_MESSAGES, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + setlocale(LC_CTYPE, ""); + setlocale(LC_MESSAGES, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); #endif // ENABLE_NLS #ifdef HAVE_OPENSSL @@ -123,7 +191,7 @@ bool Platform::setUp() OpenSSL_add_all_algorithms(); #endif // HAVE_OPENSSL #ifdef HAVE_LIBGCRYPT - if(!gcry_check_version("1.2.4")) { + if (!gcry_check_version("1.2.4")) { throw DL_ABORT_EX("gcry_check_version() failed."); } gcry_control(GCRYCTL_DISABLE_SECMEM, 0); @@ -132,9 +200,9 @@ bool Platform::setUp() #ifdef HAVE_LIBGNUTLS { int r = gnutls_global_init(); - if(r != GNUTLS_E_SUCCESS) { - throw DL_ABORT_EX(fmt("gnutls_global_init() failed, cause:%s", - gnutls_strerror(r))); + if (r != GNUTLS_E_SUCCESS) { + throw DL_ABORT_EX( + fmt("gnutls_global_init() failed, cause:%s", gnutls_strerror(r))); } gnutls_global_set_log_function(gnutls_log_callback); @@ -144,7 +212,7 @@ bool Platform::setUp() #ifdef CARES_HAVE_ARES_LIBRARY_INIT int aresErrorCode; - if((aresErrorCode = ares_library_init(ARES_LIB_INIT_ALL)) != 0) { + if ((aresErrorCode = ares_library_init(ARES_LIB_INIT_ALL)) != 0) { global::cerr()->printf("ares_library_init() failed:%s\n", ares_strerror(aresErrorCode)); } @@ -171,6 +239,15 @@ bool Platform::setUp() (void)_setmode(_fileno(stdin), _O_BINARY); (void)_setmode(_fileno(stdout), _O_BINARY); (void)_setmode(_fileno(stderr), _O_BINARY); + + // Windows build: --file-allocation=falloc uses SetFileValidData + // which requires SE_MANAGE_VOLUME_NAME privilege. SetFileValidData + // has security implications (see + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365544%28v=vs.85%29.aspx). + if (!gainPrivilege(SE_MANAGE_VOLUME_NAME)) { + A2_LOG_WARN("--file-allocation=falloc will not work properly."); + } + #endif // __MINGW32__ return true; @@ -206,9 +283,6 @@ bool Platform::tearDown() return true; } -bool Platform::isInitialized() -{ - return initialized_; -} +bool Platform::isInitialized() { return initialized_; } } // namespace aria2 |
