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 : }
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 : [[maybe_unused]] 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 0 : 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
|