blob: 03ebc7a13419062a6ffe59d86dfd651d7434e285 [file] [log] [blame]
Marc Lepagead2520a2022-04-29 15:17:17 -04001/*
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/AclStorage.h>
19
20#include <lib/support/DefaultStorageKeyAllocator.h>
21
22using namespace chip;
23using namespace chip::app;
24using namespace chip::Access;
25
Marc Lepagead2520a2022-04-29 15:17:17 -040026using Entry = AccessControl::Entry;
27using EntryListener = AccessControl::EntryListener;
Boris Zbarsky28cb6cc2023-01-04 04:46:21 -050028using StagingAuthMode = Clusters::AccessControl::AccessControlEntryAuthModeEnum;
29using StagingPrivilege = Clusters::AccessControl::AccessControlEntryPrivilegeEnum;
Boris Zbarskyf9731a82023-05-24 15:08:53 -040030using StagingTarget = Clusters::AccessControl::Structs::AccessControlTargetStruct::Type;
Marc Lepagead2520a2022-04-29 15:17:17 -040031using Target = AccessControl::Entry::Target;
32
33namespace {
34
Marc Lepagead2520a2022-04-29 15:17:17 -040035struct StagingSubject
36{
37 NodeId nodeId;
38 StagingAuthMode authMode;
39};
40
41CHIP_ERROR Convert(AuthMode from, StagingAuthMode & to)
42{
43 switch (from)
44 {
45 case AuthMode::kPase:
46 to = StagingAuthMode::kPase;
47 break;
48 case AuthMode::kCase:
49 to = StagingAuthMode::kCase;
50 break;
51 case AuthMode::kGroup:
52 to = StagingAuthMode::kGroup;
53 break;
54 default:
55 return CHIP_ERROR_INVALID_ARGUMENT;
56 }
57 return CHIP_NO_ERROR;
58}
59
60CHIP_ERROR Convert(StagingAuthMode from, AuthMode & to)
61{
62 switch (from)
63 {
64 case StagingAuthMode::kPase:
65 to = AuthMode::kPase;
66 break;
67 case StagingAuthMode::kCase:
68 to = AuthMode::kCase;
69 break;
70 case StagingAuthMode::kGroup:
71 to = AuthMode::kGroup;
72 break;
73 default:
74 return CHIP_ERROR_INVALID_ARGUMENT;
75 }
76 return CHIP_NO_ERROR;
77}
78
79CHIP_ERROR Convert(Privilege from, StagingPrivilege & to)
80{
81 switch (from)
82 {
83 case Privilege::kView:
84 to = StagingPrivilege::kView;
85 break;
86 case Privilege::kProxyView:
87 to = StagingPrivilege::kProxyView;
88 break;
89 case Privilege::kOperate:
90 to = StagingPrivilege::kOperate;
91 break;
92 case Privilege::kManage:
93 to = StagingPrivilege::kManage;
94 break;
95 case Privilege::kAdminister:
96 to = StagingPrivilege::kAdminister;
97 break;
98 default:
99 return CHIP_ERROR_INVALID_ARGUMENT;
100 }
101 return CHIP_NO_ERROR;
102}
103
104CHIP_ERROR Convert(StagingPrivilege from, Privilege & to)
105{
106 switch (from)
107 {
108 case StagingPrivilege::kView:
109 to = Privilege::kView;
110 break;
111 case StagingPrivilege::kProxyView:
112 to = Privilege::kProxyView;
113 break;
114 case StagingPrivilege::kOperate:
115 to = Privilege::kOperate;
116 break;
117 case StagingPrivilege::kManage:
118 to = Privilege::kManage;
119 break;
120 case StagingPrivilege::kAdminister:
121 to = Privilege::kAdminister;
122 break;
123 default:
124 return CHIP_ERROR_INVALID_ARGUMENT;
125 }
126 return CHIP_NO_ERROR;
127}
128
129CHIP_ERROR Convert(NodeId from, StagingSubject & to)
130{
131 if (IsOperationalNodeId(from) || IsCASEAuthTag(from))
132 {
133 to = { .nodeId = from, .authMode = StagingAuthMode::kCase };
134 }
135 else if (IsGroupId(from))
136 {
137 to = { .nodeId = GroupIdFromNodeId(from), .authMode = StagingAuthMode::kGroup };
138 }
139 else if (IsPAKEKeyId(from))
140 {
141 to = { .nodeId = PAKEKeyIdFromNodeId(from), .authMode = StagingAuthMode::kPase };
142 }
143 else
144 {
145 return CHIP_ERROR_INVALID_ARGUMENT;
146 }
147 return CHIP_NO_ERROR;
148}
149
150CHIP_ERROR Convert(StagingSubject from, NodeId & to)
151{
152 switch (from.authMode)
153 {
154 case StagingAuthMode::kPase:
155 ReturnErrorCodeIf((from.nodeId & ~kMaskPAKEKeyId) != 0, CHIP_ERROR_INVALID_ARGUMENT);
156 to = NodeIdFromPAKEKeyId(static_cast<PasscodeId>(from.nodeId));
157 break;
158 case StagingAuthMode::kCase:
159 to = from.nodeId;
160 break;
161 case StagingAuthMode::kGroup:
162 ReturnErrorCodeIf((from.nodeId & ~kMaskGroupId) != 0, CHIP_ERROR_INVALID_ARGUMENT);
163 to = NodeIdFromGroupId(static_cast<GroupId>(from.nodeId));
164 break;
165 default:
166 return CHIP_ERROR_INVALID_ARGUMENT;
167 }
168 return CHIP_NO_ERROR;
169}
170
171CHIP_ERROR Convert(const Target & from, StagingTarget & to)
172{
173 if ((from.flags & Target::kCluster) != 0)
174 {
175 to.cluster.SetNonNull(from.cluster);
176 }
177 else
178 {
179 to.cluster.SetNull();
180 }
181 if ((from.flags & Target::kEndpoint) != 0)
182 {
183 to.endpoint.SetNonNull(from.endpoint);
184 }
185 else
186 {
187 to.endpoint.SetNull();
188 }
189 if ((from.flags & Target::kDeviceType) != 0)
190 {
191 to.deviceType.SetNonNull(from.deviceType);
192 }
193 else
194 {
195 to.deviceType.SetNull();
196 }
197 return CHIP_NO_ERROR;
198}
199
200CHIP_ERROR Convert(const StagingTarget & from, Target & to)
201{
202 to.flags = 0;
203 if (!from.cluster.IsNull())
204 {
205 to.flags |= Target::kCluster;
206 to.cluster = from.cluster.Value();
207 }
208 if (!from.endpoint.IsNull())
209 {
210 to.flags |= Target::kEndpoint;
211 to.endpoint = from.endpoint.Value();
212 }
213 if (!from.deviceType.IsNull())
214 {
215 to.flags |= Target::kDeviceType;
216 to.deviceType = from.deviceType.Value();
217 }
218 return CHIP_NO_ERROR;
219}
220
Marc Lepagead2520a2022-04-29 15:17:17 -0400221} // namespace
222
223namespace chip {
224namespace app {
225
226CHIP_ERROR AclStorage::DecodableEntry::Decode(TLV::TLVReader & reader)
227{
228 ReturnErrorOnFailure(mStagingEntry.Decode(reader));
229 ReturnErrorOnFailure(Unstage());
230 return CHIP_NO_ERROR;
231}
232
233CHIP_ERROR AclStorage::DecodableEntry::Unstage()
234{
235 ReturnErrorOnFailure(GetAccessControl().PrepareEntry(mEntry));
236
237 ReturnErrorOnFailure(mEntry.SetFabricIndex(mStagingEntry.fabricIndex));
238
239 {
240 Privilege privilege;
241 ReturnErrorOnFailure(Convert(mStagingEntry.privilege, privilege));
242 ReturnErrorOnFailure(mEntry.SetPrivilege(privilege));
243 }
244
245 {
246 AuthMode authMode;
247 ReturnErrorOnFailure(Convert(mStagingEntry.authMode, authMode));
248 ReturnErrorOnFailure(mEntry.SetAuthMode(authMode));
249 }
250
251 if (!mStagingEntry.subjects.IsNull())
252 {
253 auto iterator = mStagingEntry.subjects.Value().begin();
254 while (iterator.Next())
255 {
256 StagingSubject tmp = { .nodeId = iterator.GetValue(), .authMode = mStagingEntry.authMode };
257 NodeId subject;
258 ReturnErrorOnFailure(Convert(tmp, subject));
259 ReturnErrorOnFailure(mEntry.AddSubject(nullptr, subject));
260 }
261 ReturnErrorOnFailure(iterator.GetStatus());
262 }
263
264 if (!mStagingEntry.targets.IsNull())
265 {
266 auto iterator = mStagingEntry.targets.Value().begin();
267 while (iterator.Next())
268 {
269 Target target;
270 ReturnErrorOnFailure(Convert(iterator.GetValue(), target));
271 ReturnErrorOnFailure(mEntry.AddTarget(nullptr, target));
272 }
273 ReturnErrorOnFailure(iterator.GetStatus());
274 }
275
276 return CHIP_NO_ERROR;
277}
278
279CHIP_ERROR AclStorage::EncodableEntry::EncodeForRead(TLV::TLVWriter & writer, TLV::Tag tag, FabricIndex fabric) const
280{
281 ReturnErrorOnFailure(Stage());
282 ReturnErrorOnFailure(mStagingEntry.EncodeForRead(writer, tag, fabric));
283 return CHIP_NO_ERROR;
284}
285
286CHIP_ERROR AclStorage::EncodableEntry::EncodeForWrite(TLV::TLVWriter & writer, TLV::Tag tag) const
287{
288 ReturnErrorOnFailure(Stage());
289 ReturnErrorOnFailure(mStagingEntry.EncodeForWrite(writer, tag));
290 return CHIP_NO_ERROR;
291}
292
293CHIP_ERROR AclStorage::EncodableEntry::Stage() const
294{
295 ReturnErrorOnFailure(mEntry.GetFabricIndex(mStagingEntry.fabricIndex));
296
297 {
298 Privilege privilege;
299 ReturnErrorOnFailure(mEntry.GetPrivilege(privilege));
300 ReturnErrorOnFailure(Convert(privilege, mStagingEntry.privilege));
301 }
302
303 {
304 AuthMode authMode;
305 ReturnErrorOnFailure(mEntry.GetAuthMode(authMode));
306 ReturnErrorOnFailure(Convert(authMode, mStagingEntry.authMode));
307 }
308
309 {
310 size_t count;
311 ReturnErrorOnFailure(mEntry.GetSubjectCount(count));
312 if (count > 0)
313 {
314 for (size_t i = 0; i < count; ++i)
315 {
316 NodeId subject;
317 ReturnErrorOnFailure(mEntry.GetSubject(i, subject));
318 StagingSubject tmp;
319 ReturnErrorOnFailure(Convert(subject, tmp));
320 mStagingSubjects[i] = tmp.nodeId;
321 }
322 mStagingEntry.subjects.SetNonNull(mStagingSubjects, count);
323 }
324 else
325 {
326 mStagingEntry.subjects.SetNull();
327 }
328 }
329
330 {
331 size_t count;
332 ReturnErrorOnFailure(mEntry.GetTargetCount(count));
333 if (count > 0)
334 {
335 for (size_t i = 0; i < count; ++i)
336 {
337 Target target;
338 ReturnErrorOnFailure(mEntry.GetTarget(i, target));
339 ReturnErrorOnFailure(Convert(target, mStagingTargets[i]));
340 }
341 mStagingEntry.targets.SetNonNull(mStagingTargets, count);
342 }
343 else
344 {
345 mStagingEntry.targets.SetNull();
346 }
347 }
348
349 return CHIP_NO_ERROR;
350}
351
Marc Lepagead2520a2022-04-29 15:17:17 -0400352} // namespace app
353} // namespace chip