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