11cb0ef41Sopenharmony_ci#include "fs_permission.h" 21cb0ef41Sopenharmony_ci#include "base_object-inl.h" 31cb0ef41Sopenharmony_ci#include "debug_utils-inl.h" 41cb0ef41Sopenharmony_ci#include "util.h" 51cb0ef41Sopenharmony_ci#include "v8.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <fcntl.h> 81cb0ef41Sopenharmony_ci#include <limits.h> 91cb0ef41Sopenharmony_ci#include <stdlib.h> 101cb0ef41Sopenharmony_ci#include <algorithm> 111cb0ef41Sopenharmony_ci#include <filesystem> 121cb0ef41Sopenharmony_ci#include <string> 131cb0ef41Sopenharmony_ci#include <string_view> 141cb0ef41Sopenharmony_ci#include <vector> 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_cinamespace { 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_cistd::string WildcardIfDir(const std::string& res) noexcept { 191cb0ef41Sopenharmony_ci uv_fs_t req; 201cb0ef41Sopenharmony_ci int rc = uv_fs_stat(nullptr, &req, res.c_str(), nullptr); 211cb0ef41Sopenharmony_ci if (rc == 0) { 221cb0ef41Sopenharmony_ci const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr); 231cb0ef41Sopenharmony_ci if (s->st_mode & S_IFDIR) { 241cb0ef41Sopenharmony_ci // add wildcard when directory 251cb0ef41Sopenharmony_ci if (res.back() == node::kPathSeparator) { 261cb0ef41Sopenharmony_ci return res + "*"; 271cb0ef41Sopenharmony_ci } 281cb0ef41Sopenharmony_ci return res + node::kPathSeparator + "*"; 291cb0ef41Sopenharmony_ci } 301cb0ef41Sopenharmony_ci } 311cb0ef41Sopenharmony_ci uv_fs_req_cleanup(&req); 321cb0ef41Sopenharmony_ci return res; 331cb0ef41Sopenharmony_ci} 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_civoid FreeRecursivelyNode( 361cb0ef41Sopenharmony_ci node::permission::FSPermission::RadixTree::Node* node) { 371cb0ef41Sopenharmony_ci if (node == nullptr) { 381cb0ef41Sopenharmony_ci return; 391cb0ef41Sopenharmony_ci } 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci if (node->children.size()) { 421cb0ef41Sopenharmony_ci for (auto& c : node->children) { 431cb0ef41Sopenharmony_ci FreeRecursivelyNode(c.second); 441cb0ef41Sopenharmony_ci } 451cb0ef41Sopenharmony_ci } 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci if (node->wildcard_child != nullptr) { 481cb0ef41Sopenharmony_ci delete node->wildcard_child; 491cb0ef41Sopenharmony_ci } 501cb0ef41Sopenharmony_ci delete node; 511cb0ef41Sopenharmony_ci} 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_cibool is_tree_granted(node::permission::FSPermission::RadixTree* granted_tree, 541cb0ef41Sopenharmony_ci const std::string_view& param) { 551cb0ef41Sopenharmony_ci#ifdef _WIN32 561cb0ef41Sopenharmony_ci // is UNC file path 571cb0ef41Sopenharmony_ci if (param.rfind("\\\\", 0) == 0) { 581cb0ef41Sopenharmony_ci // return lookup with normalized param 591cb0ef41Sopenharmony_ci int starting_pos = 4; // "\\?\" 601cb0ef41Sopenharmony_ci if (param.rfind("\\\\?\\UNC\\") == 0) { 611cb0ef41Sopenharmony_ci starting_pos += 4; // "UNC\" 621cb0ef41Sopenharmony_ci } 631cb0ef41Sopenharmony_ci auto normalized = param.substr(starting_pos); 641cb0ef41Sopenharmony_ci return granted_tree->Lookup(normalized, true); 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci#endif 671cb0ef41Sopenharmony_ci return granted_tree->Lookup(param, true); 681cb0ef41Sopenharmony_ci} 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci} // namespace 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_cinamespace node { 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_cinamespace permission { 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_civoid PrintTree(const FSPermission::RadixTree::Node* node, size_t spaces = 0) { 771cb0ef41Sopenharmony_ci std::string whitespace(spaces, ' '); 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci if (node == nullptr) { 801cb0ef41Sopenharmony_ci return; 811cb0ef41Sopenharmony_ci } 821cb0ef41Sopenharmony_ci if (node->wildcard_child != nullptr) { 831cb0ef41Sopenharmony_ci per_process::Debug(DebugCategory::PERMISSION_MODEL, 841cb0ef41Sopenharmony_ci "%s Wildcard: %s\n", 851cb0ef41Sopenharmony_ci whitespace, 861cb0ef41Sopenharmony_ci node->prefix); 871cb0ef41Sopenharmony_ci } else { 881cb0ef41Sopenharmony_ci per_process::Debug(DebugCategory::PERMISSION_MODEL, 891cb0ef41Sopenharmony_ci "%s Prefix: %s\n", 901cb0ef41Sopenharmony_ci whitespace, 911cb0ef41Sopenharmony_ci node->prefix); 921cb0ef41Sopenharmony_ci if (node->children.size()) { 931cb0ef41Sopenharmony_ci size_t child = 0; 941cb0ef41Sopenharmony_ci for (const auto& pair : node->children) { 951cb0ef41Sopenharmony_ci ++child; 961cb0ef41Sopenharmony_ci per_process::Debug(DebugCategory::PERMISSION_MODEL, 971cb0ef41Sopenharmony_ci "%s Child(%s): %s\n", 981cb0ef41Sopenharmony_ci whitespace, 991cb0ef41Sopenharmony_ci child, 1001cb0ef41Sopenharmony_ci std::string(1, pair.first)); 1011cb0ef41Sopenharmony_ci PrintTree(pair.second, spaces + 2); 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci per_process::Debug(DebugCategory::PERMISSION_MODEL, 1041cb0ef41Sopenharmony_ci "%s End of tree - child(%s)\n", 1051cb0ef41Sopenharmony_ci whitespace, 1061cb0ef41Sopenharmony_ci child); 1071cb0ef41Sopenharmony_ci } else { 1081cb0ef41Sopenharmony_ci per_process::Debug(DebugCategory::PERMISSION_MODEL, 1091cb0ef41Sopenharmony_ci "%s End of tree: %s\n", 1101cb0ef41Sopenharmony_ci whitespace, 1111cb0ef41Sopenharmony_ci node->prefix); 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci} 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci// allow = '*' 1171cb0ef41Sopenharmony_ci// allow = '/tmp/,/home/example.js' 1181cb0ef41Sopenharmony_civoid FSPermission::Apply(const std::string& allow, PermissionScope scope) { 1191cb0ef41Sopenharmony_ci using std::string_view_literals::operator""sv; 1201cb0ef41Sopenharmony_ci for (const std::string_view res : SplitString(allow, ","sv)) { 1211cb0ef41Sopenharmony_ci if (res == "*"sv) { 1221cb0ef41Sopenharmony_ci if (scope == PermissionScope::kFileSystemRead) { 1231cb0ef41Sopenharmony_ci deny_all_in_ = false; 1241cb0ef41Sopenharmony_ci allow_all_in_ = true; 1251cb0ef41Sopenharmony_ci } else { 1261cb0ef41Sopenharmony_ci deny_all_out_ = false; 1271cb0ef41Sopenharmony_ci allow_all_out_ = true; 1281cb0ef41Sopenharmony_ci } 1291cb0ef41Sopenharmony_ci return; 1301cb0ef41Sopenharmony_ci } 1311cb0ef41Sopenharmony_ci GrantAccess(scope, std::string(res.data(), res.size())); 1321cb0ef41Sopenharmony_ci } 1331cb0ef41Sopenharmony_ci} 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_civoid FSPermission::GrantAccess(PermissionScope perm, const std::string& res) { 1361cb0ef41Sopenharmony_ci const std::string path = WildcardIfDir(res); 1371cb0ef41Sopenharmony_ci if (perm == PermissionScope::kFileSystemRead) { 1381cb0ef41Sopenharmony_ci granted_in_fs_.Insert(path); 1391cb0ef41Sopenharmony_ci deny_all_in_ = false; 1401cb0ef41Sopenharmony_ci } else if (perm == PermissionScope::kFileSystemWrite) { 1411cb0ef41Sopenharmony_ci granted_out_fs_.Insert(path); 1421cb0ef41Sopenharmony_ci deny_all_out_ = false; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci} 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_cibool FSPermission::is_granted(PermissionScope perm, 1471cb0ef41Sopenharmony_ci const std::string_view& param = "") { 1481cb0ef41Sopenharmony_ci switch (perm) { 1491cb0ef41Sopenharmony_ci case PermissionScope::kFileSystem: 1501cb0ef41Sopenharmony_ci return allow_all_in_ && allow_all_out_; 1511cb0ef41Sopenharmony_ci case PermissionScope::kFileSystemRead: 1521cb0ef41Sopenharmony_ci return !deny_all_in_ && 1531cb0ef41Sopenharmony_ci ((param.empty() && allow_all_in_) || allow_all_in_ || 1541cb0ef41Sopenharmony_ci is_tree_granted(&granted_in_fs_, param)); 1551cb0ef41Sopenharmony_ci case PermissionScope::kFileSystemWrite: 1561cb0ef41Sopenharmony_ci return !deny_all_out_ && 1571cb0ef41Sopenharmony_ci ((param.empty() && allow_all_out_) || allow_all_out_ || 1581cb0ef41Sopenharmony_ci is_tree_granted(&granted_out_fs_, param)); 1591cb0ef41Sopenharmony_ci default: 1601cb0ef41Sopenharmony_ci return false; 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci} 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ciFSPermission::RadixTree::RadixTree() : root_node_(new Node("")) {} 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ciFSPermission::RadixTree::~RadixTree() { 1671cb0ef41Sopenharmony_ci FreeRecursivelyNode(root_node_); 1681cb0ef41Sopenharmony_ci} 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_cibool FSPermission::RadixTree::Lookup(const std::string_view& s, 1711cb0ef41Sopenharmony_ci bool when_empty_return = false) { 1721cb0ef41Sopenharmony_ci FSPermission::RadixTree::Node* current_node = root_node_; 1731cb0ef41Sopenharmony_ci if (current_node->children.size() == 0) { 1741cb0ef41Sopenharmony_ci return when_empty_return; 1751cb0ef41Sopenharmony_ci } 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci unsigned int parent_node_prefix_len = current_node->prefix.length(); 1781cb0ef41Sopenharmony_ci const std::string path(s); 1791cb0ef41Sopenharmony_ci auto path_len = path.length(); 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ci while (true) { 1821cb0ef41Sopenharmony_ci if (parent_node_prefix_len == path_len && current_node->IsEndNode()) { 1831cb0ef41Sopenharmony_ci return true; 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci auto node = current_node->NextNode(path, parent_node_prefix_len); 1871cb0ef41Sopenharmony_ci if (node == nullptr) { 1881cb0ef41Sopenharmony_ci return false; 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci current_node = node; 1921cb0ef41Sopenharmony_ci parent_node_prefix_len += current_node->prefix.length(); 1931cb0ef41Sopenharmony_ci if (current_node->wildcard_child != nullptr && 1941cb0ef41Sopenharmony_ci path_len >= (parent_node_prefix_len - 2 /* slash* */)) { 1951cb0ef41Sopenharmony_ci return true; 1961cb0ef41Sopenharmony_ci } 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci} 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_civoid FSPermission::RadixTree::Insert(const std::string& path) { 2011cb0ef41Sopenharmony_ci FSPermission::RadixTree::Node* current_node = root_node_; 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci unsigned int parent_node_prefix_len = current_node->prefix.length(); 2041cb0ef41Sopenharmony_ci int path_len = path.length(); 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci for (int i = 1; i <= path_len; ++i) { 2071cb0ef41Sopenharmony_ci bool is_wildcard_node = path[i - 1] == '*'; 2081cb0ef41Sopenharmony_ci bool is_last_char = i == path_len; 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci if (is_wildcard_node || is_last_char) { 2111cb0ef41Sopenharmony_ci std::string node_path = path.substr(parent_node_prefix_len, i); 2121cb0ef41Sopenharmony_ci current_node = current_node->CreateChild(node_path); 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci if (is_wildcard_node) { 2161cb0ef41Sopenharmony_ci current_node = current_node->CreateWildcardChild(); 2171cb0ef41Sopenharmony_ci parent_node_prefix_len = i; 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci if (UNLIKELY(per_process::enabled_debug_list.enabled( 2221cb0ef41Sopenharmony_ci DebugCategory::PERMISSION_MODEL))) { 2231cb0ef41Sopenharmony_ci per_process::Debug(DebugCategory::PERMISSION_MODEL, "Inserting %s\n", path); 2241cb0ef41Sopenharmony_ci PrintTree(root_node_); 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci} 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci} // namespace permission 2291cb0ef41Sopenharmony_ci} // namespace node 230