Matter SDK Coverage Report
Current view: top level - access - AccessControl.cpp (source / functions) Coverage Total Hit
Test: SHA:f1767a8b0a3778fdf31b1d979afbdf544892fd94 Lines: 71.7 % 304 218
Test Date: 2026-06-03 07:35:21 Functions: 78.3 % 23 18

            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          520 : CHIP_ERROR AccessControl::Init(AccessControl::Delegate * delegate, DeviceTypeResolver & deviceTypeResolver)
     217              : {
     218          520 :     VerifyOrReturnError(!IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     219              : 
     220          519 :     ChipLogProgress(DataManagement, "AccessControl: initializing");
     221              : 
     222          519 :     VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     223          519 :     CHIP_ERROR retval = delegate->Init();
     224         1038 :     if (retval == CHIP_NO_ERROR)
     225              :     {
     226          519 :         mDelegate           = delegate;
     227          519 :         mDeviceTypeResolver = &deviceTypeResolver;
     228              :     }
     229              : 
     230          519 :     return retval;
     231              : }
     232              : 
     233          521 : void AccessControl::Finish()
     234              : {
     235          521 :     VerifyOrReturn(IsInitialized());
     236          519 :     ChipLogProgress(DataManagement, "AccessControl: finishing");
     237          519 :     mDelegate->Finish();
     238          519 :     mDelegate = nullptr;
     239              : 
     240          519 :     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        20538 : CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
     360              :                                 Privilege requestPrivilege)
     361              : {
     362        20538 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     363        20538 :     VerifyOrReturnError(IsValidPrivilege(requestPrivilege), CHIP_ERROR_INVALID_ARGUMENT);
     364              : 
     365        20538 :     CHIP_ERROR result = CheckACL(subjectDescriptor, requestPath, requestPrivilege);
     366              : 
     367        20600 :     if ((CHIP_NO_ERROR != result) && (Access::AuthMode::kGroup == subjectDescriptor.authMode) &&
     368           20 :         (Access::RequestType::kCommandInvokeRequest == requestPath.requestType) &&
     369        20600 :         (Access::Privilege::kOperate == requestPrivilege) && IsGroupId(subjectDescriptor.subject))
     370              :     {
     371            8 :         Credentials::GroupDataProvider * groups = Credentials::GetGroupDataProvider();
     372           10 :         VerifyOrReturnError(nullptr != groups, result);
     373            8 :         Credentials::GroupDataProvider::GroupInfo info;
     374            8 :         GroupId gid = GroupIdFromNodeId(subjectDescriptor.subject);
     375            8 :         ReturnErrorOnFailure(groups->GetGroupInfo(subjectDescriptor.fabricIndex, gid, info));
     376            6 :         if (info.HasAuxiliaryACL() && IsGroupAuxiliaryDelegateRegistered())
     377              :         {
     378            4 :             result = mGroupAuxDelegate->Check(subjectDescriptor, requestPath, requestPrivilege);
     379              :         }
     380              :     }
     381              : 
     382              :     // CheckARL runs last: it must apply to grants from ACL or the AuxiliaryACL fallback above.
     383              : #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
     384              :     if (result == CHIP_NO_ERROR)
     385              :     {
     386              :         result = CheckARL(subjectDescriptor, requestPath, requestPrivilege);
     387              :     }
     388              : #endif
     389              : 
     390        20536 :     return result;
     391              : }
     392              : 
     393        20538 : CHIP_ERROR AccessControl::CheckACL(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
     394              :                                    Privilege requestPrivilege)
     395              : {
     396              : #if CHIP_PROGRESS_LOGGING && CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
     397              :     {
     398        20538 :         constexpr size_t kMaxCatsToLog = 6;
     399              :         char catLogBuf[kMaxCatsToLog * kCharsPerCatForLogging];
     400        20538 :         ChipLogProgress(DataManagement,
     401              :                         "AccessControl: checking f=%u a=%c s=0x" ChipLogFormatX64 " t=%s c=" ChipLogFormatMEI " e=%u p=%c r=%c",
     402              :                         subjectDescriptor.fabricIndex, GetAuthModeStringForLogging(subjectDescriptor.authMode),
     403              :                         ChipLogValueX64(subjectDescriptor.subject),
     404              :                         GetCatStringForLogging(catLogBuf, sizeof(catLogBuf), subjectDescriptor.cats),
     405              :                         ChipLogValueMEI(requestPath.cluster), requestPath.endpoint, GetPrivilegeStringForLogging(requestPrivilege),
     406              :                         GetRequestTypeStringForLogging(requestPath.requestType));
     407              :     }
     408              : #endif // CHIP_PROGRESS_LOGGING && CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
     409              : 
     410              :     {
     411        20538 :         CHIP_ERROR result = mDelegate->Check(subjectDescriptor, requestPath, requestPrivilege);
     412        41076 :         if (result != CHIP_ERROR_NOT_IMPLEMENTED)
     413              :         {
     414              : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 0
     415        20470 :             ChipLogProgress(DataManagement, "AccessControl: %s (delegate)",
     416              :                             (result == CHIP_NO_ERROR)                  ? "allowed"
     417              :                                 : (result == CHIP_ERROR_ACCESS_DENIED) ? "denied"
     418              :                                                                        : "error");
     419              : #else
     420              :             if (result != CHIP_NO_ERROR)
     421              :             {
     422              :                 ChipLogProgress(DataManagement, "AccessControl: %s (delegate)",
     423              :                                 (result == CHIP_ERROR_ACCESS_DENIED) ? "denied" : "error");
     424              :             }
     425              : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 0
     426              : 
     427        20470 :             return result;
     428              :         }
     429              :     }
     430              : 
     431              :     // Operational PASE not supported for v1.0, so PASE implies commissioning, which has highest privilege.
     432              :     // Currently, subject descriptor is only PASE if this node is the responder (aka commissionee);
     433              :     // if this node is the initiator (aka commissioner) then the subject descriptor remains blank.
     434           68 :     if (subjectDescriptor.authMode == AuthMode::kPase)
     435              :     {
     436              : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
     437            5 :         ChipLogProgress(DataManagement, "AccessControl: implicit admin (PASE)");
     438              : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
     439            5 :         return CHIP_NO_ERROR;
     440              :     }
     441              : 
     442           63 :     EntryIterator iterator;
     443           63 :     ReturnErrorOnFailure(Entries(iterator, &subjectDescriptor.fabricIndex));
     444              : 
     445           63 :     Entry entry;
     446          464 :     while (iterator.Next(entry) == CHIP_NO_ERROR)
     447              :     {
     448          191 :         AuthMode authMode = AuthMode::kNone;
     449          191 :         ReturnErrorOnFailure(entry.GetAuthMode(authMode));
     450              :         // Operational PASE not supported for v1.0.
     451          191 :         VerifyOrReturnError(authMode == AuthMode::kCase || authMode == AuthMode::kGroup, CHIP_ERROR_INCORRECT_STATE);
     452          191 :         if (authMode != subjectDescriptor.authMode)
     453              :         {
     454          169 :             continue;
     455              :         }
     456              : 
     457          128 :         Privilege privilege = Privilege::kView;
     458          128 :         ReturnErrorOnFailure(entry.GetPrivilege(privilege));
     459          128 :         if (!CheckRequestPrivilegeAgainstEntryPrivilege(requestPrivilege, privilege))
     460              :         {
     461           32 :             continue;
     462              :         }
     463              : 
     464           96 :         size_t subjectCount = 0;
     465           96 :         ReturnErrorOnFailure(entry.GetSubjectCount(subjectCount));
     466           96 :         if (subjectCount > 0)
     467              :         {
     468           89 :             bool subjectMatched = false;
     469          167 :             for (size_t i = 0; i < subjectCount; ++i)
     470              :             {
     471          105 :                 NodeId subject = kUndefinedNodeId;
     472          105 :                 ReturnErrorOnFailure(entry.GetSubject(i, subject));
     473          105 :                 if (IsOperationalNodeId(subject))
     474              :                 {
     475           53 :                     VerifyOrReturnError(authMode == AuthMode::kCase, CHIP_ERROR_INCORRECT_STATE);
     476           53 :                     if (subject == subjectDescriptor.subject)
     477              :                     {
     478           13 :                         subjectMatched = true;
     479           27 :                         break;
     480              :                     }
     481              :                 }
     482           52 :                 else if (IsCASEAuthTag(subject))
     483              :                 {
     484           45 :                     VerifyOrReturnError(authMode == AuthMode::kCase, CHIP_ERROR_INCORRECT_STATE);
     485           45 :                     if (subjectDescriptor.cats.CheckSubjectAgainstCATs(subject))
     486              :                     {
     487            8 :                         subjectMatched = true;
     488            8 :                         break;
     489              :                     }
     490              :                 }
     491            7 :                 else if (IsGroupId(subject))
     492              :                 {
     493            7 :                     VerifyOrReturnError(authMode == AuthMode::kGroup, CHIP_ERROR_INCORRECT_STATE);
     494            7 :                     if (subject == subjectDescriptor.subject)
     495              :                     {
     496            6 :                         subjectMatched = true;
     497            6 :                         break;
     498              :                     }
     499              :                 }
     500              :                 else
     501              :                 {
     502              :                     // Operational PASE not supported for v1.0.
     503            0 :                     return CHIP_ERROR_INCORRECT_STATE;
     504              :                 }
     505              :             }
     506           89 :             if (!subjectMatched)
     507              :             {
     508           62 :                 continue;
     509              :             }
     510              :         }
     511              : 
     512           34 :         size_t targetCount = 0;
     513           34 :         ReturnErrorOnFailure(entry.GetTargetCount(targetCount));
     514           34 :         if (targetCount > 0)
     515              :         {
     516           22 :             bool targetMatched = false;
     517           43 :             for (size_t i = 0; i < targetCount; ++i)
     518              :             {
     519           31 :                 Entry::Target target;
     520           31 :                 ReturnErrorOnFailure(entry.GetTarget(i, target));
     521           31 :                 if ((target.flags & Entry::Target::kCluster) && target.cluster != requestPath.cluster)
     522              :                 {
     523           21 :                     continue;
     524              :                 }
     525           15 :                 if ((target.flags & Entry::Target::kEndpoint) && target.endpoint != requestPath.endpoint)
     526              :                 {
     527            5 :                     continue;
     528              :                 }
     529           10 :                 if (target.flags & Entry::Target::kDeviceType &&
     530            0 :                     !mDeviceTypeResolver->IsDeviceTypeOnEndpoint(target.deviceType, requestPath.endpoint))
     531              :                 {
     532            0 :                     continue;
     533              :                 }
     534           10 :                 targetMatched = true;
     535           10 :                 break;
     536              :             }
     537           22 :             if (!targetMatched)
     538              :             {
     539           12 :                 continue;
     540              :             }
     541              :         }
     542              :         // Entry passed all checks: access is allowed.
     543              : 
     544              : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 0
     545           22 :         ChipLogProgress(DataManagement, "AccessControl: allowed");
     546              : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 0
     547              : 
     548           22 :         return CHIP_NO_ERROR;
     549              :     }
     550              : 
     551              :     // No entry was found which passed all checks: access is denied.
     552           41 :     ChipLogProgress(DataManagement, "AccessControl: denied");
     553           41 :     return CHIP_ERROR_ACCESS_DENIED;
     554           63 : }
     555              : 
     556              : #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
     557              : CHIP_ERROR AccessControl::CheckARL(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
     558              :                                    Privilege requestPrivilege)
     559              : {
     560              :     CHIP_ERROR result = CHIP_NO_ERROR;
     561              : 
     562              :     VerifyOrReturnError(requestPath.requestType != RequestType::kRequestTypeUnknown, CHIP_ERROR_INVALID_ARGUMENT);
     563              : 
     564              :     if (!IsAccessRestrictionListSupported())
     565              :     {
     566              :         // Access Restriction support is compiled in, but not configured/enabled. Nothing to restrict.
     567              :         return CHIP_NO_ERROR;
     568              :     }
     569              : 
     570              :     if (subjectDescriptor.isCommissioning)
     571              :     {
     572              :         result = mAccessRestrictionProvider->CheckForCommissioning(subjectDescriptor, requestPath);
     573              :     }
     574              :     else
     575              :     {
     576              :         result = mAccessRestrictionProvider->Check(subjectDescriptor, requestPath);
     577              :     }
     578              : 
     579              :     if (result != CHIP_NO_ERROR)
     580              :     {
     581              :         ChipLogProgress(DataManagement, "AccessControl: %s",
     582              :                         (result == CHIP_ERROR_ACCESS_RESTRICTED_BY_ARL) ? "denied (restricted)" : "denied (restriction error)");
     583              :         return result;
     584              :     }
     585              : 
     586              :     return result;
     587              : }
     588              : #endif
     589              : 
     590              : #if CHIP_ACCESS_CONTROL_DUMP_ENABLED
     591              : CHIP_ERROR AccessControl::Dump(const Entry & entry)
     592              : {
     593              :     CHIP_ERROR err;
     594              : 
     595              :     ChipLogDetail(DataManagement, "----- BEGIN ENTRY -----");
     596              : 
     597              :     {
     598              :         FabricIndex fabricIndex;
     599              :         SuccessOrExit(err = entry.GetFabricIndex(fabricIndex));
     600              :         ChipLogDetail(DataManagement, "fabricIndex: %u", fabricIndex);
     601              :     }
     602              : 
     603              :     {
     604              :         Privilege privilege;
     605              :         SuccessOrExit(err = entry.GetPrivilege(privilege));
     606              :         ChipLogDetail(DataManagement, "privilege: %d", to_underlying(privilege));
     607              :     }
     608              : 
     609              :     {
     610              :         AuthMode authMode;
     611              :         SuccessOrExit(err = entry.GetAuthMode(authMode));
     612              :         ChipLogDetail(DataManagement, "authMode: %d", to_underlying(authMode));
     613              :     }
     614              : 
     615              :     {
     616              :         AuxiliaryType auxiliaryType;
     617              :         // Auxiliary type is optional, so it not being implemented
     618              :         // is still a valid configuration, all other errors should
     619              :         // be handled appropriately.
     620              :         err = GetAuxiliaryType(auxiliaryType);
     621              :         if (err != CHIP_ERROR_NOT_IMPLEMENTED)
     622              :         {
     623              :             SuccessOrExit(err);
     624              :             ChipLogDetail(DataManagement, "auxiliaryType: %d", to_underlying(auxiliaryType));
     625              :         }
     626              :     }
     627              : 
     628              :     {
     629              :         size_t count;
     630              :         SuccessOrExit(err = entry.GetSubjectCount(count));
     631              :         if (count)
     632              :         {
     633              :             ChipLogDetail(DataManagement, "subjects: %u", static_cast<unsigned>(count));
     634              :             for (size_t i = 0; i < count; ++i)
     635              :             {
     636              :                 NodeId subject;
     637              :                 SuccessOrExit(err = entry.GetSubject(i, subject));
     638              :                 ChipLogDetail(DataManagement, "  %u: 0x" ChipLogFormatX64, static_cast<unsigned>(i), ChipLogValueX64(subject));
     639              :             }
     640              :         }
     641              :     }
     642              : 
     643              :     {
     644              :         size_t count;
     645              :         SuccessOrExit(err = entry.GetTargetCount(count));
     646              :         if (count)
     647              :         {
     648              :             ChipLogDetail(DataManagement, "targets: %u", static_cast<unsigned>(count));
     649              :             for (size_t i = 0; i < count; ++i)
     650              :             {
     651              :                 Entry::Target target;
     652              :                 SuccessOrExit(err = entry.GetTarget(i, target));
     653              :                 if (target.flags & Entry::Target::kCluster)
     654              :                 {
     655              :                     ChipLogDetail(DataManagement, "  %u: cluster: 0x" ChipLogFormatMEI, static_cast<unsigned>(i),
     656              :                                   ChipLogValueMEI(target.cluster));
     657              :                 }
     658              :                 if (target.flags & Entry::Target::kEndpoint)
     659              :                 {
     660              :                     ChipLogDetail(DataManagement, "  %u: endpoint: %u", static_cast<unsigned>(i), target.endpoint);
     661              :                 }
     662              :                 if (target.flags & Entry::Target::kDeviceType)
     663              :                 {
     664              :                     ChipLogDetail(DataManagement, "  %u: deviceType: 0x" ChipLogFormatMEI, static_cast<unsigned>(i),
     665              :                                   ChipLogValueMEI(target.deviceType));
     666              :                 }
     667              :             }
     668              :         }
     669              :     }
     670              : 
     671              :     ChipLogDetail(DataManagement, "----- END ENTRY -----");
     672              : 
     673              :     return CHIP_NO_ERROR;
     674              : 
     675              : exit:
     676              :     ChipLogError(DataManagement, "AccessControl: dump failed %" CHIP_ERROR_FORMAT, err.Format());
     677              :     return err;
     678              : }
     679              : #endif
     680              : 
     681        42367 : bool AccessControl::Entry::IsValid() const
     682              : {
     683        42367 :     const char * log = "unexpected error";
     684              :     IgnoreUnusedVariable(log); // logging may be disabled
     685              : 
     686        42367 :     AuthMode authMode           = AuthMode::kNone;
     687        42367 :     FabricIndex fabricIndex     = kUndefinedFabricIndex;
     688        42367 :     Privilege privilege         = static_cast<Privilege>(0);
     689        42367 :     AuxiliaryType auxiliaryType = AuxiliaryType::kSystem;
     690        42367 :     size_t subjectCount         = 0;
     691        42367 :     size_t targetCount          = 0;
     692              : 
     693        42367 :     CHIP_ERROR err = CHIP_NO_ERROR;
     694        42367 :     SuccessOrExit(err = GetAuthMode(authMode));
     695        42367 :     SuccessOrExit(err = GetFabricIndex(fabricIndex));
     696        42367 :     SuccessOrExit(err = GetPrivilege(privilege));
     697        42367 :     SuccessOrExit(err = GetSubjectCount(subjectCount));
     698        42367 :     SuccessOrExit(err = GetTargetCount(targetCount));
     699              : 
     700              :     // Auxiliary type is optional, so it not being implemented
     701              :     // is still a valid configuration, all other errors should
     702              :     // be handled appropriately.
     703        42367 :     err = GetAuxiliaryType(auxiliaryType);
     704        84734 :     if (err != CHIP_ERROR_NOT_IMPLEMENTED)
     705              :     {
     706        40948 :         SuccessOrExit(err);
     707              :     }
     708              : 
     709              : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
     710        42367 :     ChipLogProgress(DataManagement, "AccessControl: validating f=%u p=%c a=%c x=%d s=%d t=%d", fabricIndex,
     711              :                     GetPrivilegeStringForLogging(privilege), GetAuthModeStringForLogging(authMode),
     712              :                     GetAuxiliaryTypeStringForLogging(auxiliaryType), static_cast<int>(subjectCount), static_cast<int>(targetCount));
     713              : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
     714              : 
     715              :     // Fabric index must be defined.
     716        42367 :     VerifyOrExit(fabricIndex != kUndefinedFabricIndex, log = "invalid fabric index");
     717              : 
     718        42365 :     if (authMode != AuthMode::kCase)
     719              :     {
     720              :         // Operational PASE not supported for v1.0 (so must be group).
     721          734 :         VerifyOrExit(authMode == AuthMode::kGroup, log = "invalid auth mode");
     722              : 
     723              :         // Privilege must not be administer.
     724          290 :         VerifyOrExit(privilege != Privilege::kAdminister, log = "invalid privilege");
     725              :     }
     726              : 
     727        83399 :     for (size_t i = 0; i < subjectCount; ++i)
     728              :     {
     729              :         NodeId subject;
     730        42232 :         SuccessOrExit(err = GetSubject(i, subject));
     731        41856 :         const bool kIsCase  = authMode == AuthMode::kCase;
     732        41856 :         const bool kIsGroup = authMode == AuthMode::kGroup;
     733              : #if CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
     734        41856 :         ChipLogProgress(DataManagement, "  validating subject 0x" ChipLogFormatX64, ChipLogValueX64(subject));
     735              : #endif // CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
     736        41856 :         VerifyOrExit((kIsCase && IsValidCaseNodeId(subject)) || (kIsGroup && IsValidGroupNodeId(subject)), log = "invalid subject");
     737              :     }
     738              : 
     739        42781 :     for (size_t i = 0; i < targetCount; ++i)
     740              :     {
     741        41362 :         Entry::Target target;
     742        81486 :         SuccessOrExit(err = GetTarget(i, target));
     743        41362 :         const bool kHasCluster    = target.flags & Entry::Target::kCluster;
     744        41362 :         const bool kHasEndpoint   = target.flags & Entry::Target::kEndpoint;
     745        41362 :         const bool kHasDeviceType = target.flags & Entry::Target::kDeviceType;
     746        41362 :         VerifyOrExit((kHasCluster || kHasEndpoint || kHasDeviceType) && !(kHasEndpoint && kHasDeviceType) &&
     747              :                          (!kHasCluster || IsValidClusterId(target.cluster)) &&
     748              :                          (!kHasEndpoint || IsValidEndpointId(target.endpoint)) &&
     749              :                          (!kHasDeviceType || IsValidDeviceTypeId(target.deviceType)),
     750              :                      log = "invalid target");
     751              :     }
     752              : 
     753         1419 :     return true;
     754              : 
     755        40948 : exit:
     756        81896 :     if (err != CHIP_NO_ERROR)
     757              :     {
     758            0 :         ChipLogError(DataManagement, "AccessControl: %s %" CHIP_ERROR_FORMAT, log, err.Format());
     759              :     }
     760              :     else
     761              :     {
     762        40948 :         ChipLogError(DataManagement, "AccessControl: %s", log);
     763              :     }
     764        40948 :     return false;
     765              : }
     766              : 
     767           13 : void AccessControl::NotifyEntryChanged(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index,
     768              :                                        const Entry * entry, EntryListener::ChangeType changeType)
     769              : {
     770           16 :     for (EntryListener * listener = mEntryListener; listener != nullptr; listener = listener->mNext)
     771              :     {
     772            3 :         listener->OnEntryChanged(subjectDescriptor, fabric, index, entry, changeType);
     773              :     }
     774           13 : }
     775              : 
     776        21369 : AccessControl & GetAccessControl()
     777              : {
     778        21369 :     return (globalAccessControl) ? *globalAccessControl : defaultAccessControl.get();
     779              : }
     780              : 
     781          365 : void SetAccessControl(AccessControl & accessControl)
     782              : {
     783          365 :     ChipLogProgress(DataManagement, "AccessControl: setting");
     784          365 :     globalAccessControl = &accessControl;
     785          365 : }
     786              : 
     787          365 : void ResetAccessControlToDefault()
     788              : {
     789          365 :     globalAccessControl = nullptr;
     790          365 : }
     791              : 
     792              : } // namespace Access
     793              : } // namespace chip
        

Generated by: LCOV version 2.0-1