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