Line data Source code
1 : /** 2 : * Copyright (c) Libmonero 3 : * 4 : * Permission is hereby granted, free of charge, to any person obtaining a copy 5 : * of this software and associated documentation files (the "Software"), to deal 6 : * in the Software without restriction, including without limitation the rights 7 : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 : * copies of the Software, and to permit persons to whom the Software is 9 : * furnished to do so, subject to the following conditions: 10 : * 11 : * The above copyright notice and this permission notice shall be included in all 12 : * copies or substantial portions of the Software. 13 : * 14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 : * SOFTWARE. 21 : */ 22 : 23 : #include "monero_c_common.h" 24 : #include "monero_c_tls.h" 25 : 26 : #if !defined(_WIN32) 27 : #include <dirent.h> 28 : #include <openssl/x509.h> 29 : #include <sys/stat.h> 30 : #endif 31 : 32 : // monero-project's own, from crypto/slow-hash.c: it frees the scratchpad of the calling thread 33 : extern "C" void slow_hash_free_state(void); 34 : 35 : namespace monero_c { 36 : 37 : namespace { 38 : 39 : thread_local std::string g_last_error; 40 : 41 : struct slow_hash_state_owner { 42 90 : ~slow_hash_state_owner() { slow_hash_free_state(); } 43 : }; 44 : 45 : } // namespace 46 : 47 27596 : void free_slow_hash_state_at_thread_exit() noexcept { 48 27596 : thread_local slow_hash_state_owner owner; 49 : (void) owner; 50 27596 : } 51 : 52 17616 : void set_last_error(const char* msg) noexcept { 53 17616 : try { g_last_error = msg; } catch (...) { g_last_error.clear(); } 54 17616 : } 55 : 56 2806 : void set_null_error(const char* name) noexcept { 57 2806 : try { g_last_error = std::string(name) + " must not be null"; } catch (...) { g_last_error.clear(); } 58 2806 : } 59 : 60 38319 : const std::string& last_error() { 61 38319 : return g_last_error; 62 : } 63 : 64 6356 : void check_json_depth(const std::string& json) { 65 6356 : size_t depth = 0; 66 6356 : bool in_string = false; 67 12553517 : for (size_t i = 0; i < json.size(); i++) { 68 12547244 : char c = json[i]; 69 12547244 : if (in_string) { 70 7293122 : if (c == '\\') i++; 71 7292909 : else if (c == '"') in_string = false; 72 5254122 : } else if (c == '"') { 73 452313 : in_string = true; 74 4801809 : } else if (c == '[' || c == '{') { 75 29377 : if (++depth > MAX_JSON_DEPTH) throw std::invalid_argument("JSON is nested deeper than " + std::to_string(MAX_JSON_DEPTH) + " levels"); 76 4772432 : } else if ((c == ']' || c == '}') && depth > 0) { 77 21117 : depth--; 78 : } 79 : } 80 6273 : } 81 : 82 : } // namespace monero_c 83 : 84 : #if !defined(_WIN32) 85 : 86 : namespace { 87 : 88 13 : bool is_file_with_content(const std::string& path) { 89 : struct stat info; 90 13 : return stat(path.c_str(), &info) == 0 && S_ISREG(info.st_mode) && info.st_size > 0; 91 : } 92 : 93 : // true if the directory has a certificate by its hashed name, such as 5ad8a5d6.0 94 13 : bool has_hashed_certificates(const std::string& path) { 95 13 : DIR* dir = opendir(path.c_str()); 96 13 : if (dir == nullptr) return false; 97 13 : bool found = false; 98 39 : while (struct dirent* entry = readdir(dir)) { 99 39 : if (monero_c::is_hashed_certificate_name(entry->d_name)) { 100 13 : found = true; 101 13 : break; 102 : } 103 26 : } 104 13 : closedir(dir); 105 13 : return found; 106 : } 107 : 108 : // runs when the library is loaded, before a connection makes a TLS context. See find_ca_paths() for why. Windows needs none, since 109 : // epee reads the root store of the system there 110 13 : __attribute__((unused)) const bool g_ca_paths_set = [] { 111 13 : monero_c::ca_paths paths = monero_c::find_ca_paths(getenv("SSL_CERT_FILE"), getenv("SSL_CERT_DIR"), X509_get_default_cert_file(), X509_get_default_cert_dir(), 112 26 : is_file_with_content, has_hashed_certificates); 113 13 : if (!paths.file.empty()) setenv("SSL_CERT_FILE", paths.file.c_str(), 1); 114 13 : if (!paths.dir.empty()) setenv("SSL_CERT_DIR", paths.dir.c_str(), 1); 115 13 : return true; 116 13 : }(); 117 : 118 : } // namespace 119 : 120 : #endif