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/AclStorage.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 Entry = AccessControl::Entry;
27 : using EntryListener = AccessControl::EntryListener;
28 : using StagingAuthMode = Clusters::AccessControl::AccessControlEntryAuthModeEnum;
29 : using StagingPrivilege = Clusters::AccessControl::AccessControlEntryPrivilegeEnum;
30 : using StagingAuxiliaryType = Clusters::AccessControl::AccessControlAuxiliaryTypeEnum;
31 : using StagingTarget = Clusters::AccessControl::Structs::AccessControlTargetStruct::Type;
32 : using Target = AccessControl::Entry::Target;
33 :
34 : namespace {
35 :
36 : struct StagingSubject
37 : {
38 : NodeId nodeId;
39 : StagingAuthMode authMode;
40 : };
41 :
42 0 : CHIP_ERROR Convert(AuthMode from, StagingAuthMode & to)
43 : {
44 0 : switch (from)
45 : {
46 0 : case AuthMode::kPase:
47 0 : to = StagingAuthMode::kPase;
48 0 : break;
49 0 : case AuthMode::kCase:
50 0 : to = StagingAuthMode::kCase;
51 0 : break;
52 0 : case AuthMode::kGroup:
53 0 : to = StagingAuthMode::kGroup;
54 0 : break;
55 0 : default:
56 0 : return CHIP_ERROR_INVALID_ARGUMENT;
57 : }
58 0 : return CHIP_NO_ERROR;
59 : }
60 :
61 0 : CHIP_ERROR Convert(StagingAuthMode from, AuthMode & to)
62 : {
63 0 : switch (from)
64 : {
65 0 : case StagingAuthMode::kPase:
66 0 : to = AuthMode::kPase;
67 0 : break;
68 0 : case StagingAuthMode::kCase:
69 0 : to = AuthMode::kCase;
70 0 : break;
71 0 : case StagingAuthMode::kGroup:
72 0 : to = AuthMode::kGroup;
73 0 : break;
74 0 : default:
75 0 : return CHIP_ERROR_INVALID_ARGUMENT;
76 : }
77 0 : return CHIP_NO_ERROR;
78 : }
79 :
80 0 : CHIP_ERROR Convert(Privilege from, StagingPrivilege & to)
81 : {
82 0 : switch (from)
83 : {
84 0 : case Privilege::kView:
85 0 : to = StagingPrivilege::kView;
86 0 : break;
87 0 : case Privilege::kProxyView:
88 0 : to = StagingPrivilege::kProxyView;
89 0 : break;
90 0 : case Privilege::kOperate:
91 0 : to = StagingPrivilege::kOperate;
92 0 : break;
93 0 : case Privilege::kManage:
94 0 : to = StagingPrivilege::kManage;
95 0 : break;
96 0 : case Privilege::kAdminister:
97 0 : to = StagingPrivilege::kAdminister;
98 0 : break;
99 0 : default:
100 0 : return CHIP_ERROR_INVALID_ARGUMENT;
101 : }
102 0 : return CHIP_NO_ERROR;
103 : }
104 :
105 0 : CHIP_ERROR Convert(StagingPrivilege from, Privilege & to)
106 : {
107 0 : switch (from)
108 : {
109 0 : case StagingPrivilege::kView:
110 0 : to = Privilege::kView;
111 0 : break;
112 0 : case StagingPrivilege::kProxyView:
113 0 : to = Privilege::kProxyView;
114 0 : break;
115 0 : case StagingPrivilege::kOperate:
116 0 : to = Privilege::kOperate;
117 0 : break;
118 0 : case StagingPrivilege::kManage:
119 0 : to = Privilege::kManage;
120 0 : break;
121 0 : case StagingPrivilege::kAdminister:
122 0 : to = Privilege::kAdminister;
123 0 : break;
124 0 : default:
125 0 : return CHIP_ERROR_INVALID_ARGUMENT;
126 : }
127 0 : return CHIP_NO_ERROR;
128 : }
129 :
130 0 : CHIP_ERROR Convert(AuxiliaryType from, StagingAuxiliaryType & to)
131 : {
132 0 : switch (from)
133 : {
134 0 : case AuxiliaryType::kSystem:
135 0 : to = StagingAuxiliaryType::kSystem;
136 0 : break;
137 0 : case AuxiliaryType::kGroupcast:
138 0 : to = StagingAuxiliaryType::kGroupcast;
139 0 : break;
140 0 : default:
141 0 : return CHIP_ERROR_INVALID_ARGUMENT;
142 : }
143 0 : return CHIP_NO_ERROR;
144 : }
145 :
146 0 : CHIP_ERROR Convert(StagingAuxiliaryType from, AuxiliaryType & to)
147 : {
148 0 : switch (from)
149 : {
150 0 : case StagingAuxiliaryType::kSystem:
151 0 : to = AuxiliaryType::kSystem;
152 0 : break;
153 0 : case StagingAuxiliaryType::kGroupcast:
154 0 : to = AuxiliaryType::kGroupcast;
155 0 : break;
156 0 : default:
157 0 : return CHIP_ERROR_INVALID_ARGUMENT;
158 : }
159 0 : return CHIP_NO_ERROR;
160 : }
161 :
162 0 : CHIP_ERROR Convert(NodeId from, StagingSubject & to)
163 : {
164 0 : if (IsOperationalNodeId(from) || IsCASEAuthTag(from))
165 : {
166 0 : to = { .nodeId = from, .authMode = StagingAuthMode::kCase };
167 : }
168 0 : else if (IsGroupId(from))
169 : {
170 0 : to = { .nodeId = GroupIdFromNodeId(from), .authMode = StagingAuthMode::kGroup };
171 : }
172 0 : else if (IsPAKEKeyId(from))
173 : {
174 0 : to = { .nodeId = PAKEKeyIdFromNodeId(from), .authMode = StagingAuthMode::kPase };
175 : }
176 : else
177 : {
178 0 : return CHIP_ERROR_INVALID_ARGUMENT;
179 : }
180 0 : return CHIP_NO_ERROR;
181 : }
182 :
183 0 : CHIP_ERROR Convert(StagingSubject from, NodeId & to)
184 : {
185 0 : switch (from.authMode)
186 : {
187 0 : case StagingAuthMode::kPase:
188 0 : VerifyOrReturnError((from.nodeId & ~kMaskPAKEKeyId) == 0, CHIP_ERROR_INVALID_ARGUMENT);
189 0 : to = NodeIdFromPAKEKeyId(static_cast<PasscodeId>(from.nodeId));
190 0 : break;
191 0 : case StagingAuthMode::kCase:
192 0 : to = from.nodeId;
193 0 : break;
194 0 : case StagingAuthMode::kGroup:
195 0 : VerifyOrReturnError((from.nodeId & ~kMaskGroupId) == 0, CHIP_ERROR_INVALID_ARGUMENT);
196 0 : to = NodeIdFromGroupId(static_cast<GroupId>(from.nodeId));
197 0 : break;
198 0 : default:
199 0 : return CHIP_ERROR_INVALID_ARGUMENT;
200 : }
201 0 : return CHIP_NO_ERROR;
202 : }
203 :
204 0 : CHIP_ERROR Convert(const Target & from, StagingTarget & to)
205 : {
206 0 : if ((from.flags & Target::kCluster) != 0)
207 : {
208 0 : to.cluster.SetNonNull(from.cluster);
209 : }
210 : else
211 : {
212 0 : to.cluster.SetNull();
213 : }
214 0 : if ((from.flags & Target::kEndpoint) != 0)
215 : {
216 0 : to.endpoint.SetNonNull(from.endpoint);
217 : }
218 : else
219 : {
220 0 : to.endpoint.SetNull();
221 : }
222 0 : if ((from.flags & Target::kDeviceType) != 0)
223 : {
224 0 : to.deviceType.SetNonNull(from.deviceType);
225 : }
226 : else
227 : {
228 0 : to.deviceType.SetNull();
229 : }
230 0 : return CHIP_NO_ERROR;
231 : }
232 :
233 0 : CHIP_ERROR Convert(const StagingTarget & from, Target & to)
234 : {
235 0 : to.flags = 0;
236 0 : if (!from.cluster.IsNull())
237 : {
238 0 : to.flags |= Target::kCluster;
239 0 : to.cluster = from.cluster.Value();
240 : }
241 0 : if (!from.endpoint.IsNull())
242 : {
243 0 : to.flags |= Target::kEndpoint;
244 0 : to.endpoint = from.endpoint.Value();
245 : }
246 0 : if (!from.deviceType.IsNull())
247 : {
248 0 : to.flags |= Target::kDeviceType;
249 0 : to.deviceType = from.deviceType.Value();
250 : }
251 0 : return CHIP_NO_ERROR;
252 : }
253 :
254 : } // namespace
255 :
256 : namespace chip {
257 : namespace app {
258 :
259 0 : CHIP_ERROR AclStorage::DecodableEntry::Decode(TLV::TLVReader & reader)
260 : {
261 0 : ReturnErrorOnFailure(mStagingEntry.Decode(reader));
262 0 : ReturnErrorOnFailure(Unstage());
263 0 : return CHIP_NO_ERROR;
264 : }
265 :
266 0 : CHIP_ERROR AclStorage::DecodableEntry::Unstage()
267 : {
268 0 : ReturnErrorOnFailure(GetAccessControl().PrepareEntry(mEntry));
269 :
270 0 : ReturnErrorOnFailure(mEntry.SetFabricIndex(mStagingEntry.fabricIndex));
271 :
272 : {
273 : Privilege privilege;
274 0 : ReturnErrorOnFailure(Convert(mStagingEntry.privilege, privilege));
275 0 : ReturnErrorOnFailure(mEntry.SetPrivilege(privilege));
276 : }
277 :
278 : {
279 : AuthMode authMode;
280 0 : ReturnErrorOnFailure(Convert(mStagingEntry.authMode, authMode));
281 0 : ReturnErrorOnFailure(mEntry.SetAuthMode(authMode));
282 : }
283 :
284 0 : if (mStagingEntry.auxiliaryType.HasValue())
285 : {
286 : AuxiliaryType auxiliaryType;
287 0 : ReturnErrorOnFailure(Convert(mStagingEntry.auxiliaryType.Value(), auxiliaryType));
288 0 : ReturnErrorOnFailure(mEntry.SetAuxiliaryType(auxiliaryType));
289 : }
290 :
291 0 : if (!mStagingEntry.subjects.IsNull())
292 : {
293 0 : auto iterator = mStagingEntry.subjects.Value().begin();
294 0 : while (iterator.Next())
295 : {
296 0 : StagingSubject tmp = { .nodeId = iterator.GetValue(), .authMode = mStagingEntry.authMode };
297 : NodeId subject;
298 0 : ReturnErrorOnFailure(Convert(tmp, subject));
299 0 : ReturnErrorOnFailure(mEntry.AddSubject(nullptr, subject));
300 : }
301 0 : ReturnErrorOnFailure(iterator.GetStatus());
302 : }
303 :
304 0 : if (!mStagingEntry.targets.IsNull())
305 : {
306 0 : auto iterator = mStagingEntry.targets.Value().begin();
307 0 : while (iterator.Next())
308 : {
309 0 : Target target;
310 0 : ReturnErrorOnFailure(Convert(iterator.GetValue(), target));
311 0 : ReturnErrorOnFailure(mEntry.AddTarget(nullptr, target));
312 : }
313 0 : ReturnErrorOnFailure(iterator.GetStatus());
314 : }
315 :
316 0 : return CHIP_NO_ERROR;
317 : }
318 :
319 0 : CHIP_ERROR AclStorage::EncodableEntry::EncodeForRead(TLV::TLVWriter & writer, TLV::Tag tag, FabricIndex fabric) const
320 : {
321 0 : ReturnErrorOnFailure(Stage());
322 0 : ReturnErrorOnFailure(mStagingEntry.EncodeForRead(writer, tag, fabric));
323 0 : return CHIP_NO_ERROR;
324 : }
325 :
326 0 : CHIP_ERROR AclStorage::EncodableEntry::EncodeForWrite(TLV::TLVWriter & writer, TLV::Tag tag) const
327 : {
328 0 : ReturnErrorOnFailure(Stage());
329 0 : ReturnErrorOnFailure(mStagingEntry.EncodeForWrite(writer, tag));
330 0 : return CHIP_NO_ERROR;
331 : }
332 :
333 0 : CHIP_ERROR AclStorage::EncodableEntry::Stage() const
334 : {
335 0 : ReturnErrorOnFailure(mEntry.GetFabricIndex(mStagingEntry.fabricIndex));
336 :
337 : {
338 : Privilege privilege;
339 0 : ReturnErrorOnFailure(mEntry.GetPrivilege(privilege));
340 0 : ReturnErrorOnFailure(Convert(privilege, mStagingEntry.privilege));
341 : }
342 :
343 : {
344 : AuthMode authMode;
345 0 : ReturnErrorOnFailure(mEntry.GetAuthMode(authMode));
346 0 : ReturnErrorOnFailure(Convert(authMode, mStagingEntry.authMode));
347 : }
348 :
349 : {
350 : AuxiliaryType auxiliaryType;
351 0 : CHIP_ERROR err = mEntry.GetAuxiliaryType(auxiliaryType);
352 0 : if (err == CHIP_NO_ERROR)
353 : {
354 : StagingAuxiliaryType stagingAuxiliaryType;
355 0 : ReturnErrorOnFailure(Convert(auxiliaryType, stagingAuxiliaryType));
356 0 : mStagingEntry.auxiliaryType.SetValue(stagingAuxiliaryType);
357 : }
358 0 : else if (err != CHIP_ERROR_NOT_IMPLEMENTED)
359 : {
360 : // CHIP_ERROR_NOT_IMPLEMENTED is okay since this field is optional, and doesn't
361 : // need to be set in all cases (the implementation will be up to the delegate).
362 : // Any other sort of error is unexepcted so we return it here.
363 0 : return err;
364 : }
365 : }
366 :
367 : {
368 : size_t count;
369 0 : ReturnErrorOnFailure(mEntry.GetSubjectCount(count));
370 0 : if (count > 0)
371 : {
372 0 : for (size_t i = 0; i < count; ++i)
373 : {
374 : NodeId subject;
375 0 : ReturnErrorOnFailure(mEntry.GetSubject(i, subject));
376 : StagingSubject tmp;
377 0 : ReturnErrorOnFailure(Convert(subject, tmp));
378 0 : mStagingSubjects[i] = tmp.nodeId;
379 : }
380 0 : mStagingEntry.subjects.SetNonNull(mStagingSubjects, count);
381 : }
382 : else
383 : {
384 0 : mStagingEntry.subjects.SetNull();
385 : }
386 : }
387 :
388 : {
389 : size_t count;
390 0 : ReturnErrorOnFailure(mEntry.GetTargetCount(count));
391 0 : if (count > 0)
392 : {
393 0 : for (size_t i = 0; i < count; ++i)
394 : {
395 0 : Target target;
396 0 : ReturnErrorOnFailure(mEntry.GetTarget(i, target));
397 0 : ReturnErrorOnFailure(Convert(target, mStagingTargets[i]));
398 : }
399 0 : mStagingEntry.targets.SetNonNull(mStagingTargets, count);
400 : }
401 : else
402 : {
403 0 : mStagingEntry.targets.SetNull();
404 : }
405 : }
406 :
407 0 : return CHIP_NO_ERROR;
408 : }
409 :
410 : } // namespace app
411 : } // namespace chip
|