1 /*
2 * Copyright (C) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "coauth.h"
17
18 #include "securec.h"
19
20 #include "adaptor_algorithm.h"
21 #include "adaptor_log.h"
22 #include "adaptor_memory.h"
23 #include "pool.h"
24
25 #ifdef IAM_TEST_ENABLE
26 #define IAM_STATIC
27 #else
28 #define IAM_STATIC static
29 #endif
30
31 // Used to cache the ongoing coAuth scheduling.
32 IAM_STATIC LinkedList *g_scheduleList = NULL;
33
IsCoAuthInit(void)34 IAM_STATIC bool IsCoAuthInit(void)
35 {
36 return g_scheduleList != NULL;
37 }
38
DestroyScheduleNode(void * data)39 void DestroyScheduleNode(void *data)
40 {
41 if (data == NULL) {
42 LOG_ERROR("get null data");
43 return;
44 }
45 CoAuthSchedule *schedule = (CoAuthSchedule *)data;
46 if (schedule->templateIds.data != NULL) {
47 Free(schedule->templateIds.data);
48 schedule->templateIds.data = NULL;
49 }
50 Free(schedule);
51 }
52
CopyCoAuthSchedule(const CoAuthSchedule * coAuthSchedule)53 CoAuthSchedule *CopyCoAuthSchedule(const CoAuthSchedule *coAuthSchedule)
54 {
55 if (coAuthSchedule == NULL || !IsTemplateArraysValid(&(coAuthSchedule->templateIds))) {
56 LOG_ERROR("coAuthSchedule is invalid");
57 return NULL;
58 }
59 CoAuthSchedule *schedule = (CoAuthSchedule *)Malloc(sizeof(CoAuthSchedule));
60 if (schedule == NULL) {
61 LOG_ERROR("schedule is null");
62 return NULL;
63 }
64 if (memcpy_s(schedule, sizeof(CoAuthSchedule), coAuthSchedule, sizeof(CoAuthSchedule)) != EOK) {
65 LOG_ERROR("copy schedule failed");
66 Free(schedule);
67 return NULL;
68 }
69 schedule->templateIds.data = NULL;
70 schedule->templateIds.len = 0;
71 ResultCode ret = CopyTemplateArrays(&(coAuthSchedule->templateIds), &(schedule->templateIds));
72 if (ret != RESULT_SUCCESS) {
73 LOG_ERROR("copy templateIds failed");
74 Free(schedule);
75 return NULL;
76 }
77 return schedule;
78 }
79
DestroyCoAuthSchedule(CoAuthSchedule * coAuthSchedule)80 void DestroyCoAuthSchedule(CoAuthSchedule *coAuthSchedule)
81 {
82 if (coAuthSchedule == NULL) {
83 return;
84 }
85 DestroyScheduleNode(coAuthSchedule);
86 }
87
InitCoAuth(void)88 ResultCode InitCoAuth(void)
89 {
90 if (!IsCoAuthInit()) {
91 g_scheduleList = CreateLinkedList(DestroyScheduleNode);
92 }
93 if (g_scheduleList == NULL) {
94 return RESULT_GENERAL_ERROR;
95 }
96 return RESULT_SUCCESS;
97 }
98
DestoryCoAuth(void)99 void DestoryCoAuth(void)
100 {
101 DestroyLinkedList(g_scheduleList);
102 g_scheduleList = NULL;
103 }
104
AddCoAuthSchedule(const CoAuthSchedule * coAuthSchedule)105 ResultCode AddCoAuthSchedule(const CoAuthSchedule *coAuthSchedule)
106 {
107 if (!IsCoAuthInit()) {
108 LOG_ERROR("pool not init");
109 return RESULT_NEED_INIT;
110 }
111 if (coAuthSchedule == NULL) {
112 LOG_ERROR("get null schedule");
113 return RESULT_BAD_PARAM;
114 }
115 CoAuthSchedule *schedule = CopyCoAuthSchedule(coAuthSchedule);
116 if (schedule == NULL) {
117 LOG_ERROR("no memory");
118 return RESULT_NO_MEMORY;
119 }
120 if (g_scheduleList->getSize(g_scheduleList) >= MAX_SCHEDULE_NUM) {
121 LOG_ERROR("too many schedules already");
122 DestroyCoAuthSchedule(schedule);
123 return RESULT_GENERAL_ERROR;
124 }
125 ResultCode result = g_scheduleList->insert(g_scheduleList, schedule);
126 if (result != RESULT_SUCCESS) {
127 LOG_ERROR("insert failed");
128 DestroyCoAuthSchedule(schedule);
129 }
130 LOG_INFO("success");
131 return result;
132 }
133
IsScheduleMatch(const void * data,const void * condition)134 IAM_STATIC bool IsScheduleMatch(const void *data, const void *condition)
135 {
136 if ((condition == NULL) || (data == NULL)) {
137 LOG_ERROR("get null data");
138 return false;
139 }
140 uint64_t scheduleId = *(const uint64_t *)condition;
141 const CoAuthSchedule *coAuthSchedule = (const CoAuthSchedule *)data;
142 return (coAuthSchedule->scheduleId == scheduleId);
143 }
144
RemoveCoAuthSchedule(uint64_t scheduleId)145 ResultCode RemoveCoAuthSchedule(uint64_t scheduleId)
146 {
147 if (!IsCoAuthInit()) {
148 LOG_ERROR("pool not init");
149 return RESULT_NEED_INIT;
150 }
151 return g_scheduleList->remove(g_scheduleList, (void *)&scheduleId, IsScheduleMatch, true);
152 }
153
GetCoAuthSchedule(uint64_t scheduleId)154 const CoAuthSchedule *GetCoAuthSchedule(uint64_t scheduleId)
155 {
156 if (!IsCoAuthInit()) {
157 LOG_ERROR("pool not init");
158 return NULL;
159 }
160 LinkedListIterator *iterator = g_scheduleList->createIterator(g_scheduleList);
161 if (iterator == NULL) {
162 LOG_ERROR("create iterator failed");
163 return NULL;
164 }
165 CoAuthSchedule *schedule = NULL;
166 while (iterator->hasNext(iterator)) {
167 schedule = (CoAuthSchedule *)iterator->next(iterator);
168 if (schedule == NULL) {
169 LOG_ERROR("list node is null, please check");
170 continue;
171 }
172 if (schedule->scheduleId != scheduleId) {
173 continue;
174 }
175 g_scheduleList->destroyIterator(iterator);
176 return schedule;
177 }
178 g_scheduleList->destroyIterator(iterator);
179 LOG_ERROR("can't find this schedule");
180 return NULL;
181 }
182
IsScheduleIdDuplicate(uint64_t scheduleId)183 IAM_STATIC bool IsScheduleIdDuplicate(uint64_t scheduleId)
184 {
185 LinkedListNode *temp = g_scheduleList->head;
186 CoAuthSchedule *schedule = NULL;
187 while (temp != NULL) {
188 schedule = (CoAuthSchedule *)temp->data;
189 if (schedule != NULL && schedule->scheduleId == scheduleId) {
190 return true;
191 }
192 temp = temp->next;
193 }
194
195 return false;
196 }
197
GenerateValidScheduleId(uint64_t * scheduleId)198 IAM_STATIC ResultCode GenerateValidScheduleId(uint64_t *scheduleId)
199 {
200 if (g_scheduleList == NULL) {
201 LOG_ERROR("g_poolList is null");
202 return RESULT_BAD_PARAM;
203 }
204
205 for (uint32_t i = 0; i < MAX_DUPLICATE_CHECK; ++i) {
206 uint64_t tempRandom;
207 if (SecureRandom((uint8_t *)&tempRandom, sizeof(uint64_t)) != RESULT_SUCCESS) {
208 LOG_ERROR("get random failed");
209 return RESULT_GENERAL_ERROR;
210 }
211 if (!IsScheduleIdDuplicate(tempRandom)) {
212 *scheduleId = tempRandom;
213 return RESULT_SUCCESS;
214 }
215 }
216
217 LOG_ERROR("a rare failure");
218 return RESULT_GENERAL_ERROR;
219 }
220
MountExecutorOnce(const LinkedList * executors,CoAuthSchedule * coAuthSchedule,uint32_t sensorHint,uint32_t executorRole,Uint8Array deviceUdid)221 IAM_STATIC ResultCode MountExecutorOnce(const LinkedList *executors, CoAuthSchedule *coAuthSchedule,
222 uint32_t sensorHint, uint32_t executorRole, Uint8Array deviceUdid)
223 {
224 LinkedListNode *tempNode = executors->head;
225 while (tempNode != NULL) {
226 if (tempNode->data == NULL) {
227 LOG_ERROR("data is null");
228 return RESULT_UNKNOWN;
229 }
230 ExecutorInfoHal *executor = (ExecutorInfoHal *)tempNode->data;
231 if (executor->executorRole != executorRole) {
232 tempNode = tempNode->next;
233 continue;
234 }
235 if (sensorHint != INVALID_SENSOR_HINT && sensorHint != executor->executorSensorHint) {
236 tempNode = tempNode->next;
237 continue;
238 }
239
240 if (memcmp(deviceUdid.data, executor->deviceUdid, UDID_LEN) != 0) {
241 tempNode = tempNode->next;
242 continue;
243 }
244 coAuthSchedule->executors[coAuthSchedule->executorSize] = *executor;
245 ++(coAuthSchedule->executorSize);
246 return RESULT_SUCCESS;
247 }
248 LOG_ERROR("mount executor failed");
249 return RESULT_NOT_FOUND;
250 }
251
MountExecutor(const ScheduleParam * param,CoAuthSchedule * coAuthSchedule)252 IAM_STATIC ResultCode MountExecutor(const ScheduleParam *param, CoAuthSchedule *coAuthSchedule)
253 {
254 ExecutorCondition condition = {};
255 SetExecutorConditionAuthType(&condition, param->authType);
256 if (param->collectorSensorHint != INVALID_SENSOR_HINT || param->verifierSensorHint != INVALID_SENSOR_HINT) {
257 SetExecutorConditionExecutorMatcher(&condition, param->executorMatcher);
258 }
259 LinkedList *executors = QueryExecutor(&condition);
260 if (executors == NULL) {
261 LOG_ERROR("query executor failed");
262 return RESULT_UNKNOWN;
263 }
264
265 Uint8Array localUdidArray = { .data = (uint8_t *)(param->localUdid), .len = UDID_LEN };
266 Uint8Array collectorUdidArray = { .data = (uint8_t *)(param->collectorUdid), .len = UDID_LEN };
267 ResultCode ret;
268 LOG_INFO("collectorSensorHint: %{public}u, verifierSensorHint: %{public}u", param->collectorSensorHint,
269 param->verifierSensorHint);
270 if ((param->collectorSensorHint == INVALID_SENSOR_HINT || param->verifierSensorHint == INVALID_SENSOR_HINT ||
271 param->collectorSensorHint == param->verifierSensorHint) &&
272 memcmp(param->localUdid, param->collectorUdid, UDID_LEN) == 0) {
273 uint32_t allInOneSensorHint = param->verifierSensorHint | param->collectorSensorHint;
274 LOG_INFO("mount all-in-one executor");
275 ret = MountExecutorOnce(executors, coAuthSchedule, allInOneSensorHint, ALL_IN_ONE, localUdidArray);
276 if (ret != RESULT_SUCCESS) {
277 LOG_INFO("all-in-one executor is not found");
278 }
279 goto EXIT;
280 }
281
282 LOG_INFO("mount verifier and collector");
283 if (param->scheduleMode == SCHEDULE_MODE_IDENTIFY) {
284 LOG_ERROR("identification only supports all in one");
285 ret = RESULT_GENERAL_ERROR;
286 goto EXIT;
287 }
288 ret = MountExecutorOnce(executors, coAuthSchedule, param->verifierSensorHint, VERIFIER, localUdidArray);
289 if (ret != RESULT_SUCCESS) {
290 LOG_ERROR("verifier is not found");
291 goto EXIT;
292 }
293
294 ret = MountExecutorOnce(executors, coAuthSchedule, param->collectorSensorHint, COLLECTOR, collectorUdidArray);
295 if (ret != RESULT_SUCCESS) {
296 LOG_ERROR("collector is not found");
297 }
298
299 EXIT:
300 DestroyLinkedList(executors);
301 return ret;
302 }
303
GetScheduleVerifierSensorHint(const CoAuthSchedule * coAuthSchedule)304 uint32_t GetScheduleVerifierSensorHint(const CoAuthSchedule *coAuthSchedule)
305 {
306 if (coAuthSchedule == NULL) {
307 LOG_ERROR("coAuthSchedule is null");
308 return INVALID_SENSOR_HINT;
309 }
310 for (uint32_t i = 0; i < coAuthSchedule->executorSize; ++i) {
311 const ExecutorInfoHal *executor = coAuthSchedule->executors + i;
312 if (executor->executorRole == VERIFIER || executor->executorRole == ALL_IN_ONE) {
313 return executor->executorSensorHint;
314 }
315 }
316 LOG_ERROR("not found");
317 return INVALID_SENSOR_HINT;
318 }
319
GenerateSchedule(const ScheduleParam * param)320 CoAuthSchedule *GenerateSchedule(const ScheduleParam *param)
321 {
322 if (param == NULL) {
323 LOG_ERROR("param is invalid");
324 return NULL;
325 }
326 CoAuthSchedule *coAuthSchedule = Malloc(sizeof(CoAuthSchedule));
327 if (coAuthSchedule == NULL) {
328 LOG_ERROR("coAuthSchedule is null");
329 return NULL;
330 }
331 if (memset_s(coAuthSchedule, sizeof(CoAuthSchedule), 0, sizeof(CoAuthSchedule)) != EOK) {
332 LOG_ERROR("reset coAuthSchedule failed");
333 Free(coAuthSchedule);
334 return NULL;
335 }
336 ResultCode ret = GenerateValidScheduleId(&coAuthSchedule->scheduleId);
337 if (ret != RESULT_SUCCESS) {
338 LOG_ERROR("get scheduleId failed");
339 goto FAIL;
340 }
341 coAuthSchedule->associateId = param->associateId;
342 coAuthSchedule->scheduleMode = param->scheduleMode;
343 coAuthSchedule->authType = param->authType;
344 coAuthSchedule->userType = param->userType;
345 if (param->templateIds != NULL) {
346 ret = CopyTemplateArrays(param->templateIds, &(coAuthSchedule->templateIds));
347 if (ret != RESULT_SUCCESS) {
348 LOG_ERROR("copy template failed");
349 goto FAIL;
350 }
351 }
352
353 ret = MountExecutor(param, coAuthSchedule);
354 if (ret != RESULT_SUCCESS) {
355 LOG_ERROR("mount failed");
356 goto FAIL;
357 }
358 return coAuthSchedule;
359 FAIL:
360 DestroyCoAuthSchedule(coAuthSchedule);
361 return NULL;
362 }
363
IsTemplateArraysValid(const Uint64Array * templateIds)364 bool IsTemplateArraysValid(const Uint64Array *templateIds)
365 {
366 if (templateIds == NULL) {
367 LOG_ERROR("templateIds is null");
368 return false;
369 }
370 if (templateIds->len > MAX_TEMPLATE_OF_SCHEDULE || (templateIds->len != 0 && templateIds->data == NULL)) {
371 LOG_ERROR("templateIds's content is invalid");
372 return false;
373 }
374 return true;
375 }
376
CopyTemplateArrays(const Uint64Array * in,Uint64Array * out)377 ResultCode CopyTemplateArrays(const Uint64Array *in, Uint64Array *out)
378 {
379 if (!IsTemplateArraysValid(in) || out == NULL || out->data != NULL) {
380 LOG_ERROR("param is invalid");
381 return RESULT_BAD_PARAM;
382 }
383 if (in->len == 0) {
384 out->len = 0;
385 return RESULT_SUCCESS;
386 }
387 out->len = in->len;
388 out->data = (uint64_t *)Malloc(sizeof(uint64_t) * out->len);
389 if (out->data == NULL) {
390 LOG_ERROR("out data is null");
391 out->len = 0;
392 return RESULT_NO_MEMORY;
393 }
394 if (memcpy_s(out->data, (sizeof(uint64_t) * out->len), in->data, (sizeof(uint64_t) * in->len)) != EOK) {
395 LOG_ERROR("copy failed");
396 Free(out->data);
397 out->data = NULL;
398 out->len = 0;
399 return RESULT_BAD_COPY;
400 }
401 return RESULT_SUCCESS;
402 }