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 : // Included for the default AccessControlDelegate logging enables/disables.
20 : // See `chip_access_control_policy_logging_verbosity` in `src/app/BUILD.gn` for
21 : // the levels available.
22 : #include <app/AppConfig.h>
23 :
24 : #include "AccessControl.h"
25 :
26 : #include <lib/core/Global.h>
27 : #include <lib/support/TypeTraits.h>
28 :
29 : #include <credentials/GroupDataProvider.h>
30 :
31 : namespace chip {
32 : namespace Access {
33 :
34 : using chip::CATValues;
35 : using chip::FabricIndex;
36 : using chip::NodeId;
37 :
38 : namespace {
39 :
40 : Global<AccessControl> defaultAccessControl;
41 : AccessControl * globalAccessControl = nullptr; // lazily defaulted to defaultAccessControl in GetAccessControl
42 :
43 : static_assert(((unsigned(Privilege::kAdminister) & unsigned(Privilege::kManage)) == 0) &&
44 : ((unsigned(Privilege::kAdminister) & unsigned(Privilege::kOperate)) == 0) &&
45 : ((unsigned(Privilege::kAdminister) & unsigned(Privilege::kView)) == 0) &&
46 : ((unsigned(Privilege::kAdminister) & unsigned(Privilege::kProxyView)) == 0) &&
47 : ((unsigned(Privilege::kManage) & unsigned(Privilege::kOperate)) == 0) &&
48 : ((unsigned(Privilege::kManage) & unsigned(Privilege::kView)) == 0) &&
49 : ((unsigned(Privilege::kManage) & unsigned(Privilege::kProxyView)) == 0) &&
50 : ((unsigned(Privilege::kOperate) & unsigned(Privilege::kView)) == 0) &&
51 : ((unsigned(Privilege::kOperate) & unsigned(Privilege::kProxyView)) == 0) &&
52 : ((unsigned(Privilege::kView) & unsigned(Privilege::kProxyView)) == 0),
53 : "Privilege bits must be unique");
54 :
55 128 : bool CheckRequestPrivilegeAgainstEntryPrivilege(Privilege requestPrivilege, Privilege entryPrivilege)
56 : {
57 128 : switch (entryPrivilege)
58 : {
59 11 : case Privilege::kView:
60 11 : return requestPrivilege == Privilege::kView;
61 10 : case Privilege::kProxyView:
62 10 : return requestPrivilege == Privilege::kProxyView || requestPrivilege == Privilege::kView;
63 25 : case Privilege::kOperate:
64 25 : return requestPrivilege == Privilege::kOperate || requestPrivilege == Privilege::kView;
65 35 : case Privilege::kManage:
66 35 : return requestPrivilege == Privilege::kManage || requestPrivilege == Privilege::kOperate ||
67 35 : requestPrivilege == Privilege::kView;
68 47 : case Privilege::kAdminister:
69 38 : return requestPrivilege == Privilege::kAdminister || requestPrivilege == Privilege::kManage ||
70 85 : requestPrivilege == Privilege::kOperate || requestPrivilege == Privilege::kView ||
71 47 : requestPrivilege == Privilege::kProxyView;
72 : }
73 0 : return false;
74 : }
75 :
76 41570 : constexpr bool IsValidCaseNodeId(NodeId aNodeId)
77 : {
78 41570 : if (IsOperationalNodeId(aNodeId))
79 : {
80 41085 : return true;
81 : }
82 :
83 485 : if (IsCASEAuthTag(aNodeId) && (GetCASEAuthTagVersion(CASEAuthTagFromNodeId(aNodeId)) != 0))
84 : {
85 307 : return true;
86 : }
87 :
88 178 : return false;
89 : }
90 :
91 286 : constexpr bool IsValidGroupNodeId(NodeId aNodeId)
92 : {
93 286 : return IsGroupId(aNodeId) && IsValidGroupId(GroupIdFromNodeId(aNodeId));
94 : }
95 :
96 : #if CHIP_PROGRESS_LOGGING && CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
97 :
98 0 : char GetAuthModeStringForLogging(AuthMode authMode)
99 : {
100 0 : switch (authMode)
101 : {
102 0 : case AuthMode::kNone:
103 0 : return 'n';
104 0 : case AuthMode::kInternalDeviceAccess:
105 0 : return 'i';
106 0 : case AuthMode::kPase:
107 0 : return 'p';
108 0 : case AuthMode::kCase:
109 0 : return 'c';
110 0 : case AuthMode::kGroup:
111 0 : return 'g';
112 : }
113 0 : return 'u';
114 : }
115 :
116 : constexpr int kCharsPerCatForLogging = 11; // including final null terminator
117 :
118 0 : char * GetCatStringForLogging(char * buf, size_t size, const CATValues & cats)
119 : {
120 0 : if (size == 0)
121 : {
122 0 : return nullptr;
123 : }
124 0 : char * p = buf;
125 0 : char * const end = buf + size;
126 0 : *p = '\0';
127 : // Format string chars needed:
128 : // 1 for comma (optional)
129 : // 2 for 0x prefix
130 : // 8 for 32-bit hex value
131 : // 1 for null terminator (at end)
132 : static constexpr char fmtWithoutComma[] = "0x%08" PRIX32;
133 : static constexpr char fmtWithComma[] = ",0x%08" PRIX32;
134 0 : constexpr int countWithoutComma = 10;
135 0 : constexpr int countWithComma = countWithoutComma + 1;
136 0 : bool withComma = false;
137 0 : for (auto cat : cats.values)
138 : {
139 0 : if (cat == chip::kUndefinedCAT)
140 : {
141 0 : break;
142 : }
143 0 : snprintf(p, static_cast<size_t>(end - p), withComma ? fmtWithComma : fmtWithoutComma, cat);
144 0 : p += withComma ? countWithComma : countWithoutComma;
145 0 : if (p >= end)
146 : {
147 : // Output was truncated.
148 0 : p = end - ((size < 4) ? size : 4);
149 0 : while (*p)
150 : {
151 : // Indicate truncation if possible.
152 0 : *p++ = '.';
153 : }
154 0 : break;
155 : }
156 0 : withComma = true;
157 : }
158 0 : return buf;
159 : }
160 :
161 0 : char GetPrivilegeStringForLogging(Privilege privilege)
162 : {
163 0 : switch (privilege)
164 : {
165 0 : case Privilege::kView:
166 0 : return 'v';
167 0 : case Privilege::kProxyView:
168 0 : return 'p';
169 0 : case Privilege::kOperate:
170 0 : return 'o';
171 0 : case Privilege::kManage:
172 0 : return 'm';
173 0 : case Privilege::kAdminister:
174 0 : return 'a';
175 : }
176 0 : return 'u';
177 : }
178 :
179 0 : char GetAuxiliaryTypeStringForLogging(AuxiliaryType auxiliaryType)
180 : {
181 0 : switch (auxiliaryType)
182 : {
183 0 : case AuxiliaryType::kSystem:
184 0 : return 's';
185 0 : case AuxiliaryType::kGroupcast:
186 0 : return 'g';
187 0 : default:
188 0 : return 'u';
189 : }
190 : }
191 :
192 0 : char GetRequestTypeStringForLogging(RequestType requestType)
193 : {
194 0 : switch (requestType)
195 : {
196 0 : case RequestType::kAttributeReadRequest:
197 0 : return 'r';
198 0 : case RequestType::kAttributeWriteRequest:
199 0 : return 'w';
200 0 : case RequestType::kCommandInvokeRequest:
201 0 : return 'i';
202 0 : case RequestType::kEventReadRequest:
203 0 : return 'e';
204 0 : default:
205 0 : return '?';
206 : }
207 : }
208 :
209 : #endif // CHIP_PROGRESS_LOGGING && CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
210 :
211 : } // namespace
212 :
213 : Global<AccessControl::Entry::Delegate> AccessControl::Entry::mDefaultDelegate;
214 : Global<AccessControl::EntryIterator::Delegate> AccessControl::EntryIterator::mDefaultDelegate;
215 :
216 496 : CHIP_ERROR AccessControl::Init(AccessControl::Delegate * delegate, DeviceTypeResolver & deviceTypeResolver)
217 : {
218 496 : VerifyOrReturnError(!IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
219 :
220 495 : ChipLogProgress(DataManagement, "AccessControl: initializing");
221 :
222 495 : VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
223 495 : CHIP_ERROR retval = delegate->Init();
224 990 : if (retval == CHIP_NO_ERROR)
225 : {
226 495 : mDelegate = delegate;
227 495 : mDeviceTypeResolver = &deviceTypeResolver;
228 : }
229 :
230 495 : return retval;
231 : }
232 :
233 496 : void AccessControl::Finish()
234 : {
235 496 : VerifyOrReturn(IsInitialized());
236 495 : ChipLogProgress(DataManagement, "AccessControl: finishing");
237 495 : mDelegate->Finish();
238 495 : mDelegate = nullptr;
239 :
240 495 : if (IsGroupAuxiliaryDelegateRegistered())
241 : {
242 1 : mGroupAuxDelegate->Finish();
243 1 : UnregisterGroupAuxiliaryDelegate();
244 : }
245 : }
246 :
247 2 : CHIP_ERROR AccessControl::CreateEntry(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t * index,
248 : const Entry & entry)
249 : {
250 2 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
251 :
252 2 : size_t count = 0;
253 2 : size_t maxCount = 0;
254 2 : ReturnErrorOnFailure(mDelegate->GetEntryCount(fabric, count));
255 2 : ReturnErrorOnFailure(mDelegate->GetMaxEntriesPerFabric(maxCount));
256 :
257 2 : VerifyOrReturnError((count + 1) <= maxCount, CHIP_ERROR_BUFFER_TOO_SMALL);
258 :
259 2 : VerifyOrReturnError(entry.IsValid(), CHIP_ERROR_INVALID_ARGUMENT);
260 :
261 2 : size_t i = 0;
262 2 : ReturnErrorOnFailure(mDelegate->CreateEntry(&i, entry, &fabric));
263 :
264 2 : if (index)
265 : {
266 1 : *index = i;
267 : }
268 :
269 2 : NotifyEntryChanged(subjectDescriptor, fabric, i, &entry, EntryListener::ChangeType::kAdded);
270 2 : return CHIP_NO_ERROR;
271 : }
272 :
273 1 : CHIP_ERROR AccessControl::UpdateEntry(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index,
274 : const Entry & entry)
275 : {
276 1 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
277 1 : VerifyOrReturnError(entry.IsValid(), CHIP_ERROR_INVALID_ARGUMENT);
278 1 : ReturnErrorOnFailure(mDelegate->UpdateEntry(index, entry, &fabric));
279 1 : NotifyEntryChanged(subjectDescriptor, fabric, index, &entry, EntryListener::ChangeType::kUpdated);
280 1 : return CHIP_NO_ERROR;
281 : }
282 :
283 10 : CHIP_ERROR AccessControl::DeleteEntry(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index)
284 : {
285 10 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
286 10 : Entry entry;
287 10 : Entry * p = nullptr;
288 11 : if (mEntryListener != nullptr && ReadEntry(fabric, index, entry) == CHIP_NO_ERROR)
289 : {
290 0 : p = &entry;
291 : }
292 10 : ReturnErrorOnFailure(mDelegate->DeleteEntry(index, &fabric));
293 10 : if (p && p->HasDefaultDelegate())
294 : {
295 : // The entry was read prior to deletion so its latest value could be provided
296 : // to the listener after deletion. If it's been reset to its default delegate,
297 : // that best effort attempt to retain the latest value failed. This is
298 : // regrettable but OK.
299 0 : p = nullptr;
300 : }
301 10 : NotifyEntryChanged(subjectDescriptor, fabric, index, p, EntryListener::ChangeType::kRemoved);
302 10 : return CHIP_NO_ERROR;
303 10 : }
304 :
305 3 : void AccessControl::AddEntryListener(EntryListener & listener)
306 : {
307 3 : if (mEntryListener == nullptr)
308 : {
309 3 : mEntryListener = &listener;
310 3 : listener.mNext = nullptr;
311 3 : return;
312 : }
313 :
314 0 : for (EntryListener * l = mEntryListener; /**/; l = l->mNext)
315 : {
316 0 : if (l == &listener)
317 : {
318 0 : return;
319 : }
320 :
321 0 : if (l->mNext == nullptr)
322 : {
323 0 : l->mNext = &listener;
324 0 : listener.mNext = nullptr;
325 0 : return;
326 : }
327 : }
328 : }
329 :
330 2 : void AccessControl::RemoveEntryListener(EntryListener & listener)
331 : {
332 2 : if (mEntryListener == &listener)
333 : {
334 2 : mEntryListener = listener.mNext;
335 2 : listener.mNext = nullptr;
336 2 : return;
337 : }
338 :
339 0 : for (EntryListener * l = mEntryListener; l != nullptr; l = l->mNext)
340 : {
341 0 : if (l->mNext == &listener)
342 : {
343 0 : l->mNext = listener.mNext;
344 0 : listener.mNext = nullptr;
345 0 : return;
346 : }
347 : }
348 : }
349 :
350 1 : bool AccessControl::IsAccessRestrictionListSupported() const
351 : {
352 : #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
353 : return mAccessRestrictionProvider != nullptr;
354 : #else
355 1 : return false;
356 : #endif
357 : }
358 :
359 20531 : CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
360 : Privilege requestPrivilege)
361 : {
362 20531 : VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
363 20531 : VerifyOrReturnError(IsValidPrivilege(requestPrivilege), CHIP_ERROR_INVALID_ARGUMENT);
364 :
365 20531 : CHIP_ERROR result = CheckACL(subjectDescriptor, requestPath, requestPrivilege);
366 :
367 : #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
368 : if (result == CHIP_NO_ERROR)
369 : {
370 : result = CheckARL(subjectDescriptor, requestPath, requestPrivilege);
371 : }
372 : #endif
373 :
374 20593 : if ((CHIP_NO_ERROR != result) && (Access::AuthMode::kGroup == subjectDescriptor.authMode) &&
375 20 : (Access::RequestType::kCommandInvokeRequest == requestPath.requestType) &&
376 20593 : (Access::Privilege::kOperate == requestPrivilege) && IsGroupId(subjectDescriptor.subject))
377 : {
378 8 : Credentials::GroupDataProvider * groups = Credentials::GetGroupDataProvider();
379 14 : VerifyOrReturnError(nullptr != groups, result);
380 8 : Credentials::GroupDataProvider::GroupInfo info;
381 8 : GroupId gid = GroupIdFromNodeId(subjectDescriptor.subject);
382 8 : ReturnErrorOnFailure(groups->GetGroupInfo(subjectDescriptor.fabricIndex, gid, info));
383 6 : if (info.HasAuxiliaryACL() && IsGroupAuxiliaryDelegateRegistered())
384 : {
385 4 : return mGroupAuxDelegate->Check(subjectDescriptor, requestPath, requestPrivilege);
386 : }
387 : }
388 :
389 20525 : return result;
390 : }
391 :
392 20531 : CHIP_ERROR AccessControl::CheckACL(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
393 : Privilege requestPrivilege)
394 : {
395 : #if CHIP_PROGRESS_LOGGING && CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
396 : {
397 20531 : constexpr size_t kMaxCatsToLog = 6;
398 : char catLogBuf[kMaxCatsToLog * kCharsPerCatForLogging];
399 20531 : ChipLogProgress(DataManagement,
400 : "AccessControl: checking f=%u a=%c s=0x" ChipLogFormatX64 " t=%s c=" ChipLogFormatMEI " e=%u p=%c r=%c",
401 : subjectDescriptor.fabricIndex, GetAuthModeStringForLogging(subjectDescriptor.authMode),
402 : ChipLogValueX64(subjectDescriptor.subject),
403 : GetCatStringForLogging(catLogBuf, sizeof(catLogBuf), subjectDescriptor.cats),
404 : ChipLogValueMEI(requestPath.cluster), requestPath.endpoint, GetPrivilegeStringForLogging(requestPrivilege),
405 : GetRequestTypeStringForLogging(requestPath.requestType));
406 : }
407 : #endif // CHIP_PROGRESS_LOGGING && CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
408 :
409 : {
410 20531 : CHIP_ERROR result = mDelegate->Check(subjectDescriptor, requestPath, requestPrivilege);
411 41062 : if (result != CHIP_ERROR_NOT_IMPLEMENTED)
412 : {
413 : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 0
414 20463 : ChipLogProgress(DataManagement, "AccessControl: %s (delegate)",
415 : (result == CHIP_NO_ERROR) ? "allowed"
416 : : (result == CHIP_ERROR_ACCESS_DENIED) ? "denied"
417 : : "error");
418 : #else
419 : if (result != CHIP_NO_ERROR)
420 : {
421 : ChipLogProgress(DataManagement, "AccessControl: %s (delegate)",
422 : (result == CHIP_ERROR_ACCESS_DENIED) ? "denied" : "error");
423 : }
424 : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 0
425 :
426 20463 : return result;
427 : }
428 : }
429 :
430 : // Operational PASE not supported for v1.0, so PASE implies commissioning, which has highest privilege.
431 : // Currently, subject descriptor is only PASE if this node is the responder (aka commissionee);
432 : // if this node is the initiator (aka commissioner) then the subject descriptor remains blank.
433 68 : if (subjectDescriptor.authMode == AuthMode::kPase)
434 : {
435 : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
436 5 : ChipLogProgress(DataManagement, "AccessControl: implicit admin (PASE)");
437 : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
438 5 : return CHIP_NO_ERROR;
439 : }
440 :
441 63 : EntryIterator iterator;
442 63 : ReturnErrorOnFailure(Entries(iterator, &subjectDescriptor.fabricIndex));
443 :
444 63 : Entry entry;
445 464 : while (iterator.Next(entry) == CHIP_NO_ERROR)
446 : {
447 191 : AuthMode authMode = AuthMode::kNone;
448 191 : ReturnErrorOnFailure(entry.GetAuthMode(authMode));
449 : // Operational PASE not supported for v1.0.
450 191 : VerifyOrReturnError(authMode == AuthMode::kCase || authMode == AuthMode::kGroup, CHIP_ERROR_INCORRECT_STATE);
451 191 : if (authMode != subjectDescriptor.authMode)
452 : {
453 169 : continue;
454 : }
455 :
456 128 : Privilege privilege = Privilege::kView;
457 128 : ReturnErrorOnFailure(entry.GetPrivilege(privilege));
458 128 : if (!CheckRequestPrivilegeAgainstEntryPrivilege(requestPrivilege, privilege))
459 : {
460 32 : continue;
461 : }
462 :
463 96 : size_t subjectCount = 0;
464 96 : ReturnErrorOnFailure(entry.GetSubjectCount(subjectCount));
465 96 : if (subjectCount > 0)
466 : {
467 89 : bool subjectMatched = false;
468 167 : for (size_t i = 0; i < subjectCount; ++i)
469 : {
470 105 : NodeId subject = kUndefinedNodeId;
471 105 : ReturnErrorOnFailure(entry.GetSubject(i, subject));
472 105 : if (IsOperationalNodeId(subject))
473 : {
474 53 : VerifyOrReturnError(authMode == AuthMode::kCase, CHIP_ERROR_INCORRECT_STATE);
475 53 : if (subject == subjectDescriptor.subject)
476 : {
477 13 : subjectMatched = true;
478 27 : break;
479 : }
480 : }
481 52 : else if (IsCASEAuthTag(subject))
482 : {
483 45 : VerifyOrReturnError(authMode == AuthMode::kCase, CHIP_ERROR_INCORRECT_STATE);
484 45 : if (subjectDescriptor.cats.CheckSubjectAgainstCATs(subject))
485 : {
486 8 : subjectMatched = true;
487 8 : break;
488 : }
489 : }
490 7 : else if (IsGroupId(subject))
491 : {
492 7 : VerifyOrReturnError(authMode == AuthMode::kGroup, CHIP_ERROR_INCORRECT_STATE);
493 7 : if (subject == subjectDescriptor.subject)
494 : {
495 6 : subjectMatched = true;
496 6 : break;
497 : }
498 : }
499 : else
500 : {
501 : // Operational PASE not supported for v1.0.
502 0 : return CHIP_ERROR_INCORRECT_STATE;
503 : }
504 : }
505 89 : if (!subjectMatched)
506 : {
507 62 : continue;
508 : }
509 : }
510 :
511 34 : size_t targetCount = 0;
512 34 : ReturnErrorOnFailure(entry.GetTargetCount(targetCount));
513 34 : if (targetCount > 0)
514 : {
515 22 : bool targetMatched = false;
516 43 : for (size_t i = 0; i < targetCount; ++i)
517 : {
518 31 : Entry::Target target;
519 31 : ReturnErrorOnFailure(entry.GetTarget(i, target));
520 31 : if ((target.flags & Entry::Target::kCluster) && target.cluster != requestPath.cluster)
521 : {
522 21 : continue;
523 : }
524 15 : if ((target.flags & Entry::Target::kEndpoint) && target.endpoint != requestPath.endpoint)
525 : {
526 5 : continue;
527 : }
528 10 : if (target.flags & Entry::Target::kDeviceType &&
529 0 : !mDeviceTypeResolver->IsDeviceTypeOnEndpoint(target.deviceType, requestPath.endpoint))
530 : {
531 0 : continue;
532 : }
533 10 : targetMatched = true;
534 10 : break;
535 : }
536 22 : if (!targetMatched)
537 : {
538 12 : continue;
539 : }
540 : }
541 : // Entry passed all checks: access is allowed.
542 :
543 : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 0
544 22 : ChipLogProgress(DataManagement, "AccessControl: allowed");
545 : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 0
546 :
547 22 : return CHIP_NO_ERROR;
548 : }
549 :
550 : // No entry was found which passed all checks: access is denied.
551 41 : ChipLogProgress(DataManagement, "AccessControl: denied");
552 41 : return CHIP_ERROR_ACCESS_DENIED;
553 63 : }
554 :
555 : #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
556 : CHIP_ERROR AccessControl::CheckARL(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
557 : Privilege requestPrivilege)
558 : {
559 : CHIP_ERROR result = CHIP_NO_ERROR;
560 :
561 : VerifyOrReturnError(requestPath.requestType != RequestType::kRequestTypeUnknown, CHIP_ERROR_INVALID_ARGUMENT);
562 :
563 : if (!IsAccessRestrictionListSupported())
564 : {
565 : // Access Restriction support is compiled in, but not configured/enabled. Nothing to restrict.
566 : return CHIP_NO_ERROR;
567 : }
568 :
569 : if (subjectDescriptor.isCommissioning)
570 : {
571 : result = mAccessRestrictionProvider->CheckForCommissioning(subjectDescriptor, requestPath);
572 : }
573 : else
574 : {
575 : result = mAccessRestrictionProvider->Check(subjectDescriptor, requestPath);
576 : }
577 :
578 : if (result != CHIP_NO_ERROR)
579 : {
580 : ChipLogProgress(DataManagement, "AccessControl: %s",
581 : (result == CHIP_ERROR_ACCESS_RESTRICTED_BY_ARL) ? "denied (restricted)" : "denied (restriction error)");
582 : return result;
583 : }
584 :
585 : return result;
586 : }
587 : #endif
588 :
589 : #if CHIP_ACCESS_CONTROL_DUMP_ENABLED
590 : CHIP_ERROR AccessControl::Dump(const Entry & entry)
591 : {
592 : CHIP_ERROR err;
593 :
594 : ChipLogDetail(DataManagement, "----- BEGIN ENTRY -----");
595 :
596 : {
597 : FabricIndex fabricIndex;
598 : SuccessOrExit(err = entry.GetFabricIndex(fabricIndex));
599 : ChipLogDetail(DataManagement, "fabricIndex: %u", fabricIndex);
600 : }
601 :
602 : {
603 : Privilege privilege;
604 : SuccessOrExit(err = entry.GetPrivilege(privilege));
605 : ChipLogDetail(DataManagement, "privilege: %d", to_underlying(privilege));
606 : }
607 :
608 : {
609 : AuthMode authMode;
610 : SuccessOrExit(err = entry.GetAuthMode(authMode));
611 : ChipLogDetail(DataManagement, "authMode: %d", to_underlying(authMode));
612 : }
613 :
614 : {
615 : AuxiliaryType auxiliaryType;
616 : // Auxiliary type is optional, so it not being implemented
617 : // is still a valid configuration, all other errors should
618 : // be handled appropriately.
619 : err = GetAuxiliaryType(auxiliaryType);
620 : if (err != CHIP_ERROR_NOT_IMPLEMENTED)
621 : {
622 : SuccessOrExit(err);
623 : ChipLogDetail(DataManagement, "auxiliaryType: %d", to_underlying(auxiliaryType));
624 : }
625 : }
626 :
627 : {
628 : size_t count;
629 : SuccessOrExit(err = entry.GetSubjectCount(count));
630 : if (count)
631 : {
632 : ChipLogDetail(DataManagement, "subjects: %u", static_cast<unsigned>(count));
633 : for (size_t i = 0; i < count; ++i)
634 : {
635 : NodeId subject;
636 : SuccessOrExit(err = entry.GetSubject(i, subject));
637 : ChipLogDetail(DataManagement, " %u: 0x" ChipLogFormatX64, static_cast<unsigned>(i), ChipLogValueX64(subject));
638 : }
639 : }
640 : }
641 :
642 : {
643 : size_t count;
644 : SuccessOrExit(err = entry.GetTargetCount(count));
645 : if (count)
646 : {
647 : ChipLogDetail(DataManagement, "targets: %u", static_cast<unsigned>(count));
648 : for (size_t i = 0; i < count; ++i)
649 : {
650 : Entry::Target target;
651 : SuccessOrExit(err = entry.GetTarget(i, target));
652 : if (target.flags & Entry::Target::kCluster)
653 : {
654 : ChipLogDetail(DataManagement, " %u: cluster: 0x" ChipLogFormatMEI, static_cast<unsigned>(i),
655 : ChipLogValueMEI(target.cluster));
656 : }
657 : if (target.flags & Entry::Target::kEndpoint)
658 : {
659 : ChipLogDetail(DataManagement, " %u: endpoint: %u", static_cast<unsigned>(i), target.endpoint);
660 : }
661 : if (target.flags & Entry::Target::kDeviceType)
662 : {
663 : ChipLogDetail(DataManagement, " %u: deviceType: 0x" ChipLogFormatMEI, static_cast<unsigned>(i),
664 : ChipLogValueMEI(target.deviceType));
665 : }
666 : }
667 : }
668 : }
669 :
670 : ChipLogDetail(DataManagement, "----- END ENTRY -----");
671 :
672 : return CHIP_NO_ERROR;
673 :
674 : exit:
675 : ChipLogError(DataManagement, "AccessControl: dump failed %" CHIP_ERROR_FORMAT, err.Format());
676 : return err;
677 : }
678 : #endif
679 :
680 42367 : bool AccessControl::Entry::IsValid() const
681 : {
682 42367 : const char * log = "unexpected error";
683 : IgnoreUnusedVariable(log); // logging may be disabled
684 :
685 42367 : AuthMode authMode = AuthMode::kNone;
686 42367 : FabricIndex fabricIndex = kUndefinedFabricIndex;
687 42367 : Privilege privilege = static_cast<Privilege>(0);
688 42367 : AuxiliaryType auxiliaryType = AuxiliaryType::kSystem;
689 42367 : size_t subjectCount = 0;
690 42367 : size_t targetCount = 0;
691 :
692 42367 : CHIP_ERROR err = CHIP_NO_ERROR;
693 42367 : SuccessOrExit(err = GetAuthMode(authMode));
694 42367 : SuccessOrExit(err = GetFabricIndex(fabricIndex));
695 42367 : SuccessOrExit(err = GetPrivilege(privilege));
696 42367 : SuccessOrExit(err = GetSubjectCount(subjectCount));
697 42367 : SuccessOrExit(err = GetTargetCount(targetCount));
698 :
699 : // Auxiliary type is optional, so it not being implemented
700 : // is still a valid configuration, all other errors should
701 : // be handled appropriately.
702 42367 : err = GetAuxiliaryType(auxiliaryType);
703 84734 : if (err != CHIP_ERROR_NOT_IMPLEMENTED)
704 : {
705 40948 : SuccessOrExit(err);
706 : }
707 :
708 : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
709 42367 : ChipLogProgress(DataManagement, "AccessControl: validating f=%u p=%c a=%c x=%d s=%d t=%d", fabricIndex,
710 : GetPrivilegeStringForLogging(privilege), GetAuthModeStringForLogging(authMode),
711 : GetAuxiliaryTypeStringForLogging(auxiliaryType), static_cast<int>(subjectCount), static_cast<int>(targetCount));
712 : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
713 :
714 : // Fabric index must be defined.
715 42367 : VerifyOrExit(fabricIndex != kUndefinedFabricIndex, log = "invalid fabric index");
716 :
717 42365 : if (authMode != AuthMode::kCase)
718 : {
719 : // Operational PASE not supported for v1.0 (so must be group).
720 734 : VerifyOrExit(authMode == AuthMode::kGroup, log = "invalid auth mode");
721 :
722 : // Privilege must not be administer.
723 290 : VerifyOrExit(privilege != Privilege::kAdminister, log = "invalid privilege");
724 : }
725 :
726 83399 : for (size_t i = 0; i < subjectCount; ++i)
727 : {
728 : NodeId subject;
729 42232 : SuccessOrExit(err = GetSubject(i, subject));
730 41856 : const bool kIsCase = authMode == AuthMode::kCase;
731 41856 : const bool kIsGroup = authMode == AuthMode::kGroup;
732 : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
733 41856 : ChipLogProgress(DataManagement, " validating subject 0x" ChipLogFormatX64, ChipLogValueX64(subject));
734 : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
735 41856 : VerifyOrExit((kIsCase && IsValidCaseNodeId(subject)) || (kIsGroup && IsValidGroupNodeId(subject)), log = "invalid subject");
736 : }
737 :
738 42781 : for (size_t i = 0; i < targetCount; ++i)
739 : {
740 41362 : Entry::Target target;
741 81486 : SuccessOrExit(err = GetTarget(i, target));
742 41362 : const bool kHasCluster = target.flags & Entry::Target::kCluster;
743 41362 : const bool kHasEndpoint = target.flags & Entry::Target::kEndpoint;
744 41362 : const bool kHasDeviceType = target.flags & Entry::Target::kDeviceType;
745 41362 : VerifyOrExit((kHasCluster || kHasEndpoint || kHasDeviceType) && !(kHasEndpoint && kHasDeviceType) &&
746 : (!kHasCluster || IsValidClusterId(target.cluster)) &&
747 : (!kHasEndpoint || IsValidEndpointId(target.endpoint)) &&
748 : (!kHasDeviceType || IsValidDeviceTypeId(target.deviceType)),
749 : log = "invalid target");
750 : }
751 :
752 1419 : return true;
753 :
754 40948 : exit:
755 81896 : if (err != CHIP_NO_ERROR)
756 : {
757 0 : ChipLogError(DataManagement, "AccessControl: %s %" CHIP_ERROR_FORMAT, log, err.Format());
758 : }
759 : else
760 : {
761 40948 : ChipLogError(DataManagement, "AccessControl: %s", log);
762 : }
763 40948 : return false;
764 : }
765 :
766 13 : void AccessControl::NotifyEntryChanged(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index,
767 : const Entry * entry, EntryListener::ChangeType changeType)
768 : {
769 16 : for (EntryListener * listener = mEntryListener; listener != nullptr; listener = listener->mNext)
770 : {
771 3 : listener->OnEntryChanged(subjectDescriptor, fabric, index, entry, changeType);
772 : }
773 13 : }
774 :
775 21313 : AccessControl & GetAccessControl()
776 : {
777 21313 : return (globalAccessControl) ? *globalAccessControl : defaultAccessControl.get();
778 : }
779 :
780 343 : void SetAccessControl(AccessControl & accessControl)
781 : {
782 343 : ChipLogProgress(DataManagement, "AccessControl: setting");
783 343 : globalAccessControl = &accessControl;
784 343 : }
785 :
786 343 : void ResetAccessControlToDefault()
787 : {
788 343 : globalAccessControl = nullptr;
789 343 : }
790 :
791 : } // namespace Access
792 : } // namespace chip
|