30
30
#include " access/RequestPath.h"
31
31
#include " access/SubjectDescriptor.h"
32
32
#include < app/RequiredPrivilege.h>
33
+ #include < app/util/af-types.h>
34
+ #include < app/util/endpoint-config-api.h>
33
35
#include < lib/core/TLVUtilities.h>
34
36
#include < lib/support/CodeUtils.h>
35
37
36
- extern bool emberAfContainsAttribute (chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId);
37
-
38
38
namespace chip {
39
39
namespace app {
40
40
@@ -351,10 +351,8 @@ CHIP_ERROR InteractionModelEngine::ParseAttributePaths(const Access::SubjectDesc
351
351
aHasValidAttributePath = false ;
352
352
aRequestedAttributePathCount = 0 ;
353
353
354
- while (CHIP_NO_ERROR == (err = pathReader.Next ()))
354
+ while (CHIP_NO_ERROR == (err = pathReader.Next (TLV::AnonymousTag () )))
355
355
{
356
- VerifyOrReturnError (TLV::AnonymousTag () == pathReader.GetTag (), CHIP_ERROR_INVALID_TLV_TAG);
357
-
358
356
AttributePathIB::Parser path;
359
357
//
360
358
// We create an iterator to point to a single item object list that tracks the path we just parsed.
@@ -413,6 +411,152 @@ CHIP_ERROR InteractionModelEngine::ParseAttributePaths(const Access::SubjectDesc
413
411
return err;
414
412
}
415
413
414
+ static bool CanAccess (const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteClusterPath & aPath,
415
+ Access::Privilege aNeededPrivilege)
416
+ {
417
+ Access::RequestPath requestPath{ .cluster = aPath.mClusterId , .endpoint = aPath.mEndpointId };
418
+ CHIP_ERROR err = Access::GetAccessControl ().Check (aSubjectDescriptor, requestPath, aNeededPrivilege);
419
+ return (err == CHIP_NO_ERROR);
420
+ }
421
+
422
+ static bool CanAccess (const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteEventPath & aPath)
423
+ {
424
+ return CanAccess (aSubjectDescriptor, aPath, RequiredPrivilege::ForReadEvent (aPath));
425
+ }
426
+
427
+ /* *
428
+ * Helper to handle wildcard events in the event path.
429
+ */
430
+ static bool HasValidEventPathForEndpointAndCluster (EndpointId aEndpoint, const EmberAfCluster * aCluster,
431
+ const EventPathParams & aEventPath,
432
+ const Access::SubjectDescriptor & aSubjectDescriptor)
433
+ {
434
+ if (aEventPath.HasWildcardEventId ())
435
+ {
436
+ #if CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
437
+ for (decltype (aCluster->eventCount ) idx = 0 ; idx > aCluster->eventCount ; ++idx)
438
+ {
439
+ ConcreteEventPath path (aEndpoint, aCluster->clusterId , aCluster->eventList [idx]);
440
+ // If we get here, the path exists. We just have to do an ACL check for it.
441
+ bool isValid = CanAccess (aSubjectDescriptor, path);
442
+ if (isValid)
443
+ {
444
+ return true ;
445
+ }
446
+ }
447
+
448
+ return false ;
449
+ #else
450
+ // We have no way to expand wildcards. Just assume that we would need
451
+ // View permissions for whatever events are involved.
452
+ ConcreteClusterPath clusterPath (aEndpoint, aCluster->clusterId );
453
+ return CanAccess (aSubjectDescriptor, clusterPath, Access::Privilege::kView );
454
+ #endif
455
+ }
456
+
457
+ ConcreteEventPath path (aEndpoint, aCluster->clusterId , aEventPath.mEventId );
458
+ if (CheckEventSupportStatus (path) != Status::Success)
459
+ {
460
+ // Not an existing event path.
461
+ return false ;
462
+ }
463
+ return CanAccess (aSubjectDescriptor, path);
464
+ }
465
+
466
+ /* *
467
+ * Helper to handle wildcard clusters in the event path.
468
+ */
469
+ static bool HasValidEventPathForEndpoint (EndpointId aEndpoint, const EventPathParams & aEventPath,
470
+ const Access::SubjectDescriptor & aSubjectDescriptor)
471
+ {
472
+ if (aEventPath.HasWildcardClusterId ())
473
+ {
474
+ auto * endpointType = emberAfFindEndpointType (aEndpoint);
475
+ if (endpointType == nullptr )
476
+ {
477
+ // Not going to have any valid paths in here.
478
+ return false ;
479
+ }
480
+
481
+ for (decltype (endpointType->clusterCount ) idx = 0 ; idx < endpointType->clusterCount ; ++idx)
482
+ {
483
+ bool hasValidPath =
484
+ HasValidEventPathForEndpointAndCluster (aEndpoint, &endpointType->cluster [idx], aEventPath, aSubjectDescriptor);
485
+ if (hasValidPath)
486
+ {
487
+ return true ;
488
+ }
489
+ }
490
+
491
+ return false ;
492
+ }
493
+
494
+ auto * cluster = emberAfFindServerCluster (aEndpoint, aEventPath.mClusterId );
495
+ if (cluster == nullptr )
496
+ {
497
+ // Nothing valid here.
498
+ return false ;
499
+ }
500
+ return HasValidEventPathForEndpointAndCluster (aEndpoint, cluster, aEventPath, aSubjectDescriptor);
501
+ }
502
+
503
+ CHIP_ERROR InteractionModelEngine::ParseEventPaths (const Access::SubjectDescriptor & aSubjectDescriptor,
504
+ EventPathIBs::Parser & aEventPathListParser, bool & aHasValidEventPath,
505
+ size_t & aRequestedEventPathCount)
506
+ {
507
+ TLV::TLVReader pathReader;
508
+ aEventPathListParser.GetReader (&pathReader);
509
+ CHIP_ERROR err = CHIP_NO_ERROR;
510
+
511
+ aHasValidEventPath = false ;
512
+ aRequestedEventPathCount = 0 ;
513
+
514
+ while (CHIP_NO_ERROR == (err = pathReader.Next (TLV::AnonymousTag ())))
515
+ {
516
+ EventPathIB::Parser path;
517
+ ReturnErrorOnFailure (path.Init (pathReader));
518
+
519
+ EventPathParams eventPath;
520
+ ReturnErrorOnFailure (path.ParsePath (eventPath));
521
+
522
+ ++aRequestedEventPathCount;
523
+
524
+ if (aHasValidEventPath)
525
+ {
526
+ // Can skip all the rest of the checking.
527
+ continue ;
528
+ }
529
+
530
+ // The definition of "valid path" is "path exists and ACL allows
531
+ // access". We need to do some expansion of wildcards to handle that.
532
+ if (eventPath.HasWildcardEndpointId ())
533
+ {
534
+ for (uint16_t endpointIndex = 0 ; !aHasValidEventPath && endpointIndex < emberAfEndpointCount (); ++endpointIndex)
535
+ {
536
+ if (!emberAfEndpointIndexIsEnabled (endpointIndex))
537
+ {
538
+ continue ;
539
+ }
540
+ aHasValidEventPath =
541
+ HasValidEventPathForEndpoint (emberAfEndpointFromIndex (endpointIndex), eventPath, aSubjectDescriptor);
542
+ }
543
+ }
544
+ else
545
+ {
546
+ // No need to check whether the endpoint is enabled, because
547
+ // emberAfFindEndpointType returns null for disabled endpoints.
548
+ aHasValidEventPath = HasValidEventPathForEndpoint (eventPath.mEndpointId , eventPath, aSubjectDescriptor);
549
+ }
550
+ }
551
+
552
+ if (err == CHIP_ERROR_END_OF_TLV)
553
+ {
554
+ err = CHIP_NO_ERROR;
555
+ }
556
+
557
+ return err;
558
+ }
559
+
416
560
Protocols::InteractionModel::Status InteractionModelEngine::OnReadInitialRequest (Messaging::ExchangeContext * apExchangeContext,
417
561
const PayloadHeader & aPayloadHeader,
418
562
System::PacketBufferHandle && aPayload,
@@ -472,6 +616,7 @@ Protocols::InteractionModel::Status InteractionModelEngine::OnReadInitialRequest
472
616
size_t requestedEventPathCount = 0 ;
473
617
AttributePathIBs::Parser attributePathListParser;
474
618
bool hasValidAttributePath = false ;
619
+ bool hasValidEventPath = false ;
475
620
476
621
CHIP_ERROR err = subscribeRequestParser.GetAttributeRequests (&attributePathListParser);
477
622
if (err == CHIP_NO_ERROR)
@@ -489,14 +634,16 @@ Protocols::InteractionModel::Status InteractionModelEngine::OnReadInitialRequest
489
634
return Status::InvalidAction;
490
635
}
491
636
492
- EventPathIBs::Parser eventpathListParser ;
493
- err = subscribeRequestParser.GetEventRequests (&eventpathListParser );
637
+ EventPathIBs::Parser eventPathListParser ;
638
+ err = subscribeRequestParser.GetEventRequests (&eventPathListParser );
494
639
if (err == CHIP_NO_ERROR)
495
640
{
496
- TLV::TLVReader pathReader;
497
- eventpathListParser.GetReader (&pathReader);
498
- ReturnErrorCodeIf (TLV::Utilities::Count (pathReader, requestedEventPathCount, false ) != CHIP_NO_ERROR,
499
- Status::InvalidAction);
641
+ auto subjectDescriptor = apExchangeContext->GetSessionHandle ()->AsSecureSession ()->GetSubjectDescriptor ();
642
+ err = ParseEventPaths (subjectDescriptor, eventPathListParser, hasValidEventPath, requestedEventPathCount);
643
+ if (err != CHIP_NO_ERROR)
644
+ {
645
+ return Status::InvalidAction;
646
+ }
500
647
}
501
648
else if (err != CHIP_ERROR_END_OF_TLV)
502
649
{
@@ -512,12 +659,7 @@ Protocols::InteractionModel::Status InteractionModelEngine::OnReadInitialRequest
512
659
return Status::InvalidAction;
513
660
}
514
661
515
- //
516
- // TODO: We don't have an easy way to do a similar 'path expansion' for events to deduce
517
- // access so for now, assume that the presence of any path in the event list means they
518
- // might have some access to those events.
519
- //
520
- if (!hasValidAttributePath && requestedEventPathCount == 0 )
662
+ if (!hasValidAttributePath && !hasValidEventPath)
521
663
{
522
664
ChipLogError (InteractionModel,
523
665
" Subscription from [%u:" ChipLogFormatX64 " ] has no access at all. Rejecting request." ,
0 commit comments