| 1406 | } |
| 1407 | |
| 1408 | static int private_directory_tree_open(const char *directory_path) { |
| 1409 | if (!directory_path || !directory_path[0] || O_DIRECTORY == 0 || O_NOFOLLOW == 0) { |
| 1410 | return -1; |
| 1411 | } |
| 1412 | char *path = private_log_directory_path_copy(directory_path); |
| 1413 | if (!path) { |
| 1414 | return -1; |
| 1415 | } |
| 1416 | bool absolute = path[0] == '/'; |
| 1417 | int current_fd = open(absolute ? "/" : ".", O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); |
| 1418 | bool ok = current_fd >= 0 && fd_set_cloexec(current_fd); |
| 1419 | char *cursor = path; |
| 1420 | while (ok && *cursor == '/') { |
| 1421 | cursor++; |
| 1422 | } |
| 1423 | bool visited = false; |
| 1424 | while (ok && *cursor) { |
| 1425 | char *component = cursor; |
| 1426 | while (*cursor && *cursor != '/') { |
| 1427 | cursor++; |
| 1428 | } |
| 1429 | char saved = *cursor; |
| 1430 | *cursor = '\0'; |
| 1431 | if (strcmp(component, ".") == 0) { |
| 1432 | /* Relative paths may contain a harmless explicit current-dir |
| 1433 | * component. Parent traversal is never valid for private logs. */ |
| 1434 | } else if (strcmp(component, "..") == 0 || !component[0]) { |
| 1435 | ok = false; |
| 1436 | } else { |
| 1437 | ok = posix_directory_parent_secure(current_fd); |
| 1438 | bool created = ok && mkdirat(current_fd, component, 0700) == 0; |
| 1439 | if (!created && errno != EEXIST) { |
| 1440 | ok = false; |
| 1441 | } |
| 1442 | int next_fd = |
| 1443 | ok ? openat(current_fd, component, O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW) |
| 1444 | : -1; |
| 1445 | struct stat status; |
| 1446 | ok = next_fd >= 0 && fd_set_cloexec(next_fd) && fstat(next_fd, &status) == 0 && |
| 1447 | S_ISDIR(status.st_mode) && posix_directory_transition_secure(current_fd, next_fd); |
| 1448 | if (ok && created) { |
| 1449 | ok = status.st_uid == geteuid() && fchmod(next_fd, 0700) == 0 && |
| 1450 | cbm_macos_extended_acl_fd_clear(next_fd) && |
| 1451 | cbm_macos_extended_acl_fd_is_empty(next_fd); |
| 1452 | } |
| 1453 | if (ok) { |
| 1454 | (void)close(current_fd); |
| 1455 | current_fd = next_fd; |
| 1456 | visited = true; |
| 1457 | } else if (next_fd >= 0) { |
| 1458 | (void)close(next_fd); |
| 1459 | } |
| 1460 | } |
| 1461 | *cursor = saved; |
| 1462 | while (*cursor == '/') { |
| 1463 | cursor++; |
| 1464 | } |
| 1465 | } |
no test coverage detected