1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
#include "privilege.h"
#include <map>
//#include <mutex>
#include "win.h" //includes "windows.h"
#include "thread.h"
#include "zstring.h"
#include "scope_guard.h"
#include "win_ver.h"
using namespace zen;
namespace
{
bool privilegeIsActive(const wchar_t* privilege) //throw FileError
{
HANDLE hToken = nullptr;
if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
TOKEN_QUERY, //__in DWORD DesiredAccess,
&hToken)) //__out PHANDLE TokenHandle
throwFileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), L"OpenProcessToken", getLastError());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
LUID luid = {};
if (!::LookupPrivilegeValue(nullptr, //__in_opt LPCTSTR lpSystemName,
privilege, //__in LPCTSTR lpName,
&luid )) //__out PLUID lpLuid
throwFileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), L"LookupPrivilegeValue", getLastError());
PRIVILEGE_SET priv = {};
priv.PrivilegeCount = 1;
priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
priv.Privilege[0].Luid = luid;
priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
BOOL alreadyGranted = FALSE;
if (!::PrivilegeCheck(hToken, //__in HANDLE ClientToken,
&priv, //__inout PPRIVILEGE_SET RequiredPrivileges,
&alreadyGranted)) //__out LPBOOL pfResult
throwFileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), L"PrivilegeCheck", getLastError());
return alreadyGranted != FALSE;
}
void setPrivilege(const wchar_t* privilege, bool enable) //throw FileError
{
HANDLE hToken = nullptr;
if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
TOKEN_ADJUST_PRIVILEGES, //__in DWORD DesiredAccess,
&hToken)) //__out PHANDLE TokenHandle
throwFileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), L"OpenProcessToken", getLastError());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
LUID luid = {};
if (!::LookupPrivilegeValue(nullptr, //__in_opt LPCTSTR lpSystemName,
privilege, //__in LPCTSTR lpName,
&luid )) //__out PLUID lpLuid
throwFileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), L"LookupPrivilegeValue", getLastError());
TOKEN_PRIVILEGES tp = {};
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
if (!::AdjustTokenPrivileges(hToken, //__in HANDLE TokenHandle,
false, //__in BOOL DisableAllPrivileges,
&tp, //__in_opt PTOKEN_PRIVILEGES NewState,
0, //__in DWORD BufferLength,
nullptr, //__out_opt PTOKEN_PRIVILEGES PreviousState,
nullptr)) //__out_opt PDWORD ReturnLength
throwFileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), L"AdjustTokenPrivileges", getLastError());
DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
if (lastError == ERROR_NOT_ALL_ASSIGNED) //check although previous function returned with success!
{
#ifdef __MINGW32__ //Shobjidl.h
#define ERROR_ELEVATION_REQUIRED 740L
#endif
if (vistaOrLater()) //replace this useless error code with what it *really* means!
lastError = ERROR_ELEVATION_REQUIRED;
throwFileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), L"AdjustTokenPrivileges", lastError);
}
}
class Privileges
{
public:
static Privileges& getInstance()
{
//meyers singleton: avoid static initialization order problem in global namespace!
static Privileges inst;
return inst;
}
void ensureActive(const wchar_t* privilege) //throw FileError
{
boost::lock_guard<boost::mutex> dummy(lockPrivileges);
if (activePrivileges.find(privilege) != activePrivileges.end())
return; //privilege already active
if (privilegeIsActive(privilege)) //privilege was already active before starting this tool
activePrivileges.insert(std::make_pair(privilege, false));
else
{
setPrivilege(privilege, true);
activePrivileges.insert(std::make_pair(privilege, true));
}
}
private:
Privileges() {}
Privileges (const Privileges&) = delete;
Privileges& operator=(const Privileges&) = delete;
~Privileges() //clean up: deactivate all privileges that have been activated by this application
{
for (const auto& priv : activePrivileges)
if (priv.second)
{
try
{
setPrivilege(priv.first.c_str(), false); //throw FileError
}
catch (FileError&) {}
}
}
std::map<Zstring, bool> activePrivileges; //bool: enabled by this application
boost::mutex lockPrivileges;
};
//caveat: function scope static initialization is not thread-safe in VS 2010!
auto& dummy = Privileges::getInstance();
}
void zen::activatePrivilege(const wchar_t* privilege) //throw FileError
{
Privileges::getInstance().ensureActive(privilege);
}
|