Matter SDK Coverage Report
Current view: top level - access - AccessControl.cpp (source / functions) Coverage Total Hit
Test: SHA:97920baf58e6bf4a18be41e121e08f13676f36b0 Lines: 90.0 % 279 251
Test Date: 2025-08-17 07:11:11 Functions: 100.0 % 22 22

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

Generated by: LCOV version 2.0-1