From 1126722bd3e21dec8ecc84b9129c8998ac2bb661 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 18 Apr 2016 22:16:30 +0900 Subject: mingw: Defer the falloc warning until falloc is specified by option --- src/FallocFileAllocationIterator.cc | 19 +++++++++ src/FallocFileAllocationIterator.h | 4 ++ src/Platform.cc | 82 ------------------------------------- src/util.cc | 71 ++++++++++++++++++++++++++++++++ src/util.h | 4 ++ 5 files changed, 98 insertions(+), 82 deletions(-) diff --git a/src/FallocFileAllocationIterator.cc b/src/FallocFileAllocationIterator.cc index febcf19b..04590557 100644 --- a/src/FallocFileAllocationIterator.cc +++ b/src/FallocFileAllocationIterator.cc @@ -34,14 +34,33 @@ /* copyright --> */ #include "FallocFileAllocationIterator.h" #include "DlAbortEx.h" +#include "util.h" +#include "LogFactory.h" namespace aria2 { +#ifdef __MINGW32__ +bool FallocFileAllocationIterator::gainPrivilegeAttempted_ = false; +#endif // __MINGW32__ + FallocFileAllocationIterator::FallocFileAllocationIterator(BinaryStream* stream, int64_t offset, int64_t totalLength) : stream_(stream), offset_(offset), totalLength_(totalLength) { +#ifdef __MINGW32__ + // 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 (!gainPrivilegeAttempted_) { + if (!util::gainPrivilege(SE_MANAGE_VOLUME_NAME)) { + A2_LOG_WARN("--file-allocation=falloc will not work properly."); + } + + gainPrivilegeAttempted_ = true; + } +#endif // __MINGW32__ } void FallocFileAllocationIterator::allocateChunk() diff --git a/src/FallocFileAllocationIterator.h b/src/FallocFileAllocationIterator.h index fb306af1..08b8b4a1 100644 --- a/src/FallocFileAllocationIterator.h +++ b/src/FallocFileAllocationIterator.h @@ -47,6 +47,10 @@ private: int64_t offset_; int64_t totalLength_; +#ifdef __MINGW32__ + static bool gainPrivilegeAttempted_; +#endif // __MINGW32__ + public: FallocFileAllocationIterator(BinaryStream* stream, int64_t offset, int64_t totalLength); diff --git a/src/Platform.cc b/src/Platform.cc index 94ec86f2..cbeab9e9 100644 --- a/src/Platform.cc +++ b/src/Platform.cc @@ -94,79 +94,6 @@ Platform::Platform() { setUp(); } Platform::~Platform() { tearDown(); } -#ifdef __MINGW32__ -namespace { -bool gainPrivilege(LPCTSTR privName) -{ - 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(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(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() { if (initialized_) { @@ -239,15 +166,6 @@ 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; diff --git a/src/util.cc b/src/util.cc index 045aa014..2f9e7d38 100644 --- a/src/util.cc +++ b/src/util.cc @@ -2121,6 +2121,77 @@ void make_fd_cloexec(int fd) #endif // !__MINGW32__ } +#ifdef __MINGW32__ +bool gainPrivilege(LPCTSTR privName) +{ + 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(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(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; +} +#endif // __MINGW32__ + } // namespace util } // namespace aria2 diff --git a/src/util.h b/src/util.h index 14b5d146..25183b5c 100644 --- a/src/util.h +++ b/src/util.h @@ -867,6 +867,10 @@ std::string formatLastError(int errNum); // CreateProcess call. void make_fd_cloexec(int fd); +#ifdef __MINGW32__ +bool gainPrivilege(LPCTSTR privName); +#endif // __MINGW32__ + } // namespace util } // namespace aria2 -- cgit