1 /*
2  * Copyright (c) 2021-2022 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 "cm_event_process.h"
17 
18 #include <dirent.h>
19 #include <sys/stat.h>
20 
21 #include "securec.h"
22 
23 #include "cert_manager.h"
24 #include "cert_manager_auth_mgr.h"
25 #include "cert_manager_file_operator.h"
26 #include "cert_manager_key_operation.h"
27 #include "cert_manager_session_mgr.h"
28 #include "cert_manager_status.h"
29 #include "cert_manager_storage.h"
30 #include "cm_log.h"
31 #include "cm_type.h"
32 
DeleteAuth(const struct CmContext * context,const char * fileName,bool isDeleteByUid)33 static void DeleteAuth(const struct CmContext *context, const char *fileName, bool isDeleteByUid)
34 {
35     CM_LOG_D("isDeleteByUid:%d", isDeleteByUid);
36     struct CmBlob keyUri = { strlen(fileName) + 1, (uint8_t *)fileName };
37 
38     int32_t ret;
39     if (isDeleteByUid) {
40         ret = CmAuthDeleteAuthInfoByUid(context->userId, context->uid, &keyUri);
41     } else {
42         ret = CmAuthDeleteAuthInfoByUserId(context->userId, &keyUri);
43     }
44     if (ret != CM_SUCCESS) {
45         CM_LOG_E("delete auth info failed ret: %d", ret); /* only record logs */
46     }
47     return;
48 }
49 
CmTraversalDirActionCredential(const char * filePath,const char * fileName)50 static int32_t CmTraversalDirActionCredential(const char *filePath, const char *fileName)
51 {
52     int32_t ret = remove(filePath);
53     if (ret != CM_SUCCESS) {
54         CM_LOG_E("App cert delete faild, ret: %d", ret);
55         return ret;
56     }
57 
58     struct CmBlob keyUri = { strlen(fileName) + 1, (uint8_t *)fileName };
59     ret = CmKeyOpDeleteKey(&keyUri);
60     if (ret != CM_SUCCESS) { /* ignore the return of delete key */
61         CM_LOG_E("App key delete failed ret: %d", ret);
62     }
63 
64     return CM_SUCCESS;
65 }
66 
CmTraversalDirActionUserCa(const struct CmContext * context,const char * filePath,const char * fileName,const uint32_t store)67 static int32_t CmTraversalDirActionUserCa(const struct CmContext *context, const char *filePath, const char *fileName,
68     const uint32_t store)
69 {
70     int32_t ret = remove(filePath);
71     if (ret != CM_SUCCESS) {
72         CM_LOG_E("User cert delete faild, ret: %d", ret);
73         return ret;
74     }
75 
76     struct CmBlob certUri = { strlen(fileName) + 1, (uint8_t *)fileName }; /* include '\0' at end. */
77     struct CmMutableBlob pathBlob = { strlen(filePath) + 1, (uint8_t *)filePath };
78     ret = CmSetStatusEnable(context, &pathBlob, &certUri, store);
79     if (ret != CM_SUCCESS) {
80         CM_LOG_E("User set status faild, ret: %d", ret);
81         return ret;
82     }
83 
84     return CM_SUCCESS;
85 }
86 
CmTraversalDirAction(const struct CmContext * context,const char * filePath,const char * fileName,const uint32_t store)87 static int32_t CmTraversalDirAction(const struct CmContext *context, const char *filePath,
88     const char *fileName, const uint32_t store)
89 {
90     int32_t ret = CM_SUCCESS;
91 
92     switch (store) {
93         case CM_CREDENTIAL_STORE :
94             DeleteAuth(context, fileName, false);
95             __attribute__((fallthrough));
96         case CM_PRI_CREDENTIAL_STORE :
97             ret = CmTraversalDirActionCredential(filePath, fileName);
98             break;
99         case CM_USER_TRUSTED_STORE :
100             ret = CmTraversalDirActionUserCa(context, filePath, fileName, store);
101             break;
102         default:
103             break;
104     }
105     if (ret != CM_SUCCESS) {
106         CM_LOG_E("CmTraversalDirAction failed store:%u", store);
107     }
108 
109     return CM_SUCCESS;
110 }
111 
GetNextLayerPath(const char * path,const char * name,char * outPath,uint32_t outPathLen)112 static int32_t GetNextLayerPath(const char *path, const char *name, char *outPath, uint32_t outPathLen)
113 {
114     if (strncpy_s(outPath, outPathLen, path, strlen(path)) != EOK) {
115         return CMR_ERROR_INVALID_OPERATION;
116     }
117     if (outPath[strlen(outPath) - 1] != '/') {
118         if (strncat_s(outPath, outPathLen, "/", strlen("/")) != EOK) {
119             return CMR_ERROR_INVALID_OPERATION;
120         }
121     }
122     if (strncat_s(outPath, outPathLen, name, strlen(name)) != EOK) {
123         return CMR_ERROR_INVALID_OPERATION;
124     }
125     return CM_SUCCESS;
126 }
127 
RemoveDir(const char * dirPath)128 static int32_t RemoveDir(const char *dirPath)
129 {
130     struct stat fileStat;
131     int32_t ret = stat(dirPath, &fileStat);
132     if (ret != 0) {
133         return CMR_ERROR_INVALID_OPERATION;
134     }
135 
136     if (!S_ISDIR(fileStat.st_mode)) {
137         return CMR_ERROR_INVALID_OPERATION;
138     }
139 
140     DIR *dir = opendir(dirPath);
141     if (dir  == NULL) {
142         return CMR_ERROR_INVALID_OPERATION;
143     }
144 
145     struct dirent *dire = readdir(dir);
146     while (dire != NULL) {
147         if (dire->d_type == DT_REG) { /* only care about files. */
148             ret = CmFileRemove(dirPath, dire->d_name);
149             if (ret != CM_SUCCESS) { /* Continue to delete remaining files */
150                 CM_LOG_E("remove file failed when remove authlist files, ret = %d.", ret);
151             }
152         }
153         dire = readdir(dir);
154     }
155     (void)closedir(dir);
156     (void)remove(dirPath);
157     return CM_SUCCESS;
158 }
159 
RemoveAuthListDir(const char * path,const uint32_t store,bool isSameUid)160 static void RemoveAuthListDir(const char *path, const uint32_t store, bool isSameUid)
161 {
162     if (!isSameUid || (store != CM_CREDENTIAL_STORE)) {
163         return;
164     }
165 
166     char authListPath[CM_MAX_FILE_NAME_LEN] = {0};
167     char name[] = "authlist";
168     int32_t ret = GetNextLayerPath(path, name, authListPath, sizeof(authListPath));
169     if (ret != CM_SUCCESS) {
170         return;
171     }
172 
173     RemoveDir(authListPath);
174 }
175 
TraversalUidLayerDir(const struct CmContext * context,const char * uidPath,const char * direName,const uint32_t store,bool isSameUid)176 static void TraversalUidLayerDir(const struct CmContext *context, const char *uidPath, const char *direName,
177     const uint32_t store, bool isSameUid)
178 {
179     if (!isSameUid) {
180         if (store == CM_CREDENTIAL_STORE) { /* remove deleted uid from authlist */
181             DeleteAuth(context, direName, true);
182         }
183     } else {
184         (void)CmTraversalDirAction(context, uidPath, direName, store);
185     }
186 }
187 
CmTraversalUidLayerDir(const struct CmContext * context,const char * path,const uint32_t store,bool isSameUid)188 static int32_t CmTraversalUidLayerDir(const struct CmContext *context, const char *path,
189     const uint32_t store, bool isSameUid)
190 {
191     int32_t ret = CM_SUCCESS;
192     /* do nothing when dir is not exist */
193     if (CmIsDirExist(path) != CMR_OK) {
194         CM_LOG_D("Dir is not exist");
195         return CM_SUCCESS;
196     }
197 
198     DIR *dir = opendir(path);
199     if (dir  == NULL) {
200         CM_LOG_E("open dir failed");
201         return CMR_ERROR_OPEN_FILE_FAIL;
202     }
203 
204     struct dirent *dire = readdir(dir);
205     while (dire != NULL) {
206         char uidPath[CM_MAX_FILE_NAME_LEN] = {0};
207         if (GetNextLayerPath(path, dire->d_name, uidPath, sizeof(uidPath)) != CM_SUCCESS) {
208             closedir(dir);
209             return CMR_ERROR_INVALID_OPERATION;
210         }
211 
212         if ((strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0) && (dire->d_type == DT_REG)) {
213             TraversalUidLayerDir(context, uidPath, dire->d_name, store, isSameUid);
214         }
215         dire = readdir(dir);
216     }
217     closedir(dir);
218 
219     /* remove authList Path */
220     RemoveAuthListDir(path, store, isSameUid);
221 
222     if (isSameUid) {
223         ret = remove(path);
224     }
225     return ret;
226 }
227 
TraversalUserIdLayerDir(const struct CmContext * context,const char * userIdPath,const char * direName,const uint32_t store,bool isUserDeleteEvent)228 static int32_t TraversalUserIdLayerDir(const struct CmContext *context, const char *userIdPath, const char *direName,
229     const uint32_t store, bool isUserDeleteEvent)
230 {
231     uint32_t uid = (uint32_t)atoi(direName);
232     CM_LOG_D("CmTraversalUserIdLayerDir userId:%u, uid:%u", context->userId, uid);
233 
234     int32_t ret = CM_SUCCESS;
235     if (isUserDeleteEvent) { /* user delete event */
236         struct CmContext userContext = { context->userId, uid, {0} };
237         ret = CmTraversalUidLayerDir(&userContext, userIdPath, store, true);
238     } else { /* package delete event */
239         if (uid == context->uid) {
240             ret = CmTraversalUidLayerDir(context, userIdPath, store, true);
241         } else if (store == CM_CREDENTIAL_STORE) {
242             ret = CmTraversalUidLayerDir(context, userIdPath, store, false);
243         } else {
244             /* do nothing */
245         }
246     }
247     return ret;
248 }
249 
CmTraversalUserIdLayerDir(const struct CmContext * context,const char * path,const uint32_t store)250 static int32_t CmTraversalUserIdLayerDir(const struct CmContext *context, const char *path, const uint32_t store)
251 {
252     bool isUserDeleteEvent = (context->uid == INVALID_VALUE);
253     int32_t ret = CM_SUCCESS;
254 
255     /* do nothing when dir is not exist */
256     if (CmIsDirExist(path) != CMR_OK) {
257         CM_LOG_D("UserId dir is not exist");
258         return CM_SUCCESS;
259     }
260 
261     DIR *dir = opendir(path);
262     if (dir  == NULL) {
263         CM_LOG_E("Open userId dir failed");
264         return CMR_ERROR_OPEN_FILE_FAIL;
265     }
266 
267     struct dirent *dire = readdir(dir);
268     while (dire != NULL) {
269         char userIdPath[CM_MAX_FILE_NAME_LEN] = {0};
270         if (GetNextLayerPath(path, dire->d_name, userIdPath, sizeof(userIdPath)) != CM_SUCCESS) {
271             closedir(dir);
272             return CMR_ERROR_INVALID_OPERATION;
273         }
274 
275         if (dire->d_type == DT_DIR && (strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0)) {
276             (void)TraversalUserIdLayerDir(context, userIdPath, dire->d_name, store, isUserDeleteEvent);
277         } else if (dire->d_type != DT_DIR) {
278             (void)remove(userIdPath);
279         }
280         dire = readdir(dir);
281     }
282     closedir(dir);
283 
284     /* delete userId directory only in user remove event */
285     if (isUserDeleteEvent) {
286         ret = remove(path);
287     }
288 
289     return ret;
290 }
291 
CmTraversalDir(const struct CmContext * context,const char * path,const uint32_t store)292 static int32_t CmTraversalDir(const struct CmContext *context, const char *path, const uint32_t store)
293 {
294     int32_t ret = CM_SUCCESS;
295     /* do nothing when dir is not exist */
296     if (CmIsDirExist(path) != CMR_OK) {
297         CM_LOG_D("Root dir is not exist");
298         return CM_SUCCESS;
299     }
300 
301     DIR *dir = opendir(path);
302     if (dir  == NULL) {
303         CM_LOG_E("open dir failed");
304         return CMR_ERROR_OPEN_FILE_FAIL;
305     }
306 
307     struct dirent *dire = readdir(dir);
308     while (dire != NULL) {
309         char deletePath[CM_MAX_FILE_NAME_LEN] = { 0 };
310         if (GetNextLayerPath(path, dire->d_name, deletePath, sizeof(deletePath)) != CM_SUCCESS) {
311             closedir(dir);
312             return CMR_ERROR_INVALID_OPERATION;
313         }
314 
315         if (dire->d_type == DT_DIR && (strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0) &&
316             ((uint32_t)atoi(dire->d_name) == context->userId)) {
317             ret = CmTraversalUserIdLayerDir(context, deletePath, store);
318         } else if (dire->d_type != DT_DIR) {
319             (void)remove(deletePath);
320         }
321         dire = readdir(dir);
322     }
323     closedir(dir);
324 
325     return ret;
326 }
327 
CmTraversalBackupUidDir(const char * certConfigUidDirPath)328 static int32_t CmTraversalBackupUidDir(const char *certConfigUidDirPath)
329 {
330     if (certConfigUidDirPath == NULL) {
331         CM_LOG_E("input params is invaild");
332         return CMR_ERROR_INVALID_ARGUMENT;
333     }
334 
335     uint32_t fileCounts = 0;
336     struct CmBlob fileNames[MAX_COUNT_CERTIFICATE] = { 0 };
337     /* Gets all files under the certConfigUidDirPath */
338     int32_t ret = CmUidLayerGetFileCountAndNames(certConfigUidDirPath, fileNames, sizeof(fileNames), &fileCounts);
339     if (ret != CM_SUCCESS) {
340         CM_LOG_E("Get file count and names for the certConfigUidDirPath, ret = %d", ret);
341         return ret;
342     }
343 
344     for (uint32_t i = 0; i < fileCounts; i++) {
345         struct CmBlob *certConfigFilePath = &fileNames[i];
346 
347         /* Delete user cert backup and config file */
348         ret = CmRemoveBackupUserCert(NULL, NULL, (const char *)certConfigFilePath->data);
349         if (ret != CM_SUCCESS) {
350             CM_LOG_E("CmRemoveBackupUserCert failed");
351             continue;
352         }
353     }
354 
355     CmFreeFileNames(fileNames, fileCounts);
356 
357     return CM_SUCCESS;
358 }
359 
CmTraversalBackupUserIdDir(const char * certConfigUserIdDirPath)360 static int32_t CmTraversalBackupUserIdDir(const char *certConfigUserIdDirPath)
361 {
362     if (certConfigUserIdDirPath == NULL) {
363         CM_LOG_E("input params is invaild");
364         return CMR_ERROR_INVALID_ARGUMENT;
365     }
366 
367     DIR *dir = opendir(certConfigUserIdDirPath);
368     if (dir == NULL) {
369         CM_LOG_E("opendir certConfigUserIdDirPath failed");
370         return CM_FAILURE;
371     }
372 
373     int32_t ret = CM_SUCCESS;
374     struct dirent *dire = NULL;
375     /* Traverse the {configRootDir}/{userid} directory */
376     while ((dire = readdir(dir)) != NULL) {
377         if ((strcmp(dire->d_name, ".") == 0) || (strcmp(dire->d_name, "..") == 0)) {
378             continue;
379         }
380         char certConfigUidDirPath[CERT_MAX_PATH_LEN] = { 0 };
381         if (snprintf_s(certConfigUidDirPath, CERT_MAX_PATH_LEN, CERT_MAX_PATH_LEN - 1, "%s/%s", certConfigUserIdDirPath,
382                        dire->d_name) < 0) {
383             CM_LOG_E("Construct certConfigUidDirPath failed");
384             continue;
385         }
386 
387         ret = CmTraversalBackupUidDir(certConfigUidDirPath);
388         if (ret != CM_SUCCESS) {
389             CM_LOG_E("CmTraversalBackupUidDir failed, ret = %d", ret);
390             continue;
391         }
392 
393         /* Delete user cert config {configRootDir}/{userid}/{uid} directory */
394         ret = CmDirRemove(certConfigUidDirPath);
395         if (ret != CM_SUCCESS) {
396             CM_LOG_E("Remove user certConfigUidDirPath fail, ret = %d", ret);
397             continue;
398         }
399     };
400 
401     closedir(dir);
402     return CM_SUCCESS;
403 }
404 
CmTraversalBackupUserCert(uint32_t userId)405 static int32_t CmTraversalBackupUserCert(uint32_t userId)
406 {
407     int32_t ret = CM_SUCCESS;
408     char certConfigUserIdDirPath[CERT_MAX_PATH_LEN] = { 0 };
409     ret = CmGetCertConfUserIdDir(userId, certConfigUserIdDirPath, CERT_MAX_PATH_LEN);
410     if (ret != CM_SUCCESS) {
411         CM_LOG_E("Construct certConfigUserIdDirPath(userId: %u) failed", userId);
412         return CM_FAILURE;
413     }
414 
415     ret = CmTraversalBackupUserIdDir(certConfigUserIdDirPath);
416     if (ret != CM_SUCCESS) {
417         CM_LOG_E("CmTraversalBackupUserIdDir failed, ret = %d", ret);
418         return CM_FAILURE;
419     }
420 
421     /* Delete {configRootDir}/{userid} directory */
422     ret = CmDirRemove(certConfigUserIdDirPath);
423     if (ret != CM_SUCCESS) {
424         CM_LOG_E("Remove user certConfigUserIdDirPath fail, ret = %d", ret);
425         return CMR_ERROR_REMOVE_FILE_FAIL;
426     }
427 
428     /* Delete {backupRootDir}/{userid} directory */
429     char certBackupUserIdDirPath[CERT_MAX_PATH_LEN] = { 0 };
430     ret = CmGetCertBackupDir(userId, certBackupUserIdDirPath, CERT_MAX_PATH_LEN);
431     if (ret != CM_SUCCESS) {
432         CM_LOG_E("Construct certBackupUserIdDirPath failed");
433         return CM_FAILURE;
434     }
435     ret = CmDirRemove(certBackupUserIdDirPath);
436     if (ret != CM_SUCCESS) {
437         CM_LOG_E("Remove user certBackupUserIdDirPath fail, ret = %d", ret);
438         return CMR_ERROR_REMOVE_FILE_FAIL;
439     }
440 
441     return CM_SUCCESS;
442 }
443 
RemoveSessionInfo(const struct CmContext * context)444 static void RemoveSessionInfo(const struct CmContext *context)
445 {
446     bool isUserDeleteEvent = (context->uid == INVALID_VALUE);
447 
448     if (isUserDeleteEvent) {
449         /* remove session node by user id */
450         struct CmSessionNodeInfo info = { context->userId, 0, { 0, NULL } };
451         CmDeleteSessionByNodeInfo(DELETE_SESSION_BY_USERID, &info);
452     } else {
453         /* remove session node by uid */
454         struct CmSessionNodeInfo info = { context->userId, context->uid, { 0, NULL } };
455         CmDeleteSessionByNodeInfo(DELETE_SESSION_BY_UID, &info);
456     }
457 }
458 
CmDeleteProcessInfo(const struct CmContext * context)459 int32_t CmDeleteProcessInfo(const struct CmContext *context)
460 {
461     RemoveSessionInfo(context);
462 
463     int32_t ret = CM_SUCCESS;
464     if (context->uid == INVALID_VALUE) { // user delete event
465         /* Delete user ca */
466         ret = CmTraversalDir(context, USER_CA_STORE, CM_USER_TRUSTED_STORE);
467         if (ret != CM_SUCCESS) {
468             CM_LOG_E("CmDeleteUserCa faild");
469         }
470 
471         /* Delete user ca backup and config */
472         ret = CmTraversalBackupUserCert(context->userId);
473         if (ret != CM_SUCCESS) {
474             CM_LOG_E("Delete user ca backup and config file failed");
475         }
476     }
477 
478     /* Delete private credentail */
479     ret = CmTraversalDir(context, APP_CA_STORE, CM_PRI_CREDENTIAL_STORE);
480     if (ret != CM_SUCCESS) {
481         CM_LOG_E("CmDeletePrivateCredential faild");
482     }
483 
484     /* Delete public credentail */
485     ret = CmTraversalDir(context, CREDNTIAL_STORE, CM_CREDENTIAL_STORE);
486     if (ret != CM_SUCCESS) {
487         CM_LOG_E("CmDeletePublicCredential faild");
488     }
489 
490     /* Delete system credentail*/
491     ret = CmTraversalDir(context, SYS_CREDNTIAL_STORE, CM_SYS_CREDENTIAL_STORE);
492     if (ret != CM_SUCCESS) {
493         CM_LOG_E("CmDeletePublicCredential faild");
494     }
495 
496     return ret;
497 }
498