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