Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #pragma once
20 :
21 : #include <access/AccessConfig.h>
22 :
23 : #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
24 : #include "AccessRestrictionProvider.h"
25 : #endif
26 :
27 : #include "AuxiliaryType.h"
28 : #include "Privilege.h"
29 : #include "RequestPath.h"
30 : #include "SubjectDescriptor.h"
31 :
32 : #include <lib/core/CHIPCore.h>
33 : #include <lib/core/Global.h>
34 : #include <lib/support/CodeUtils.h>
35 :
36 : // Dump function for use during development only (0 for disabled, non-zero for enabled).
37 : #define CHIP_ACCESS_CONTROL_DUMP_ENABLED 0
38 :
39 : namespace chip {
40 : namespace Access {
41 :
42 : class AccessControl
43 : {
44 : public:
45 : /**
46 : * Used by access control to determine if a device type resolves to an endpoint.
47 : */
48 : struct DeviceTypeResolver
49 : {
50 : public:
51 315 : virtual ~DeviceTypeResolver() = default;
52 :
53 : virtual bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) = 0;
54 : };
55 :
56 : /**
57 : * Handle to an entry in the access control list.
58 : *
59 : * Must be prepared (`AccessControl::PrepareEntry`) or read (`AccessControl::ReadEntry`) before first use.
60 : */
61 : class Entry
62 : {
63 : public:
64 : struct Target
65 : {
66 : using Flags = unsigned;
67 : static constexpr Flags kCluster = 1 << 0;
68 : static constexpr Flags kEndpoint = 1 << 1;
69 : static constexpr Flags kDeviceType = 1 << 2;
70 : Flags flags = 0;
71 : ClusterId cluster;
72 : EndpointId endpoint;
73 : DeviceTypeId deviceType;
74 : };
75 :
76 : class Delegate
77 : {
78 : public:
79 8 : Delegate() = default;
80 :
81 : Delegate(const Delegate &) = delete;
82 : Delegate & operator=(const Delegate &) = delete;
83 :
84 173 : virtual ~Delegate() = default;
85 :
86 292 : virtual void Release() {}
87 :
88 : // Simple getters
89 0 : virtual CHIP_ERROR GetAuthMode(AuthMode & authMode) const { return CHIP_ERROR_NOT_IMPLEMENTED; }
90 0 : virtual CHIP_ERROR GetFabricIndex(FabricIndex & fabricIndex) const { return CHIP_ERROR_NOT_IMPLEMENTED; }
91 0 : virtual CHIP_ERROR GetPrivilege(Privilege & privilege) const { return CHIP_ERROR_NOT_IMPLEMENTED; }
92 1419 : virtual CHIP_ERROR GetAuxiliaryType(AuxiliaryType & auxiliaryType) const { return CHIP_ERROR_NOT_IMPLEMENTED; }
93 :
94 : // Simple setters
95 0 : virtual CHIP_ERROR SetAuthMode(AuthMode authMode) { return CHIP_ERROR_NOT_IMPLEMENTED; }
96 0 : virtual CHIP_ERROR SetFabricIndex(FabricIndex fabricIndex) { return CHIP_ERROR_NOT_IMPLEMENTED; }
97 0 : virtual CHIP_ERROR SetPrivilege(Privilege privilege) { return CHIP_ERROR_NOT_IMPLEMENTED; }
98 0 : virtual CHIP_ERROR SetAuxiliaryType(AuxiliaryType auxiliaryType) { return CHIP_ERROR_NOT_IMPLEMENTED; }
99 :
100 : // Subjects
101 0 : virtual CHIP_ERROR GetSubjectCount(size_t & count) const { return CHIP_ERROR_NOT_IMPLEMENTED; }
102 0 : virtual CHIP_ERROR GetSubject(size_t index, NodeId & subject) const { return CHIP_ERROR_NOT_IMPLEMENTED; }
103 0 : virtual CHIP_ERROR SetSubject(size_t index, NodeId subject) { return CHIP_ERROR_NOT_IMPLEMENTED; }
104 0 : virtual CHIP_ERROR AddSubject(size_t * index, NodeId subject) { return CHIP_ERROR_NOT_IMPLEMENTED; }
105 0 : virtual CHIP_ERROR RemoveSubject(size_t index) { return CHIP_ERROR_NOT_IMPLEMENTED; }
106 :
107 : // Targets
108 0 : virtual CHIP_ERROR GetTargetCount(size_t & count) const { return CHIP_ERROR_NOT_IMPLEMENTED; }
109 0 : virtual CHIP_ERROR GetTarget(size_t index, Target & target) const { return CHIP_ERROR_NOT_IMPLEMENTED; }
110 0 : virtual CHIP_ERROR SetTarget(size_t index, const Target & target) { return CHIP_ERROR_NOT_IMPLEMENTED; }
111 0 : virtual CHIP_ERROR AddTarget(size_t * index, const Target & target) { return CHIP_ERROR_NOT_IMPLEMENTED; }
112 0 : virtual CHIP_ERROR RemoveTarget(size_t index) { return CHIP_ERROR_NOT_IMPLEMENTED; }
113 : };
114 :
115 292 : Entry() = default;
116 :
117 : Entry(Entry && other) : mDelegate(other.mDelegate) { other.mDelegate = &mDefaultDelegate.get(); }
118 :
119 0 : Entry & operator=(Entry && other)
120 : {
121 0 : if (this != &other)
122 : {
123 0 : mDelegate->Release();
124 0 : mDelegate = other.mDelegate;
125 0 : other.mDelegate = &mDefaultDelegate.get();
126 : }
127 0 : return *this;
128 : }
129 :
130 : Entry(const Entry &) = delete;
131 : Entry & operator=(const Entry &) = delete;
132 :
133 292 : ~Entry() { mDelegate->Release(); }
134 :
135 : // Simple getters
136 42998 : CHIP_ERROR GetAuthMode(AuthMode & authMode) const { return mDelegate->GetAuthMode(authMode); }
137 42815 : CHIP_ERROR GetFabricIndex(FabricIndex & fabricIndex) const { return mDelegate->GetFabricIndex(fabricIndex); }
138 42934 : CHIP_ERROR GetPrivilege(Privilege & privilege) const { return mDelegate->GetPrivilege(privilege); }
139 42367 : CHIP_ERROR GetAuxiliaryType(AuxiliaryType & auxiliaryType) const { return mDelegate->GetAuxiliaryType(auxiliaryType); }
140 :
141 : // Simple setters
142 664 : CHIP_ERROR SetAuthMode(AuthMode authMode) { return mDelegate->SetAuthMode(authMode); }
143 656 : CHIP_ERROR SetFabricIndex(FabricIndex fabricIndex) { return mDelegate->SetFabricIndex(fabricIndex); }
144 632 : CHIP_ERROR SetPrivilege(Privilege privilege) { return mDelegate->SetPrivilege(privilege); }
145 0 : CHIP_ERROR SetAuxiliaryType(AuxiliaryType auxiliaryType) { return mDelegate->SetAuxiliaryType(auxiliaryType); }
146 :
147 : /**
148 : * Gets the number of subjects.
149 : *
150 : * @param [out] count The number of subjects.
151 : */
152 42941 : CHIP_ERROR GetSubjectCount(size_t & count) const { return mDelegate->GetSubjectCount(count); }
153 :
154 : /**
155 : * Gets the specified subject.
156 : *
157 : * @param [in] index The index of the subject to get.
158 : * @param [out] subject The subject into which to get.
159 : */
160 42486 : CHIP_ERROR GetSubject(size_t index, NodeId & subject) const { return mDelegate->GetSubject(index, subject); }
161 :
162 : /**
163 : * Sets the specified subject.
164 : *
165 : * @param [in] index The index of the subject to set.
166 : * @param [in] subject The subject from which to set.
167 : */
168 441 : CHIP_ERROR SetSubject(size_t index, NodeId subject) { return mDelegate->SetSubject(index, subject); }
169 :
170 : /**
171 : * Adds the specified subject.
172 : *
173 : * @param [out] index The index of the added subject, if not null.
174 : * @param [in] subject The subject to add.
175 : */
176 654 : CHIP_ERROR AddSubject(size_t * index, NodeId subject) { return mDelegate->AddSubject(index, subject); }
177 :
178 : /**
179 : * Removes the specified subject.
180 : *
181 : * @param [in] index The index of the subject to delete.
182 : */
183 3 : CHIP_ERROR RemoveSubject(size_t index) { return mDelegate->RemoveSubject(index); }
184 :
185 : /**
186 : * Gets the number of targets.
187 : *
188 : * @param [out] count The number of targets.
189 : */
190 42879 : CHIP_ERROR GetTargetCount(size_t & count) const { return mDelegate->GetTargetCount(count); }
191 :
192 : /**
193 : * Gets the specified target.
194 : *
195 : * @param [in] index The index of the target to get.
196 : * @param [out] target The target into which to get.
197 : */
198 41805 : CHIP_ERROR GetTarget(size_t index, Target & target) const { return mDelegate->GetTarget(index, target); }
199 :
200 : /**
201 : * Sets the specified target.
202 : *
203 : * @param [in] index The index of the target to set.
204 : * @param [in] target The target from which to set.
205 : */
206 20418 : CHIP_ERROR SetTarget(size_t index, const Target & target) { return mDelegate->SetTarget(index, target); }
207 :
208 : /**
209 : * Adds the specified target.
210 : *
211 : * @param [out] index The index of the added target, if not null.
212 : * @param [in] target The target to add.
213 : */
214 531 : CHIP_ERROR AddTarget(size_t * index, const Target & target) { return mDelegate->AddTarget(index, target); }
215 :
216 : /**
217 : * Removes the specified target.
218 : *
219 : * @param [in] index The index of the target to delete.
220 : */
221 1 : CHIP_ERROR RemoveTarget(size_t index) { return mDelegate->RemoveTarget(index); }
222 :
223 0 : bool HasDefaultDelegate() const { return mDelegate == &mDefaultDelegate.get(); }
224 :
225 1419 : const Delegate & GetDelegate() const { return *mDelegate; }
226 :
227 1254 : Delegate & GetDelegate() { return *mDelegate; }
228 :
229 1265 : void SetDelegate(Delegate & delegate)
230 : {
231 1265 : mDelegate->Release();
232 1265 : mDelegate = &delegate;
233 1265 : }
234 :
235 0 : void ResetDelegate()
236 : {
237 0 : mDelegate->Release();
238 0 : mDelegate = &mDefaultDelegate.get();
239 0 : }
240 :
241 : /**
242 : * Validate whether an ACL Entry is valid and complies with all defined constraints.
243 : *
244 : * @retval true if all the fields within the Entry are valid and compliant.
245 : */
246 : bool IsValid() const;
247 :
248 : private:
249 : static Global<Delegate> mDefaultDelegate;
250 : Delegate * mDelegate = &mDefaultDelegate.get();
251 : };
252 :
253 : /**
254 : * Handle to an entry iterator in the access control list.
255 : *
256 : * Must be initialized (`AccessControl::Entries`) before first use.
257 : */
258 : class EntryIterator
259 : {
260 : public:
261 : class Delegate
262 : {
263 : public:
264 7 : Delegate() = default;
265 :
266 : Delegate(const Delegate &) = delete;
267 : Delegate & operator=(const Delegate &) = delete;
268 :
269 165 : virtual ~Delegate() = default;
270 :
271 70 : virtual void Release() {}
272 :
273 0 : virtual CHIP_ERROR Next(Entry & entry) { return CHIP_ERROR_SENTINEL; }
274 : };
275 :
276 70 : EntryIterator() = default;
277 :
278 : EntryIterator(const EntryIterator &) = delete;
279 : EntryIterator & operator=(const EntryIterator &) = delete;
280 :
281 70 : ~EntryIterator() { mDelegate->Release(); }
282 :
283 266 : CHIP_ERROR Next(Entry & entry) { return mDelegate->Next(entry); }
284 :
285 : const Delegate & GetDelegate() const { return *mDelegate; }
286 :
287 67 : Delegate & GetDelegate() { return *mDelegate; }
288 :
289 71 : void SetDelegate(Delegate & delegate)
290 : {
291 71 : mDelegate->Release();
292 71 : mDelegate = &delegate;
293 71 : }
294 :
295 : void ResetDelegate()
296 : {
297 : mDelegate->Release();
298 : mDelegate = &mDefaultDelegate.get();
299 : }
300 :
301 : private:
302 : static Global<Delegate> mDefaultDelegate;
303 : Delegate * mDelegate = &mDefaultDelegate.get();
304 : };
305 :
306 : /**
307 : * Used by access control to notify of changes in access control list.
308 : */
309 : class EntryListener
310 : {
311 : public:
312 : enum class ChangeType
313 : {
314 : kAdded = 1,
315 : kRemoved = 2,
316 : kUpdated = 3
317 : };
318 :
319 6 : virtual ~EntryListener() = default;
320 :
321 : /**
322 : * Notifies of a change in the access control list.
323 : *
324 : * The fabric is indicated by its own parameter. If available, a subject descriptor will
325 : * have more detail (and its fabric index will match). A best effort is made to provide
326 : * the latest value of the changed entry.
327 : *
328 : * @param [in] subjectDescriptor Optional (if available) subject descriptor for this operation.
329 : * @param [in] fabric Index of fabric in which entry has changed.
330 : * @param [in] index Index of entry to which has changed (relative to fabric).
331 : * @param [in] entry Optional (best effort) latest value of entry which has changed.
332 : * @param [in] changeType Type of change.
333 : */
334 : virtual void OnEntryChanged(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index,
335 : const Entry * entry, ChangeType changeType) = 0;
336 :
337 : private:
338 : EntryListener * mNext = nullptr;
339 :
340 : friend class AccessControl;
341 : };
342 :
343 : class Delegate
344 : {
345 : public:
346 145 : Delegate() = default;
347 :
348 : Delegate(const Delegate &) = delete;
349 : Delegate & operator=(const Delegate &) = delete;
350 :
351 185 : virtual ~Delegate() = default;
352 :
353 5 : virtual void Release() {}
354 :
355 167 : virtual CHIP_ERROR Init() { return CHIP_NO_ERROR; }
356 168 : virtual void Finish() {}
357 :
358 : // Capabilities
359 1 : virtual CHIP_ERROR GetMaxEntriesPerFabric(size_t & value) const
360 : {
361 1 : value = 0;
362 1 : return CHIP_NO_ERROR;
363 : }
364 :
365 1 : virtual CHIP_ERROR GetMaxSubjectsPerEntry(size_t & value) const
366 : {
367 1 : value = 0;
368 1 : return CHIP_NO_ERROR;
369 : }
370 :
371 1 : virtual CHIP_ERROR GetMaxTargetsPerEntry(size_t & value) const
372 : {
373 1 : value = 0;
374 1 : return CHIP_NO_ERROR;
375 : }
376 :
377 1 : virtual CHIP_ERROR GetMaxEntryCount(size_t & value) const
378 : {
379 1 : value = 0;
380 1 : return CHIP_NO_ERROR;
381 : }
382 :
383 : // Actualities
384 1 : virtual CHIP_ERROR GetEntryCount(FabricIndex fabric, size_t & value) const
385 : {
386 1 : value = 0;
387 1 : return CHIP_NO_ERROR;
388 : }
389 :
390 1 : virtual CHIP_ERROR GetEntryCount(size_t & value) const
391 : {
392 1 : value = 0;
393 1 : return CHIP_NO_ERROR;
394 : }
395 :
396 : // Preparation
397 1 : virtual CHIP_ERROR PrepareEntry(Entry & entry) { return CHIP_NO_ERROR; }
398 :
399 : // CRUD
400 1 : virtual CHIP_ERROR CreateEntry(size_t * index, const Entry & entry, FabricIndex * fabricIndex) { return CHIP_NO_ERROR; }
401 1 : virtual CHIP_ERROR ReadEntry(size_t index, Entry & entry, const FabricIndex * fabricIndex) const { return CHIP_NO_ERROR; }
402 1 : virtual CHIP_ERROR UpdateEntry(size_t index, const Entry & entry, const FabricIndex * fabricIndex) { return CHIP_NO_ERROR; }
403 1 : virtual CHIP_ERROR DeleteEntry(size_t index, const FabricIndex * fabricIndex) { return CHIP_NO_ERROR; }
404 :
405 : // Iteration
406 1 : virtual CHIP_ERROR Entries(EntryIterator & iterator, const FabricIndex * fabricIndex) const { return CHIP_NO_ERROR; }
407 :
408 0 : virtual CHIP_ERROR AuxiliaryEntries(EntryIterator & iterator, const FabricIndex * fabricIndex) const
409 : {
410 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
411 : }
412 :
413 : // Check
414 : // Return CHIP_NO_ERROR if allowed, CHIP_ERROR_ACCESS_DENIED if denied,
415 : // CHIP_ERROR_NOT_IMPLEMENTED to use the default check algorithm (against entries),
416 : // or any other CHIP_ERROR if another error occurred.
417 1 : virtual CHIP_ERROR Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
418 : Privilege requestPrivilege)
419 : {
420 1 : return CHIP_ERROR_ACCESS_DENIED;
421 : }
422 : };
423 :
424 149 : AccessControl() = default;
425 :
426 : AccessControl(const AccessControl &) = delete;
427 : AccessControl & operator=(const AccessControl &) = delete;
428 :
429 341 : ~AccessControl()
430 : {
431 341 : if (IsGroupAuxiliaryDelegateRegistered())
432 : {
433 0 : mGroupAuxDelegate->Release();
434 : }
435 :
436 : // Never-initialized AccessControl instances will not have the delegate set.
437 341 : if (IsInitialized())
438 : {
439 0 : mDelegate->Release();
440 : }
441 341 : }
442 :
443 : /**
444 : * Initialize the access control module. Must be called before first use.
445 : *
446 : * @return CHIP_NO_ERROR on success, CHIP_ERROR_INCORRECT_STATE if called more than once,
447 : * CHIP_ERROR_INVALID_ARGUMENT if delegate is null, or other fatal error.
448 : */
449 : CHIP_ERROR Init(AccessControl::Delegate * delegate, DeviceTypeResolver & deviceTypeResolver);
450 :
451 : /**
452 : * Deinitialize the access control module. Must be called when finished.
453 : */
454 : void Finish();
455 :
456 : // Capabilities
457 1 : CHIP_ERROR GetMaxEntriesPerFabric(size_t & value) const
458 : {
459 1 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
460 1 : return mDelegate->GetMaxEntriesPerFabric(value);
461 : }
462 :
463 1 : CHIP_ERROR GetMaxSubjectsPerEntry(size_t & value) const
464 : {
465 1 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
466 1 : return mDelegate->GetMaxSubjectsPerEntry(value);
467 : }
468 :
469 1 : CHIP_ERROR GetMaxTargetsPerEntry(size_t & value) const
470 : {
471 1 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
472 1 : return mDelegate->GetMaxTargetsPerEntry(value);
473 : }
474 :
475 : CHIP_ERROR GetMaxEntryCount(size_t & value) const
476 : {
477 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
478 : return mDelegate->GetMaxEntryCount(value);
479 : }
480 :
481 : // Actualities
482 3 : CHIP_ERROR GetEntryCount(FabricIndex fabric, size_t & value) const
483 : {
484 3 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
485 3 : return mDelegate->GetEntryCount(fabric, value);
486 : }
487 :
488 2 : CHIP_ERROR GetEntryCount(size_t & value) const
489 : {
490 2 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
491 2 : return mDelegate->GetEntryCount(value);
492 : }
493 :
494 : /**
495 : * Prepares an entry.
496 : *
497 : * An entry must be prepared or read (`ReadEntry`) before first use.
498 : *
499 : * @param [in] entry Entry to prepare.
500 : */
501 652 : CHIP_ERROR PrepareEntry(Entry & entry)
502 : {
503 652 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
504 652 : return mDelegate->PrepareEntry(entry);
505 : }
506 :
507 : /**
508 : * Creates an entry in the access control list.
509 : *
510 : * @param [in] subjectDescriptor Optional subject descriptor for this operation.
511 : * @param [in] fabric Index of fabric in which to create entry.
512 : * @param [out] index (If not nullptr) index of created entry (relative to fabric).
513 : * @param [in] entry Entry from which created entry is copied.
514 : */
515 : CHIP_ERROR CreateEntry(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t * index, const Entry & entry);
516 :
517 : /**
518 : * Creates an entry in the access control list.
519 : *
520 : * @param [out] index Entry index of created entry, if not null. May be relative to `fabricIndex`.
521 : * @param [in] entry Entry from which to copy.
522 : * @param [out] fabricIndex Fabric index of created entry, if not null, in which case entry `index` will be relative to fabric.
523 : */
524 21483 : CHIP_ERROR CreateEntry(size_t * index, const Entry & entry, FabricIndex * fabricIndex = nullptr)
525 : {
526 21483 : VerifyOrReturnError(entry.IsValid(), CHIP_ERROR_INVALID_ARGUMENT);
527 1009 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
528 1009 : return mDelegate->CreateEntry(index, entry, fabricIndex);
529 : }
530 :
531 : /**
532 : * Reads an entry in the access control list.
533 : *
534 : * @param [in] fabric Index of fabric in which to read entry.
535 : * @param [in] index Index of entry to read (relative to fabric).
536 : * @param [in] entry Entry into which read entry is copied.
537 : */
538 1 : CHIP_ERROR ReadEntry(FabricIndex fabric, size_t index, Entry & entry) const
539 : {
540 1 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
541 1 : return mDelegate->ReadEntry(index, entry, &fabric);
542 : }
543 :
544 : /**
545 : * Reads an entry from the access control list.
546 : *
547 : * @param [in] index Entry index of entry to read. May be relative to `fabricIndex`.
548 : * @param [out] entry Entry into which to copy.
549 : * @param [in] fabricIndex Fabric to which entry `index` is relative, if not null.
550 : */
551 465 : CHIP_ERROR ReadEntry(size_t index, Entry & entry, const FabricIndex * fabricIndex = nullptr) const
552 : {
553 465 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
554 465 : return mDelegate->ReadEntry(index, entry, fabricIndex);
555 : }
556 :
557 : /**
558 : * Updates an entry in the access control list.
559 : *
560 : * @param [in] subjectDescriptor Optional subject descriptor for this operation.
561 : * @param [in] fabric Index of fabric in which to update entry.
562 : * @param [in] index Index of entry to update (relative to fabric).
563 : * @param [in] entry Entry from which updated entry is copied.
564 : */
565 : CHIP_ERROR UpdateEntry(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index, const Entry & entry);
566 :
567 : /**
568 : * Updates an entry in the access control list.
569 : *
570 : * @param [in] index Entry index of entry to update, if not null. May be relative to `fabricIndex`.
571 : * @param [in] entry Entry from which to copy.
572 : * @param [in] fabricIndex Fabric to which entry `index` is relative, if not null.
573 : */
574 20881 : CHIP_ERROR UpdateEntry(size_t index, const Entry & entry, const FabricIndex * fabricIndex = nullptr)
575 : {
576 20881 : VerifyOrReturnError(entry.IsValid(), CHIP_ERROR_INVALID_ARGUMENT);
577 407 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
578 407 : return mDelegate->UpdateEntry(index, entry, fabricIndex);
579 : }
580 :
581 : /**
582 : * Deletes an entry in the access control list.
583 : *
584 : * @param [in] subjectDescriptor Optional subject descriptor for this operation.
585 : * @param [in] fabric Index of fabric in which to delete entry.
586 : * @param [in] index Index of entry to delete (relative to fabric).
587 : */
588 : CHIP_ERROR DeleteEntry(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index);
589 :
590 : /**
591 : * Deletes an entry from the access control list.
592 : *
593 : * @param [in] index Entry index of entry to delete. May be relative to `fabricIndex`.
594 : * @param [in] fabricIndex Fabric to which entry `index` is relative, if not null.
595 : */
596 21569 : CHIP_ERROR DeleteEntry(size_t index, const FabricIndex * fabricIndex = nullptr)
597 : {
598 21569 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
599 21569 : return mDelegate->DeleteEntry(index, fabricIndex);
600 : }
601 :
602 : /**
603 : * @brief Remove all ACL entries for the given fabricIndex
604 : *
605 : * @param[in] fabricIndex fabric index for which to remove all entries
606 : */
607 2 : CHIP_ERROR DeleteAllEntriesForFabric(FabricIndex fabricIndex)
608 : {
609 2 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
610 :
611 2 : CHIP_ERROR stickyError = CHIP_NO_ERROR;
612 :
613 : // Remove access control entries in reverse order (it could be any order, but reverse order
614 : // will cause less churn in persistent storage).
615 2 : size_t aclCount = 0;
616 4 : if (GetEntryCount(fabricIndex, aclCount) == CHIP_NO_ERROR)
617 : {
618 11 : while (aclCount)
619 : {
620 9 : CHIP_ERROR err = DeleteEntry(nullptr, fabricIndex, --aclCount);
621 18 : stickyError = (stickyError == CHIP_NO_ERROR) ? err : stickyError;
622 : }
623 : }
624 :
625 2 : return stickyError;
626 : }
627 :
628 : /**
629 : * Iterates over entries in the access control list.
630 : *
631 : * @param [in] fabricIndex Fabric over which to iterate entries.
632 : * @param [out] iterator Iterator controlling the iteration.
633 : */
634 0 : CHIP_ERROR Entries(FabricIndex fabricIndex, EntryIterator & iterator) const
635 : {
636 0 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
637 0 : return mDelegate->Entries(iterator, &fabricIndex);
638 : }
639 :
640 : /**
641 : * Iterates over entries in the access control list.
642 : *
643 : * @param [out] iterator Iterator controlling the iteration.
644 : * @param [in] fabricIndex Iteration is confined to fabric, if not null.
645 : */
646 67 : CHIP_ERROR Entries(EntryIterator & iterator, const FabricIndex * fabricIndex = nullptr) const
647 : {
648 67 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
649 67 : return mDelegate->Entries(iterator, fabricIndex);
650 : }
651 :
652 : /**
653 : * Iterates over auxiliary entries for the given fabric.
654 : *
655 : * @param [in] fabricIndex Fabric index for which to iterate auxiliary entries.
656 : * @param [out] iterator Iterator controlling the iteration.
657 : */
658 5 : CHIP_ERROR AuxiliaryEntries(FabricIndex fabricIndex, EntryIterator & iterator) const
659 : {
660 5 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
661 5 : VerifyOrReturnError(IsGroupAuxiliaryDelegateRegistered(), CHIP_ERROR_NOT_IMPLEMENTED);
662 4 : return mGroupAuxDelegate->AuxiliaryEntries(iterator, &fabricIndex);
663 : }
664 :
665 : // Adds a listener to the end of the listener list, if not already in the list.
666 : void AddEntryListener(EntryListener & listener);
667 :
668 : // Removes a listener from the listener list, if in the list.
669 : void RemoveEntryListener(EntryListener & listener);
670 :
671 : /**
672 : * @brief Registers a delegate to handle auxiliary access control entries. There
673 : * can only be 1 group auxiliary access control delegate registered at a time. To
674 : * replace the delegate after one has been set previously, one MUST unregister the
675 : * currently set delegate before calling this registration function.
676 : *
677 : * @param[in] delegate The delegate to register.
678 : *
679 : * @retval #CHIP_ERROR_INVALID_ARGUMENT if the delegate is null.
680 : * @retval #CHIP_ERROR_INCORRECT_STATE if a delegate is already registered.
681 : * @retval #CHIP_NO_ERROR on success.
682 : */
683 6 : CHIP_ERROR RegisterGroupAuxiliaryDelegate(Delegate * delegate)
684 : {
685 6 : VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
686 6 : VerifyOrReturnError(mGroupAuxDelegate == nullptr, CHIP_ERROR_INCORRECT_STATE);
687 5 : mGroupAuxDelegate = delegate;
688 5 : return CHIP_NO_ERROR;
689 : }
690 :
691 854 : bool IsGroupAuxiliaryDelegateRegistered() const { return (mGroupAuxDelegate != nullptr); }
692 :
693 : /**
694 : * @brief Unregisters the delegate handling auxiliary access control entries.
695 : */
696 5 : void UnregisterGroupAuxiliaryDelegate()
697 : {
698 5 : if (IsGroupAuxiliaryDelegateRegistered())
699 : {
700 5 : mGroupAuxDelegate->Release();
701 5 : mGroupAuxDelegate = nullptr;
702 : }
703 5 : }
704 :
705 : #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
706 : // Set an optional AcceessRestriction object for MNGD feature.
707 : void SetAccessRestrictionProvider(AccessRestrictionProvider * accessRestrictionProvider)
708 : {
709 : mAccessRestrictionProvider = accessRestrictionProvider;
710 : }
711 :
712 : AccessRestrictionProvider * GetAccessRestrictionProvider() { return mAccessRestrictionProvider; }
713 : #endif
714 :
715 : /**
716 : * Check whether or not Access Restriction List is supported.
717 : *
718 : * @retval true if Access Restriction List is supported.
719 : */
720 : bool IsAccessRestrictionListSupported() const;
721 :
722 : /**
723 : * Check whether access (by a subject descriptor, to a request path,
724 : * requiring a privilege) should be allowed or denied.
725 : *
726 : * If an AccessRestrictionProvider object is set, it will be checked for additional access restrictions.
727 : *
728 : * @retval #CHIP_ERROR_ACCESS_DENIED if denied.
729 : * @retval other errors should also be treated as denied.
730 : * @retval #CHIP_NO_ERROR if allowed.
731 : */
732 : CHIP_ERROR Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath, Privilege requestPrivilege);
733 :
734 : #if CHIP_ACCESS_CONTROL_DUMP_ENABLED
735 : CHIP_ERROR Dump(const Entry & entry);
736 : #endif
737 :
738 : private:
739 46062 : bool IsInitialized() const { return (mDelegate != nullptr); }
740 :
741 : void NotifyEntryChanged(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index, const Entry * entry,
742 : EntryListener::ChangeType changeType);
743 :
744 : /**
745 : * Check ACL for whether access (by a subject descriptor, to a request path,
746 : * requiring a privilege) should be allowed or denied.
747 : */
748 : CHIP_ERROR CheckACL(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath, Privilege requestPrivilege);
749 :
750 : /**
751 : * Check CommissioningARL or ARL (as appropriate) for whether access (by a
752 : * subject descriptor, to a request path, requiring a privilege) should
753 : * be allowed or denied.
754 : */
755 : CHIP_ERROR CheckARL(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath, Privilege requestPrivilege);
756 :
757 : private:
758 : Delegate * mDelegate = nullptr;
759 :
760 : // This is an access control delegate that is specifically set to handle auxiliary ACL entries
761 : // based on group information. It is part of server init params, and can also be set at runtime using
762 : // RegisterGroupAuxiliaryDelegate(). It is needed for functionality in the groupcast cluster protected by
763 : // the LN feature, and the access control cluster protected by the AUX feature. It is expected that
764 : // this delegate will have an implementation of the AuxiliaryEntries() funciton for reporting these
765 : // entries. It is also expected to implement a Check() function to actually use these entries
766 : // to approve/deny access control.
767 : Delegate * mGroupAuxDelegate = nullptr;
768 :
769 : DeviceTypeResolver * mDeviceTypeResolver = nullptr;
770 :
771 : EntryListener * mEntryListener = nullptr;
772 :
773 : #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
774 : AccessRestrictionProvider * mAccessRestrictionProvider;
775 : #endif
776 : };
777 :
778 : /**
779 : * Get the global instance set by SetAccessControl, or the default.
780 : *
781 : * Calls to this function must be synchronized externally.
782 : */
783 : AccessControl & GetAccessControl();
784 :
785 : /**
786 : * Set the global instance returned by GetAccessControl.
787 : *
788 : * Calls to this function must be synchronized externally.
789 : */
790 : void SetAccessControl(AccessControl & accessControl);
791 :
792 : /**
793 : * Reset the global instance to the default.
794 : *
795 : * Calls to this function must be synchronized externally.
796 : */
797 : void ResetAccessControlToDefault();
798 :
799 : } // namespace Access
800 : } // namespace chip
|