1 /*
2  * Copyright (c) 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 "cert_manager_file_operator.h"
17 
18 #include <dirent.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 
25 #include "securec.h"
26 
27 #include "cert_manager_mem.h"
28 #include "cert_manager_storage.h"
29 #include "cert_manager_updateflag.h"
30 #include "cm_log.h"
31 
GetFileName(const char * path,const char * fileName,char * fullFileName,uint32_t fullFileNameLen)32 static int32_t GetFileName(const char *path, const char *fileName, char *fullFileName, uint32_t fullFileNameLen)
33 {
34     if (path != NULL && strlen(path) > 0) {
35         if (strncpy_s(fullFileName, fullFileNameLen, path, strlen(path)) != EOK) {
36             return CMR_ERROR_INVALID_OPERATION;
37         }
38 
39         if (path[strlen(path) - 1] != '/') {
40             if (strncat_s(fullFileName, fullFileNameLen, "/", strlen("/")) != EOK) {
41                 return CMR_ERROR_INVALID_OPERATION;
42             }
43         }
44 
45         if (strncat_s(fullFileName, fullFileNameLen, fileName, strlen(fileName)) != EOK) {
46             return CMR_ERROR_INVALID_OPERATION;
47         }
48     } else {
49         if (strncpy_s(fullFileName, fullFileNameLen, fileName, strlen(fileName)) != EOK) {
50             return CMR_ERROR_INVALID_OPERATION;
51         }
52     }
53     return CMR_OK;
54 }
55 
GetFullFileName(const char * path,const char * fileName,char ** fullFileName)56 static int32_t GetFullFileName(const char *path, const char *fileName, char **fullFileName)
57 {
58     uint32_t nameLen = CM_MAX_FILE_NAME_LEN;
59     char *tmpFileName = (char *)CMMalloc(nameLen);
60     if (tmpFileName == NULL) {
61         return CMR_ERROR_MALLOC_FAIL;
62     }
63     (void)memset_s(tmpFileName, nameLen, 0, nameLen);
64 
65     int32_t ret = GetFileName(path, fileName, tmpFileName, nameLen);
66     if (ret != CMR_OK) {
67         CM_LOG_E("get full fileName failed");
68         CM_FREE_PTR(tmpFileName);
69         return ret;
70     }
71     *fullFileName = tmpFileName;
72 
73     return CMR_OK;
74 }
75 
IsFileExist(const char * fileName)76 static int32_t IsFileExist(const char *fileName)
77 {
78     if (access(fileName, F_OK) != 0) {
79         return CMR_ERROR_NOT_EXIST;
80     }
81 
82     return CMR_OK;
83 }
84 
CmIsDirExist(const char * path)85 int32_t CmIsDirExist(const char *path)
86 {
87     if (path == NULL) {
88         return CMR_ERROR_NULL_POINTER;
89     }
90     return IsFileExist(path);
91 }
92 
FileRead(const char * fileName,uint32_t offset,uint8_t * buf,uint32_t len)93 static uint32_t FileRead(const char *fileName, uint32_t offset, uint8_t *buf, uint32_t len)
94 {
95     (void)offset;
96     if (IsFileExist(fileName) != CMR_OK) {
97         return 0;
98     }
99     if (strstr(fileName, "../") != NULL) {
100         CM_LOG_E("invalid filePath");
101         return 0;
102     }
103 
104     char filePath[PATH_MAX + 1] = {0};
105     if (realpath(fileName, filePath) == NULL) {
106         CM_LOG_E("invalid filepath: %s", fileName);
107         return 0;
108     }
109 
110     FILE *fp = fopen(filePath, "rb");
111     if (fp == NULL) {
112         CM_LOG_E("failed to open file");
113         return 0;
114     }
115 
116     uint32_t size = fread(buf, 1, len, fp);
117     if (fclose(fp) < 0) {
118         CM_LOG_E("failed to close file");
119         return 0;
120     }
121 
122     return size;
123 }
124 
FileSize(const char * fileName)125 static uint32_t FileSize(const char *fileName)
126 {
127     if (IsFileExist(fileName) != CMR_OK) {
128         return 0;
129     }
130 
131     struct stat fileStat;
132     (void)memset_s(&fileStat, sizeof(fileStat), 0, sizeof(fileStat));
133 
134     if (stat(fileName, &fileStat) != 0) {
135         CM_LOG_E("file stat fail.");
136         return 0;
137     }
138 
139     return (uint32_t)fileStat.st_size;
140 }
141 
FileWrite(const char * fileName,uint32_t offset,const uint8_t * buf,uint32_t len,bool isWriteBakFile)142 static int32_t FileWrite(const char *fileName, uint32_t offset, const uint8_t *buf, uint32_t len, bool isWriteBakFile)
143 {
144     (void)offset;
145     char filePath[PATH_MAX + 1] = {0};
146     if (memcpy_s(filePath, sizeof(filePath) - 1, fileName, strlen(fileName)) != EOK) {
147         return CMR_ERROR_INVALID_OPERATION;
148     }
149     if (strstr(filePath, "../") != NULL) {
150         CM_LOG_E("invalid filePath");
151         return CMR_ERROR_NOT_EXIST;
152     }
153     /* Ignore return value: realpath will return null in musl c when the file does not exist */
154     (void)realpath(fileName, filePath);
155 
156     int32_t fd;
157     if (isWriteBakFile) {
158         fd = open(filePath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
159     } else {
160         fd = open(filePath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
161     }
162     if (fd < 0) {
163         CM_LOG_E("open file failed, errno = 0x%x", errno);
164         return CMR_ERROR_OPEN_FILE_FAIL;
165     }
166 
167     int32_t size = write(fd, buf, len);
168     if (size < 0) {
169         CM_LOG_E("write file failed, errno = 0x%x", errno);
170         close(fd);
171         return CMR_ERROR_WRITE_FILE_FAIL;
172     }
173     if (fsync(fd) < 0) {
174         CM_LOG_E("sync file failed");
175         close(fd);
176         return CMR_ERROR_WRITE_FILE_FAIL;
177     }
178     close(fd);
179     return CMR_OK;
180 }
181 
FileRemove(const char * fileName)182 static int32_t FileRemove(const char *fileName)
183 {
184     int32_t ret = IsFileExist(fileName);
185     if (ret != CMR_OK) {
186         return CMR_OK; /* if file not exist, return ok */
187     }
188 
189     struct stat tmp;
190     if (stat(fileName, &tmp) != 0) {
191         return CMR_ERROR_INVALID_OPERATION;
192     }
193 
194     if (S_ISDIR(tmp.st_mode)) {
195         return CMR_ERROR_INVALID_ARGUMENT;
196     }
197 
198     if ((unlink(fileName) != 0) && (errno != ENOENT)) {
199         CM_LOG_E("failed to remove file: errno = 0x%x", errno);
200         return CMR_ERROR_REMOVE_FILE_FAIL;
201     }
202 
203     return CMR_OK;
204 }
205 
CmFileRemove(const char * path,const char * fileName)206 int32_t CmFileRemove(const char *path, const char *fileName)
207 {
208     if (fileName == NULL) {
209         return CMR_ERROR_INVALID_ARGUMENT;
210     }
211 
212     char *fullFileName = NULL;
213     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
214     if (ret != CMR_OK) {
215         return ret;
216     }
217 
218     ret = FileRemove(fullFileName);
219     CM_FREE_PTR(fullFileName);
220     return ret;
221 }
222 
CmMakeDir(const char * path)223 int32_t CmMakeDir(const char *path)
224 {
225     if ((access(path, F_OK)) != -1) {
226         return CMR_OK;
227     }
228 
229     if (mkdir(path, S_IRWXU) == 0) {
230         return CMR_OK;
231     } else {
232         if (errno == EEXIST || errno == EAGAIN) {
233             return CMR_ERROR_ALREADY_EXISTS;
234         } else {
235             return CMR_ERROR_MAKE_DIR_FAIL;
236         }
237     }
238 }
239 
CmUserBakupMakeDir(const char * path,const mode_t * mode)240 int32_t CmUserBakupMakeDir(const char *path, const mode_t *mode)
241 {
242     mode_t modeTmp = S_IRWXU | S_IROTH | S_IXOTH; /* The default directory permission is 0705 */
243 
244     if ((access(path, F_OK)) != -1) {
245         return CMR_OK;
246     }
247 
248     if (mode != NULL) {
249         modeTmp = *mode;
250     }
251     if (mkdir(path, modeTmp) == 0) {
252         return CMR_OK;
253     } else {
254         if (errno == EEXIST || errno == EAGAIN) {
255             return CMR_ERROR_ALREADY_EXISTS;
256         } else {
257             return CMR_ERROR_MAKE_DIR_FAIL;
258         }
259     }
260 }
261 
CmOpenDir(const char * path)262 void *CmOpenDir(const char *path)
263 {
264     return (void *)opendir(path);
265 }
266 
CmCloseDir(void * dirp)267 int32_t CmCloseDir(void *dirp)
268 {
269     return closedir((DIR *)dirp);
270 }
271 
CmGetDirFile(void * dirp,struct CmFileDirentInfo * direntInfo)272 int32_t CmGetDirFile(void *dirp, struct CmFileDirentInfo *direntInfo)
273 {
274     DIR *dir = (DIR *)dirp;
275     struct dirent *dire = readdir(dir);
276 
277     while (dire != NULL) {
278         if (dire->d_type != DT_REG) { /* only care about files. */
279             dire = readdir(dir);
280             continue;
281         }
282 
283         uint32_t len = strlen(dire->d_name);
284         if (memcpy_s(direntInfo->fileName, sizeof(direntInfo->fileName) - 1, dire->d_name, len) != EOK) {
285             return CMR_ERROR_INVALID_OPERATION;
286         }
287         direntInfo->fileName[len] = '\0';
288         return CMR_OK;
289     }
290 
291     return CMR_ERROR_NOT_EXIST;
292 }
293 
CmFileRead(const char * path,const char * fileName,uint32_t offset,uint8_t * buf,uint32_t len)294 uint32_t CmFileRead(const char *path, const char *fileName, uint32_t offset, uint8_t *buf, uint32_t len)
295 {
296     if ((fileName == NULL) || (buf == NULL) || (len == 0)) {
297         return 0;
298     }
299 
300     char *fullFileName = NULL;
301     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
302     if (ret != CMR_OK) {
303         return 0;
304     }
305 
306     uint32_t size = FileRead(fullFileName, offset, buf, len);
307     CM_FREE_PTR(fullFileName);
308     return size;
309 }
310 
CmFileWrite(const char * path,const char * fileName,uint32_t offset,const uint8_t * buf,uint32_t len)311 int32_t CmFileWrite(const char *path, const char *fileName, uint32_t offset, const uint8_t *buf, uint32_t len)
312 {
313     if ((fileName == NULL) || (buf == NULL) || (len == 0)) {
314         return CMR_ERROR_INVALID_ARGUMENT;
315     }
316 
317     char *fullFileName = NULL;
318     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
319     if (ret != CMR_OK) {
320         return ret;
321     }
322 
323     ret = FileWrite(fullFileName, offset, buf, len, false);
324     CM_FREE_PTR(fullFileName);
325     return ret;
326 }
327 
CmUserBackupFileWrite(const char * path,const char * fileName,uint32_t offset,const uint8_t * buf,uint32_t len)328 int32_t CmUserBackupFileWrite(const char *path, const char *fileName, uint32_t offset, const uint8_t *buf, uint32_t len)
329 {
330     if ((fileName == NULL) || (buf == NULL) || (len == 0)) {
331         return CMR_ERROR_INVALID_ARGUMENT;
332     }
333 
334     char *fullFileName = NULL;
335     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
336     if (ret != CMR_OK) {
337         return ret;
338     }
339 
340     ret = FileWrite(fullFileName, offset, buf, len, true);
341     CM_FREE_PTR(fullFileName);
342     return ret;
343 }
344 
CmFileSize(const char * path,const char * fileName)345 uint32_t CmFileSize(const char *path, const char *fileName)
346 {
347     if (fileName == NULL) {
348         CM_LOG_E("fileName is NULL");
349         return 0;
350     }
351 
352     char *fullFileName = NULL;
353     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
354     if (ret != CMR_OK) {
355         CM_LOG_E("GetFullFileName failed");
356         return 0;
357     }
358 
359     uint32_t size = FileSize(fullFileName);
360     CM_FREE_PTR(fullFileName);
361     return size;
362 }
363 
CmUidLayerGetFileNames(const char * filePath,struct CmBlob * fileNames,const uint32_t arraySize,uint32_t count)364 static int32_t CmUidLayerGetFileNames(const char *filePath, struct CmBlob *fileNames,
365     const uint32_t arraySize, uint32_t count)
366 {
367     if (count >= arraySize) {
368         return CMR_ERROR_BUFFER_TOO_SMALL;
369     }
370     uint32_t filePathLen = strlen(filePath);
371     if (filePathLen >= CM_MAX_FILE_NAME_LEN) {
372         CM_LOG_E("CmUidLayerGetFileNames filePathLen:%u", filePathLen);
373         return CMR_ERROR_BUFFER_TOO_SMALL;
374     }
375 
376     fileNames[count].data = (uint8_t *)CMMalloc(filePathLen + 1);
377     if (fileNames[count].data == NULL) {
378         return CMR_ERROR_MALLOC_FAIL;
379     }
380     (void)memset_s(fileNames[count].data, filePathLen + 1, 0, filePathLen + 1);
381     if (memcpy_s(fileNames[count].data, CM_MAX_FILE_NAME_LEN, filePath, filePathLen) != EOK) {
382         /* fileNames memory free in top layer function */
383         return CMR_ERROR_BUFFER_TOO_SMALL;
384     }
385     fileNames[count].size = filePathLen + 1; /* include '\0' at end */
386     return CM_SUCCESS;
387 }
388 
CmUidLayerGetFileCountAndNames(const char * path,struct CmBlob * fileNames,const uint32_t arraySize,uint32_t * fileCount)389 int32_t CmUidLayerGetFileCountAndNames(const char *path, struct CmBlob *fileNames,
390     const uint32_t arraySize, uint32_t *fileCount)
391 {
392     /* do nothing when dir is not exist */
393     if (CmIsDirExist(path) != CMR_OK) {
394         CM_LOG_D("Uid layer dir is not exist");
395         return CM_SUCCESS;
396     }
397     DIR *dir = opendir(path);
398     if (dir == NULL) {
399         CM_LOG_E("open uid layer dir failed");
400         return CMR_ERROR_OPEN_FILE_FAIL;
401     }
402 
403     int32_t ret = CM_SUCCESS;
404     uint32_t count = *fileCount;
405     struct dirent *dire = readdir(dir);
406     while (dire != NULL) {
407         char uidPath[CM_MAX_FILE_NAME_LEN] = {0};
408         if (strncpy_s(uidPath, sizeof(uidPath), path, strlen(path)) != EOK) {
409             ret = CMR_ERROR_INVALID_OPERATION;
410             break;
411         }
412 
413         if (uidPath[strlen(uidPath) - 1] != '/') {
414             if (strncat_s(uidPath, sizeof(uidPath), "/", strlen("/")) != EOK) {
415                 ret = CMR_ERROR_INVALID_OPERATION;
416                 break;
417             }
418         }
419 
420         if (strncat_s(uidPath, sizeof(uidPath), dire->d_name, strlen(dire->d_name)) != EOK) {
421             ret = CMR_ERROR_INVALID_OPERATION;
422             break;
423         }
424 
425         if ((dire->d_type == DT_REG) && (strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0)) {
426             ret = CmUidLayerGetFileNames(uidPath, fileNames, arraySize, count);
427             if (ret != CM_SUCCESS) {
428                 break;
429             }
430             count++;
431         }
432         dire = readdir(dir);
433     }
434     *fileCount = count;
435     closedir(dir);
436     return ret;
437 }
438 
CmUserIdLayerGetFileCountAndNames(const char * path,struct CmBlob * fileNames,const uint32_t arraySize,uint32_t * fileCount)439 int32_t CmUserIdLayerGetFileCountAndNames(const char *path, struct CmBlob *fileNames,
440     const uint32_t arraySize, uint32_t *fileCount)
441 {
442     char userIdPath[CM_MAX_FILE_NAME_LEN] = { 0 };
443     /* do nothing when dir is not exist */
444     if (CmIsDirExist(path) != CMR_OK) {
445         CM_LOG_D("UserId layer dir is not exist");
446         return CM_SUCCESS;
447     }
448     DIR *dir = opendir(path);
449     if (dir  == NULL) {
450         CM_LOG_E("open userId layer dir failed");
451         return CMR_ERROR_OPEN_FILE_FAIL;
452     }
453     struct dirent *dire = readdir(dir);
454     while (dire != NULL) {
455         (void)memset_s(userIdPath, CM_MAX_FILE_NAME_LEN, 0, CM_MAX_FILE_NAME_LEN);
456         if (strncpy_s(userIdPath, sizeof(userIdPath), path, strlen(path)) != EOK) {
457             closedir(dir);
458             return CMR_ERROR_INVALID_OPERATION;
459         }
460 
461         if (userIdPath[strlen(userIdPath) - 1] != '/') {
462             if (strncat_s(userIdPath, sizeof(userIdPath), "/", strlen("/")) != EOK) {
463                 closedir(dir);
464                 return CMR_ERROR_INVALID_OPERATION;
465             }
466         }
467 
468         if (strncat_s(userIdPath, sizeof(userIdPath), dire->d_name, strlen(dire->d_name)) != EOK) {
469             closedir(dir);
470             return CMR_ERROR_INVALID_OPERATION;
471         }
472 
473         if ((dire->d_type == DT_DIR) && (strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0)) {
474             if (CmUidLayerGetFileCountAndNames(userIdPath, fileNames, arraySize, fileCount) != CM_SUCCESS) {
475                 CM_LOG_E("CmUidLayerGetFileCountAndNames faild");
476                 closedir(dir);
477                 return CM_FAILURE;
478             }
479         } else if (dire->d_type != DT_DIR) {
480             (void)remove(userIdPath);
481         }
482         dire = readdir(dir);
483     }
484     closedir(dir);
485     return CM_SUCCESS;
486 }
487 
CmIsFileExist(const char * path,const char * fileName)488 int32_t CmIsFileExist(const char *path, const char *fileName)
489 {
490     if (fileName == NULL) {
491         CM_LOG_E("fileName is NULL");
492         return CMR_ERROR_INVALID_ARGUMENT;
493     }
494 
495     char *fullFileName = NULL;
496     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
497     if (ret != CM_SUCCESS) {
498         CM_LOG_E("GetFullFileName failed");
499         return ret;
500     }
501 
502     ret = IsFileExist(fullFileName);
503     CM_FREE_PTR(fullFileName);
504     return ret;
505 }
506 
CmGetSubDir(void * dirp,struct CmFileDirentInfo * direntInfo)507 int32_t CmGetSubDir(void *dirp, struct CmFileDirentInfo *direntInfo)
508 {
509     DIR *dir = (DIR *)dirp;
510     struct dirent *dire = readdir(dir);
511 
512     while (dire != NULL) {
513         if ((dire->d_type != DT_DIR) || (strcmp(dire->d_name, ".") == 0) ||
514             (strcmp(dire->d_name, "..") == 0)) {
515             dire = readdir(dir);
516             continue;
517         }
518 
519         uint32_t dirLen = strlen(dire->d_name);
520         if (memcpy_s(direntInfo->fileName, sizeof(direntInfo->fileName) - 1, dire->d_name, dirLen) != EOK) {
521             return CMR_ERROR_INVALID_OPERATION;
522         }
523         direntInfo->fileName[dirLen] = '\0';
524         return CMR_OK;
525     }
526 
527     return CMR_ERROR_NOT_EXIST;
528 }
529 
DirRemove(const char * path)530 static int32_t DirRemove(const char *path)
531 {
532     if (access(path, F_OK) != 0) {
533         return CMR_ERROR_NOT_EXIST;
534     }
535 
536     struct stat tmp;
537     if (stat(path, &tmp) != 0) {
538         return CMR_ERROR_INVALID_OPERATION;
539     }
540 
541     if (S_ISDIR(tmp.st_mode)) {
542         uint32_t i = 0;
543         struct dirent *dire = NULL;
544         DIR *dirp = opendir(path);
545         if (dirp == NULL) {
546             CM_LOG_E("open dir failed");
547             return CMR_ERROR_OPEN_FILE_FAIL;
548         }
549         while ((dire = readdir(dirp)) != NULL) {
550             if ((strcmp(dire->d_name, ".") == 0) || (strcmp(dire->d_name, "..") == 0)) {
551                 continue;
552             }
553             i++;
554         }
555         closedir(dirp);
556 
557         if (i != 0) {
558             CM_LOG_E("Dir is not empty");
559             return CMR_ERROR_INVALID_ARGUMENT;
560         }
561         rmdir(path);
562         return CMR_OK;
563     }
564     return CMR_ERROR_INVALID_ARGUMENT;
565 }
566 
CmDirRemove(const char * path)567 int32_t CmDirRemove(const char *path)
568 {
569     if (path == NULL) {
570         return CMR_ERROR_INVALID_ARGUMENT;
571     }
572 
573     return DirRemove(path);
574 }
575