MySQL 9.1.0
Source Code Documentation
access_rights.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2021, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_ACCESS_RIGHTS_INCLUDED
27#define MYSQL_HARNESS_ACCESS_RIGHTS_INCLUDED
28
29#include "harness_export.h"
30
31#ifdef _WIN32
32#include <aclapi.h>
33#else
34#include <sys/stat.h> // stat
35#include <sys/types.h>
36#include <unistd.h>
37#endif
38
39#include <optional>
40#include <system_error>
41#include <utility> // exchange
42#include <vector>
43
45
46namespace mysql_harness {
47
48#ifndef _WIN32
49
50namespace posix::access_rights {
51
53
54/**
55 * denies permissions.
56 */
57template <int Mask>
59 public:
60 static constexpr const mode_t kMask = Mask;
61 static constexpr const mode_t kFullAccessMask = (S_IRWXU | S_IRWXG | S_IRWXO);
62
63 // Mask MUST not have flags output of FullAccessMask
64 static_assert(!(kMask & ~kFullAccessMask));
65
67 const security_descriptor_type &perms) {
68 if ((perms & kMask) != 0) {
69 return stdx::unexpected(make_error_code(std::errc::permission_denied));
70 }
71
72 return {};
73 }
74};
75
76/**
77 * allows permissions.
78 */
79template <int Mask>
81 public:
82 static constexpr const mode_t kMask = Mask;
83 static constexpr const mode_t kFullAccessMask = (S_IRWXU | S_IRWXG | S_IRWXO);
84
86 const security_descriptor_type &perms) {
87 if ((perms & kFullAccessMask) != kMask) {
88 return stdx::unexpected(make_error_code(std::errc::permission_denied));
89 }
90
91 return {};
92 }
93};
94
95} // namespace posix::access_rights
96#endif
97
98#ifdef _WIN32
99namespace win32::access_rights {
100
101class LocalDeleter {
102 public:
103 void operator()(void *ptr) { LocalFree(ptr); }
104};
105
106template <class T>
107using LocalAllocated = std::unique_ptr<T, LocalDeleter>;
108
109/**
110 * a smart-pointer for types whose size is discovered at runtime.
111 *
112 * used to wrap APIs like the SECURITY_DESCRIPTOR
113 * on windows which has variable size and explicit no allocation
114 * and no free function.
115 *
116 * It is up to the caller to:
117 *
118 * - ask for the size of the data
119 * - allocate and free
120 *
121 * Uses LocalFree() to free its owned memory which makes it suitable
122 * win32 APIs which explicitly "must be freed with LocalFree()".
123 */
124template <class T>
125class Allocated {
126 public:
127 using allocated_type = LocalAllocated<T>;
128 using pointer = typename allocated_type::pointer;
129 using element_type = typename allocated_type::element_type;
130
131 /**
132 * allocate memory.
133 *
134 * @param size size to allocate.
135 */
136 explicit Allocated(size_t size)
137 : allocated_{reinterpret_cast<pointer>(LocalAlloc(LPTR, size))} {}
138
139 /**
140 * take ownership of p.
141 *
142 * p MUST be allocated by LocalAlloc()
143 */
144 Allocated(pointer p) : allocated_{p} {}
145
146 pointer get() const noexcept { return allocated_.get(); }
147
148 pointer operator->() const { return allocated_.get(); }
149
150 void reset(pointer ptr) { allocated_.reset(ptr); }
151
152 private:
153 allocated_type allocated_;
154};
155
156/**
157 * a Allocated which remembers its size().
158 */
159template <class T>
160class SizedAllocated : public Allocated<T> {
161 public:
162 /**
163 * allocate memory.
164 *
165 * @param size size to allocate.
166 */
167 SizedAllocated(size_t size) : Allocated<T>{size}, size_{size} {}
168
169 [[nodiscard]] size_t size() const noexcept { return size_; }
170
171 private:
172 size_t size_;
173};
174
175using security_descriptor_type = Allocated<SECURITY_DESCRIPTOR>;
176
177/**
178 * a SID structure of a "well-known-sid".
179 */
180stdx::expected<Allocated<SID>, std::error_code> HARNESS_EXPORT
181create_well_known_sid(WELL_KNOWN_SID_TYPE well_known_sid);
182
183/**
184 * get current users SID.
185 */
186stdx::expected<Allocated<SID>, std::error_code> HARNESS_EXPORT
187current_user_sid();
188
189/**
190 * Security Identifier.
191 */
192class HARNESS_EXPORT Sid {
193 public:
194 /**
195 * wrap a native SID pointer.
196 */
197 Sid(SID *sid) : sid_{std::move(sid)} {}
198
199 BYTE revision() const { return sid_->Revision; }
200 BYTE sub_authority_count() const { return sid_->SubAuthorityCount; }
201 SID_IDENTIFIER_AUTHORITY identifier_authority() const {
202 return sid_->IdentifierAuthority;
203 }
204
205 std::string to_string() const;
206
207 SID *native() { return sid_; }
208
209 friend bool operator==(const Sid &, const Sid &);
210
211 private:
212 SID *sid_;
213};
214
215inline bool operator==(const Sid &a, const Sid &b) {
216 return EqualSid(a.sid_, b.sid_);
217}
218
219/**
220 * Access Control Entry.
221 *
222 * header of all ACE structures.
223 */
224class HARNESS_EXPORT Ace {
225 public:
226 Ace(ACE_HEADER *ace) : ace_{std::move(ace)} {}
227
228 BYTE type() const { return ace_->AceType; }
229 BYTE flags() const { return ace_->AceFlags; }
230 WORD size() const { return ace_->AceSize; }
231
232 void *data() const { return ace_; }
233
234 std::string to_string() const;
235
236 private:
237 ACE_HEADER *ace_;
238};
239
240/**
241 * Access Control List.
242 */
243class HARNESS_EXPORT Acl {
244 public:
245 explicit Acl(ACL *acl) : acl_{std::move(acl)} {}
246
247 class HARNESS_EXPORT iterator {
248 public:
249 using value_type = Ace;
250 using reference = value_type &;
251
252 iterator(ACL *acl, size_t ndx) : acl_{acl}, ndx_{ndx} {}
253
254 reference operator*();
255 iterator &operator++();
256 bool operator!=(const iterator &other) const;
257
258 private:
259 ACL *acl_;
260 size_t ndx_;
261
262 value_type ace_{nullptr};
263 };
264
265 iterator begin() const { return {acl_, 0}; }
266 iterator end() const { return {acl_, size()}; }
267
268 size_t size() const;
269
270 std::string to_string() const;
271
272 private:
273 ACL *acl_;
274};
275
276/**
277 * Allowed Access ACE (Access Control Entry).
278 */
279class HARNESS_EXPORT AccessAllowedAce {
280 public:
281 explicit AccessAllowedAce(ACCESS_ALLOWED_ACE *ace) : ace_{ace} {}
282
283 ACCESS_MASK mask() const { return ace_->Mask; }
284 Sid sid() const { return reinterpret_cast<SID *>(&ace_->SidStart); }
285
286 std::string to_string() const;
287
288 private:
289 ACCESS_ALLOWED_ACE *ace_;
290};
291
292/**
293 * a optional DACL.
294 *
295 * a optional DACL allows to differentiate between an empty DACL and a no DACL:
296 *
297 * - if no DACL is set, everything is allowed.
298 * - if a DACL is set, but empty, nothing is allowed.
299 */
300using OptionalDacl = std::optional<ACL *>;
301
302/**
303 * Security Descriptor.
304 *
305 * contains a DACL.
306 *
307 * may be in absolute or self-relative form.
308 */
309class HARNESS_EXPORT SecurityDescriptor {
310 public:
311 /**
312 * wrap a native SECURITY_DESCRITOR pointer.
313 *
314 * does NOT take ownership of the SECURITY_DESCRIPTOR.
315 */
316 explicit SecurityDescriptor(SECURITY_DESCRIPTOR *desc) : desc_{desc} {}
317
318 /**
319 * initialize an security descriptor with a revision.
320 *
321 * the descriptor will:
322 *
323 * - have no SACL
324 * - no DACL
325 * - no owner
326 * - no primary group
327 * - all control flags set to false.
328 */
330 DWORD revision = SECURITY_DESCRIPTOR_REVISION);
331
332 /**
333 * set optional ACL
334 */
335 stdx::expected<void, std::error_code> dacl(const OptionalDacl &dacl,
336 bool dacl_defaulted);
337
338 /**
339 * get a optional ACL.
340 */
342
343 /**
344 * check if a security descriptor is self-relative.
345 */
346 bool is_self_relative() const {
347 return control().value_or(0) & SE_SELF_RELATIVE;
348 }
349
350 /**
351 * get the control bits of a security descritor.
352 */
354
355 /**
356 * transform a security descriptor into self-relative form.
357 */
359 make_self_relative();
360
361 /**
362 * get string representation.
363 */
364 std::string to_string() const;
365
366 private:
367 SECURITY_DESCRIPTOR *desc_;
368};
369
370class HARNESS_EXPORT AclBuilder {
371 public:
372 struct WellKnownSid {
373 WELL_KNOWN_SID_TYPE sid;
374 };
375
376 /**
377 * identify a current-user-lookup.
378 */
379 struct CurrentUser {};
380
381 /**
382 * grant additional rights to a trustee identified by a SID.
383 *
384 * when applied will combine the specified rights with the existing allowed
385 * or denied rights of the trustee.
386 *
387 * @param sid SID of the trustee
388 * @param rights rights to grant.
389 */
390 static EXPLICIT_ACCESSW ace_grant_access(SID *sid, DWORD rights);
391
392 /**
393 * set rights of a trustee identified by a SID.
394 *
395 * when applied will set the specified rights of the trustee.
396 *
397 * @param sid SID of the trustee
398 * @param rights rights to grant.
399 */
400 static EXPLICIT_ACCESSW ace_set_access(SID *sid, DWORD rights);
401
402 /**
403 * revoke access of a trustee identified by a SID.
404 *
405 * when applied will revoke the all rights of the trustee.
406 *
407 * @param sid SID of the trustee
408 */
409 static EXPLICIT_ACCESSW ace_revoke_access(SID *sid);
410
411 /**
412 * create a AclBuilder from a empty security descriptor.
413 */
414 AclBuilder();
415
416 /**
417 * create a AclBuilder from an existing security descritor.
418 */
419 explicit AclBuilder(security_descriptor_type old_desc);
420
421 /**
422 * grant additional access rights to the current user.
423 */
424 AclBuilder &grant(CurrentUser, DWORD rights);
425
426 /**
427 * grant additional access rights to a well-known-sid.
428 */
429 AclBuilder &grant(const WellKnownSid &owner, DWORD rights);
430
431 AclBuilder &grant(Allocated<SID> sid, DWORD rights);
432
433 AclBuilder &set(CurrentUser, DWORD rights);
434
435 AclBuilder &set(const WellKnownSid &owner, DWORD rights);
436
437 AclBuilder &set(Allocated<SID> sid, DWORD rights);
438
439 AclBuilder &revoke(CurrentUser);
440
441 AclBuilder &revoke(const WellKnownSid &owner);
442
443 AclBuilder &revoke(Allocated<SID> sid);
444
446
447 private:
448 std::vector<Allocated<SID>> owned_sids_;
449
450 std::error_code ec_{};
451 std::vector<EXPLICIT_ACCESSW> perms_;
452 mysql_harness::win32::access_rights::OptionalDacl dacl_;
453 // Allocated<SECURITY_DESCRIPTOR>
454 security_descriptor_type old_desc_;
455};
456
457class HARNESS_EXPORT AllowUserReadWritableVerifier {
458 public:
460 const security_descriptor_type &perms);
461};
462
463class HARNESS_EXPORT DenyOtherReadWritableVerifier {
464 public:
466 const security_descriptor_type &perms);
467};
468
469} // namespace win32::access_rights
470#endif
471
472#ifdef _WIN32
474#else
476#endif
477
478/**
479 * fail access_rights_verify() if others can read or write or execute.
480 */
482#ifdef _WIN32
484#else
486#endif
487
488/**
489 * fail access_rights_verify() if someone else then the owner of the file can
490 * read or write.
491 */
493#ifdef _WIN32
495#else
497#endif
498
499/**
500 * get a access rights of file.
501 *
502 * @param file_name of a file.
503 */
505access_rights_get(const std::string &file_name) noexcept;
506
507/**
508 * check if a security descriptor satisfies a verifier.
509 */
510template <class Func>
512 const security_descriptor_type &rights, Func &&func) {
513 return func(rights);
514}
515
516/**
517 * set access rights of a file.
518 */
520 const std::string &file_name, const security_descriptor_type &sec_desc);
521
522} // namespace mysql_harness
523#endif
Sid class.
Definition: common.h:219
allows permissions.
Definition: access_rights.h:80
stdx::expected< void, std::error_code > operator()(const security_descriptor_type &perms)
Definition: access_rights.h:85
static constexpr const mode_t kFullAccessMask
Definition: access_rights.h:83
static constexpr const mode_t kMask
Definition: access_rights.h:82
denies permissions.
Definition: access_rights.h:58
static constexpr const mode_t kMask
Definition: access_rights.h:60
stdx::expected< void, std::error_code > operator()(const security_descriptor_type &perms)
Definition: access_rights.h:66
static constexpr const mode_t kFullAccessMask
Definition: access_rights.h:61
Definition: expected.h:286
const char * p
Definition: ctype-mb.cc:1225
static int flags[50]
Definition: hp_test1.cc:40
static mi_bit_type mask[]
Definition: mi_packrec.cc:141
bool operator!=(const my_thread_handle &a, const my_thread_handle &b)
Definition: my_thread.h:158
bool operator==(const my_thread_handle &a, const my_thread_handle &b)
Definition: my_thread.h:151
uint16_t value_type
Definition: vt100.h:184
std::string HARNESS_EXPORT reset()
get 'reset attributes' ESC sequence.
Definition: vt100.cc:37
std::string file_name(Log_file_id file_id)
Provides name of the log file with the given file id, e.g.
Definition: log0pre_8_0_30.cc:94
MYSQL_STRINGS_EXPORT void initialize(const char *charset_dir=nullptr, MY_CHARSET_LOADER *loader=nullptr)
Initialize character set/collation library.
Definition: collations.cc:98
static mysql_service_status_t get(THD **thd) noexcept
Definition: mysql_current_thread_reader_all_empty.cc:31
mode_t security_descriptor_type
Definition: access_rights.h:52
Definition: common.h:42
std::string HARNESS_EXPORT to_string(const ShutdownPending::Reason &reason)
Definition: process_state_component.cc:60
std::error_code make_error_code(DynamicLoaderErrc ec)
make error_code from a DynamicLoaderErrc.
Definition: dynamic_loader.cc:79
HARNESS_EXPORT stdx::expected< void, std::error_code > access_rights_set(const std::string &file_name, const security_descriptor_type &sec_desc)
set access rights of a file.
Definition: access_rights.cc:762
posix::access_rights::DenyPermissionVerifier<(S_IRWXO)> DenyOtherReadWritableVerifier
fail access_rights_verify() if others can read or write or execute.
Definition: access_rights.h:485
posix::access_rights::security_descriptor_type security_descriptor_type
Definition: access_rights.h:475
posix::access_rights::AllowPermissionVerifier<(S_IRUSR|S_IWUSR)> AllowUserReadWritableVerifier
fail access_rights_verify() if someone else then the owner of the file can read or write.
Definition: access_rights.h:496
stdx::expected< void, std::error_code > access_rights_verify(const security_descriptor_type &rights, Func &&func)
check if a security descriptor satisfies a verifier.
Definition: access_rights.h:511
HARNESS_EXPORT stdx::expected< security_descriptor_type, std::error_code > access_rights_get(const std::string &file_name) noexcept
get a access rights of file.
Definition: access_rights.cc:747
const char * begin(const char *const c)
Definition: base64.h:44
size_t size(const char *const c)
Definition: base64.h:46
Cursor end()
A past-the-end Cursor.
Definition: rules_table_service.cc:192
Definition: gcs_xcom_synode.h:64
unexpected(E) -> unexpected< E >
std::set< Key, Compare, ut::allocator< Key > > set
Specialization of set which uses ut_allocator.
Definition: ut0new.h:2884
required string type
Definition: replication_group_member_actions.proto:34
Ssl_acceptor_context_property_type & operator++(Ssl_acceptor_context_property_type &property_type)
Increment operator for Ssl_acceptor_context_type Used by iterator.
Definition: ssl_acceptor_context_data.cc:273