Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2022 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : 18 : #include <app/server/DefaultAclStorage.h> 19 : 20 : #include <lib/support/DefaultStorageKeyAllocator.h> 21 : 22 : using namespace chip; 23 : using namespace chip::app; 24 : using namespace chip::Access; 25 : 26 : using EncodableEntry = AclStorage::EncodableEntry; 27 : using Entry = AccessControl::Entry; 28 : using EntryListener = AccessControl::EntryListener; 29 : using StagingAuthMode = Clusters::AccessControl::AccessControlEntryAuthModeEnum; 30 : using StagingPrivilege = Clusters::AccessControl::AccessControlEntryPrivilegeEnum; 31 : using StagingTarget = Clusters::AccessControl::Structs::AccessControlTargetStruct::Type; 32 : using Target = AccessControl::Entry::Target; 33 : 34 : namespace { 35 : 36 : /* 37 : Size calculation for TLV encoded entry. 38 : 39 : Because EncodeForWrite is used without an accessing fabric, the fabric index is 40 : not encoded. However, let's assume it is. This yields 17 bytes total overhead, 41 : but it's wise to add a few more for safety. 42 : 43 : Each subject may require up to 9 bytes. Each target may require up to 14 bytes 44 : (only one of endpoint or device type will be encoded). 45 : 46 : DATA C T L V NOTES 47 : structure (anonymous) 1 0x15 48 : field 1 privilege 1 1 1 49 : field 2 authmode 1 1 1 50 : field 3 subjects 1 1 51 : uint64 1 8 per subject 52 : end list 1 0x18 53 : field 4 targets 1 1 54 : structure (anonymous) 1 per target 55 : field 0 cluster 1 1 4 56 : field 1 endpoint 1 1 2 only field 1 or 2 57 : field 2 devicetype 1 1 4 only field 1 or 2 58 : end structure 1 59 : end list 1 0x18 60 : field 254 fabric index 1 1 1 not written 61 : end structure 1 0x18 62 : */ 63 : 64 : // TODO(#14455): get actual values for max subjects/targets 65 : constexpr int kEncodedEntryOverheadBytes = 17 + 8; 66 : constexpr int kEncodedEntrySubjectBytes = 9 * CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_SUBJECTS_PER_ENTRY; 67 : constexpr int kEncodedEntryTargetBytes = 14 * CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_TARGETS_PER_ENTRY; 68 : constexpr int kEncodedEntryTotalBytes = kEncodedEntryOverheadBytes + kEncodedEntrySubjectBytes + kEncodedEntryTargetBytes; 69 : 70 : class : public EntryListener 71 : { 72 : public: 73 0 : void OnEntryChanged(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index, const Entry * entry, 74 : ChangeType changeType) override 75 : { 76 : CHIP_ERROR err; 77 : 78 0 : uint8_t buffer[kEncodedEntryTotalBytes] = { 0 }; 79 : 80 0 : VerifyOrExit(mPersistentStorage != nullptr, err = CHIP_ERROR_INCORRECT_STATE); 81 : 82 0 : if (changeType == ChangeType::kRemoved) 83 : { 84 : // Shuffle down entries past index, then delete entry at last index. 85 : while (true) 86 : { 87 0 : uint16_t size = static_cast<uint16_t>(sizeof(buffer)); 88 0 : err = mPersistentStorage->SyncGetKeyValue( 89 0 : DefaultStorageKeyAllocator::AccessControlAclEntry(fabric, index + 1).KeyName(), buffer, size); 90 0 : if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) 91 : { 92 0 : break; 93 : } 94 0 : SuccessOrExit(err); 95 0 : SuccessOrExit(err = mPersistentStorage->SyncSetKeyValue( 96 : DefaultStorageKeyAllocator::AccessControlAclEntry(fabric, index).KeyName(), buffer, size)); 97 0 : index++; 98 0 : } 99 0 : SuccessOrExit(err = mPersistentStorage->SyncDeleteKeyValue( 100 : DefaultStorageKeyAllocator::AccessControlAclEntry(fabric, index).KeyName())); 101 : } 102 : else 103 : { 104 : // Write added/updated entry at index. 105 0 : VerifyOrExit(entry != nullptr, err = CHIP_ERROR_INCORRECT_STATE); 106 0 : TLV::TLVWriter writer; 107 0 : writer.Init(buffer); 108 0 : EncodableEntry encodableEntry(*entry); 109 0 : SuccessOrExit(err = encodableEntry.EncodeForWrite(writer, TLV::AnonymousTag())); 110 0 : SuccessOrExit(err = mPersistentStorage->SyncSetKeyValue( 111 : DefaultStorageKeyAllocator::AccessControlAclEntry(fabric, index).KeyName(), buffer, 112 : static_cast<uint16_t>(writer.GetLengthWritten()))); 113 0 : } 114 : 115 0 : return; 116 : 117 0 : exit: 118 0 : ChipLogError(DataManagement, "DefaultAclStorage: failed %" CHIP_ERROR_FORMAT, err.Format()); 119 : } 120 : 121 : // Must initialize before use. 122 1 : void Init(PersistentStorageDelegate & persistentStorage) { mPersistentStorage = &persistentStorage; } 123 : 124 : private: 125 : PersistentStorageDelegate * mPersistentStorage = nullptr; 126 : 127 : } sEntryListener; 128 : 129 : } // namespace 130 : 131 : namespace chip { 132 : namespace app { 133 : 134 1 : CHIP_ERROR DefaultAclStorage::Init(PersistentStorageDelegate & persistentStorage, ConstFabricIterator first, 135 : ConstFabricIterator last) 136 : { 137 1 : ChipLogProgress(DataManagement, "DefaultAclStorage: initializing"); 138 : 139 : CHIP_ERROR err; 140 : 141 1 : size_t count = 0; 142 : 143 1 : for (auto it = first; it != last; ++it) 144 : { 145 0 : auto fabric = it->GetFabricIndex(); 146 0 : for (size_t index = 0; /**/; ++index) 147 : { 148 0 : uint8_t buffer[kEncodedEntryTotalBytes] = { 0 }; 149 0 : uint16_t size = static_cast<uint16_t>(sizeof(buffer)); 150 0 : err = persistentStorage.SyncGetKeyValue(DefaultStorageKeyAllocator::AccessControlAclEntry(fabric, index).KeyName(), 151 : buffer, size); 152 0 : if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) 153 : { 154 0 : break; 155 : } 156 0 : SuccessOrExit(err); 157 : 158 : TLV::TLVReader reader; 159 0 : reader.Init(buffer, size); 160 0 : SuccessOrExit(err = reader.Next()); 161 : 162 0 : DecodableEntry decodableEntry; 163 0 : SuccessOrExit(err = decodableEntry.Decode(reader)); 164 : 165 0 : Entry & entry = decodableEntry.GetEntry(); 166 0 : SuccessOrExit(err = entry.SetFabricIndex(fabric)); 167 : 168 0 : SuccessOrExit(err = GetAccessControl().CreateEntry(nullptr, fabric, nullptr, entry)); 169 0 : count++; 170 0 : } 171 : } 172 : 173 1 : ChipLogProgress(DataManagement, "DefaultAclStorage: %u entries loaded", (unsigned) count); 174 : 175 1 : sEntryListener.Init(persistentStorage); 176 1 : GetAccessControl().AddEntryListener(sEntryListener); 177 : 178 1 : return CHIP_NO_ERROR; 179 : 180 0 : exit: 181 0 : ChipLogError(DataManagement, "DefaultAclStorage: failed %" CHIP_ERROR_FORMAT, err.Format()); 182 0 : return err; 183 : } 184 : 185 : } // namespace app 186 : } // namespace chip