mingw: Defer the falloc warning until falloc is specified by option

pull/632/head
Tatsuhiro Tsujikawa 2016-04-18 22:16:30 +09:00
parent c9e2223741
commit 1126722bd3
5 changed files with 98 additions and 82 deletions

View File

@ -34,14 +34,33 @@
/* copyright --> */ /* copyright --> */
#include "FallocFileAllocationIterator.h" #include "FallocFileAllocationIterator.h"
#include "DlAbortEx.h" #include "DlAbortEx.h"
#include "util.h"
#include "LogFactory.h"
namespace aria2 { namespace aria2 {
#ifdef __MINGW32__
bool FallocFileAllocationIterator::gainPrivilegeAttempted_ = false;
#endif // __MINGW32__
FallocFileAllocationIterator::FallocFileAllocationIterator(BinaryStream* stream, FallocFileAllocationIterator::FallocFileAllocationIterator(BinaryStream* stream,
int64_t offset, int64_t offset,
int64_t totalLength) int64_t totalLength)
: stream_(stream), offset_(offset), totalLength_(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() void FallocFileAllocationIterator::allocateChunk()

View File

@ -47,6 +47,10 @@ private:
int64_t offset_; int64_t offset_;
int64_t totalLength_; int64_t totalLength_;
#ifdef __MINGW32__
static bool gainPrivilegeAttempted_;
#endif // __MINGW32__
public: public:
FallocFileAllocationIterator(BinaryStream* stream, int64_t offset, FallocFileAllocationIterator(BinaryStream* stream, int64_t offset,
int64_t totalLength); int64_t totalLength);

View File

@ -94,79 +94,6 @@ Platform::Platform() { setUp(); }
Platform::~Platform() { tearDown(); } 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<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() bool Platform::setUp()
{ {
if (initialized_) { if (initialized_) {
@ -239,15 +166,6 @@ bool Platform::setUp()
(void)_setmode(_fileno(stdin), _O_BINARY); (void)_setmode(_fileno(stdin), _O_BINARY);
(void)_setmode(_fileno(stdout), _O_BINARY); (void)_setmode(_fileno(stdout), _O_BINARY);
(void)_setmode(_fileno(stderr), _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__ #endif // __MINGW32__
return true; return true;

View File

@ -2121,6 +2121,77 @@ void make_fd_cloexec(int fd)
#endif // !__MINGW32__ #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<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;
}
#endif // __MINGW32__
} // namespace util } // namespace util
} // namespace aria2 } // namespace aria2

View File

@ -867,6 +867,10 @@ std::string formatLastError(int errNum);
// CreateProcess call. // CreateProcess call.
void make_fd_cloexec(int fd); void make_fd_cloexec(int fd);
#ifdef __MINGW32__
bool gainPrivilege(LPCTSTR privName);
#endif // __MINGW32__
} // namespace util } // namespace util
} // namespace aria2 } // namespace aria2