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

Generated by: LCOV version 2.0-1