]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Copyright Andrey Semashev 2016. | |
3 | * Distributed under the Boost Software License, Version 1.0. | |
4 | * (See accompanying file LICENSE_1_0.txt or copy at | |
5 | * http://www.boost.org/LICENSE_1_0.txt) | |
6 | */ | |
7 | /*! | |
8 | * \file windows/object_name.cpp | |
9 | * \author Andrey Semashev | |
10 | * \date 06.03.2016 | |
11 | * | |
12 | * \brief This header is the Boost.Log library implementation, see the library documentation | |
13 | * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. | |
14 | */ | |
15 | ||
16 | #include <boost/log/detail/config.hpp> | |
17 | #include <cstddef> | |
18 | #include <cstdlib> | |
19 | #include <string> | |
20 | #include <vector> | |
21 | #include <algorithm> | |
22 | #include <boost/memory_order.hpp> | |
23 | #include <boost/atomic/atomic.hpp> | |
24 | #include <boost/move/utility_core.hpp> | |
25 | #include <boost/log/exceptions.hpp> | |
26 | #include <boost/log/utility/ipc/object_name.hpp> | |
27 | #include <boost/detail/winapi/get_last_error.hpp> | |
28 | #include <windows.h> | |
29 | #include <lmcons.h> | |
30 | #include <security.h> | |
31 | #include "windows/auto_handle.hpp" | |
32 | #include "windows/utf_code_conversion.hpp" | |
33 | #include <boost/log/detail/header.hpp> | |
34 | ||
35 | namespace boost { | |
36 | ||
37 | BOOST_LOG_OPEN_NAMESPACE | |
38 | ||
39 | namespace ipc { | |
40 | ||
41 | BOOST_LOG_ANONYMOUS_NAMESPACE { | |
42 | ||
43 | #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 | |
44 | ||
45 | class auto_boundary_descriptor | |
46 | { | |
47 | private: | |
48 | HANDLE m_handle; | |
49 | ||
50 | public: | |
51 | explicit auto_boundary_descriptor(HANDLE h = NULL) BOOST_NOEXCEPT : m_handle(h) | |
52 | { | |
53 | } | |
54 | ||
55 | ~auto_boundary_descriptor() BOOST_NOEXCEPT | |
56 | { | |
57 | if (m_handle) | |
58 | DeleteBoundaryDescriptor(m_handle); | |
59 | } | |
60 | ||
61 | void init(HANDLE h) BOOST_NOEXCEPT | |
62 | { | |
63 | BOOST_ASSERT(m_handle == NULL); | |
64 | m_handle = h; | |
65 | } | |
66 | ||
67 | HANDLE get() const BOOST_NOEXCEPT { return m_handle; } | |
68 | HANDLE* get_ptr() BOOST_NOEXCEPT { return &m_handle; } | |
69 | ||
70 | void swap(auto_boundary_descriptor& that) BOOST_NOEXCEPT | |
71 | { | |
72 | HANDLE h = m_handle; | |
73 | m_handle = that.m_handle; | |
74 | that.m_handle = h; | |
75 | } | |
76 | ||
77 | BOOST_DELETED_FUNCTION(auto_boundary_descriptor(auto_boundary_descriptor const&)) | |
78 | BOOST_DELETED_FUNCTION(auto_boundary_descriptor& operator=(auto_boundary_descriptor const&)) | |
79 | }; | |
80 | ||
81 | //! Handle for the private namespace for \c user scope | |
82 | static boost::atomic< HANDLE > g_user_private_namespace; | |
83 | ||
84 | //! Closes the private namespace on process exit | |
85 | void close_user_namespace() | |
86 | { | |
87 | HANDLE h = g_user_private_namespace.load(boost::memory_order_acquire); | |
88 | if (h) | |
89 | { | |
90 | ClosePrivateNamespace(h, 0); | |
91 | g_user_private_namespace.store((HANDLE)NULL, boost::memory_order_release); | |
92 | } | |
93 | } | |
94 | ||
95 | //! Attempts to create or open the private namespace | |
96 | bool init_user_namespace() | |
97 | { | |
98 | HANDLE h = g_user_private_namespace.load(boost::memory_order_acquire); | |
99 | if (BOOST_UNLIKELY(!h)) | |
100 | { | |
101 | // Obtain the current user SID | |
102 | boost::log::ipc::aux::auto_handle h_process_token; | |
103 | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, h_process_token.get_ptr())) | |
104 | return false; | |
105 | ||
106 | DWORD token_user_size = 0; | |
107 | GetTokenInformation(h_process_token.get(), TokenUser, NULL, 0u, &token_user_size); | |
108 | if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || token_user_size < sizeof(TOKEN_USER)) | |
109 | return false; | |
110 | std::vector< unsigned char > token_user_storage(static_cast< std::size_t >(token_user_size), static_cast< unsigned char >(0u)); | |
111 | if (!GetTokenInformation(h_process_token.get(), TokenUser, &token_user_storage[0], token_user_size, &token_user_size)) | |
112 | return false; | |
113 | ||
114 | TOKEN_USER const& token_user = *reinterpret_cast< const TOKEN_USER* >(&token_user_storage[0]); | |
115 | if (!token_user.User.Sid) | |
116 | return false; | |
117 | ||
118 | // Create a boundary descriptor with the user's SID | |
119 | auto_boundary_descriptor h_boundary(CreateBoundaryDescriptorW(L"User", 0)); | |
120 | if (!h_boundary.get()) | |
121 | return false; | |
122 | ||
123 | if (!AddSIDToBoundaryDescriptor(h_boundary.get_ptr(), token_user.User.Sid)) | |
124 | return false; | |
125 | ||
126 | // Create or open a namespace for kernel objects | |
127 | h = CreatePrivateNamespaceW(NULL, h_boundary.get(), L"User"); | |
128 | if (!h) | |
129 | h = OpenPrivateNamespaceW(h_boundary.get(), L"User"); | |
130 | ||
131 | if (h) | |
132 | { | |
133 | HANDLE expected = NULL; | |
134 | if (g_user_private_namespace.compare_exchange_strong(expected, h, boost::memory_order_acq_rel, boost::memory_order_acquire)) | |
135 | { | |
136 | std::atexit(&close_user_namespace); | |
137 | } | |
138 | else | |
139 | { | |
140 | // Another thread must have opened the namespace | |
141 | ClosePrivateNamespace(h, 0); | |
142 | h = expected; | |
143 | } | |
144 | } | |
145 | } | |
146 | ||
147 | return !!h; | |
148 | } | |
149 | ||
150 | #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 | |
151 | ||
152 | //! Returns a prefix string for a shared resource according to the scope | |
153 | std::string get_scope_prefix(object_name::scope ns) | |
154 | { | |
155 | std::string prefix; | |
156 | switch (ns) | |
157 | { | |
158 | case object_name::process_group: | |
159 | { | |
160 | // For now consider all processes as members of the common process group. It may change if there is found | |
161 | // a way to get a process group id (i.e. id of the closest parent process that was created with the CREATE_NEW_PROCESS_GROUP flag). | |
162 | prefix = "Local\\boost.log.process_group"; | |
163 | } | |
164 | break; | |
165 | ||
166 | case object_name::session: | |
167 | { | |
168 | prefix = "Local\\boost.log.session"; | |
169 | } | |
170 | break; | |
171 | ||
172 | case object_name::user: | |
173 | { | |
174 | #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 | |
175 | if (init_user_namespace()) | |
176 | { | |
177 | prefix = "User\\boost.log.user"; | |
178 | } | |
179 | else | |
180 | #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 | |
181 | { | |
182 | wchar_t buf[UNLEN + 1u]; | |
183 | ULONG len = sizeof(buf) / sizeof(*buf); | |
184 | if (BOOST_UNLIKELY(!GetUserNameExW(NameSamCompatible, buf, &len))) | |
185 | { | |
186 | const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError(); | |
187 | BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to obtain the current user name", (err)); | |
188 | } | |
189 | ||
190 | std::replace(buf, buf + len, L'\\', L'.'); | |
191 | ||
192 | prefix = "Local\\boost.log.user." + boost::log::aux::utf16_to_utf8(buf); | |
193 | } | |
194 | } | |
195 | break; | |
196 | ||
197 | default: | |
198 | prefix = "Global\\boost.log.global"; | |
199 | break; | |
200 | } | |
201 | ||
202 | prefix.push_back('.'); | |
203 | ||
204 | return BOOST_LOG_NRVO_RESULT(prefix); | |
205 | } | |
206 | ||
207 | } // namespace | |
208 | ||
209 | //! Constructor from the object name | |
210 | BOOST_LOG_API object_name::object_name(scope ns, const char* str) : | |
211 | m_name(get_scope_prefix(ns) + str) | |
212 | { | |
213 | } | |
214 | ||
215 | //! Constructor from the object name | |
216 | BOOST_LOG_API object_name::object_name(scope ns, std::string const& str) : | |
217 | m_name(get_scope_prefix(ns) + str) | |
218 | { | |
219 | } | |
220 | ||
221 | } // namespace ipc | |
222 | ||
223 | BOOST_LOG_CLOSE_NAMESPACE // namespace log | |
224 | ||
225 | } // namespace boost | |
226 | ||
227 | #include <boost/log/detail/footer.hpp> |