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