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