| 247 | } |
| 248 | |
| 249 | static bool InitRPCAuthentication() |
| 250 | { |
| 251 | std::string user; |
| 252 | std::string pass; |
| 253 | |
| 254 | if (gArgs.GetArg("-rpcpassword", "") == "") |
| 255 | { |
| 256 | std::optional<fs::perms> cookie_perms{std::nullopt}; |
| 257 | auto cookie_perms_arg{gArgs.GetArg("-rpccookieperms")}; |
| 258 | if (cookie_perms_arg) { |
| 259 | auto perm_opt = InterpretPermString(*cookie_perms_arg); |
| 260 | if (!perm_opt) { |
| 261 | LogError("Invalid -rpccookieperms=%s; must be one of 'owner', 'group', or 'all'.", *cookie_perms_arg); |
| 262 | return false; |
| 263 | } |
| 264 | cookie_perms = *perm_opt; |
| 265 | } |
| 266 | |
| 267 | switch (GenerateAuthCookie(cookie_perms, user, pass)) { |
| 268 | case AuthCookieResult::Error: |
| 269 | return false; |
| 270 | case AuthCookieResult::Disabled: |
| 271 | LogInfo("RPC authentication cookie file generation is disabled."); |
| 272 | break; |
| 273 | case AuthCookieResult::Ok: |
| 274 | LogInfo("Using random cookie authentication."); |
| 275 | break; |
| 276 | } |
| 277 | } else { |
| 278 | LogInfo("Using rpcuser/rpcpassword authentication."); |
| 279 | LogWarning("The use of rpcuser/rpcpassword is less secure, because credentials are configured in plain text. It is recommended that locally-run instances switch to cookie-based auth, or otherwise to use hashed rpcauth credentials. See share/rpcauth in the source directory for more information."); |
| 280 | user = gArgs.GetArg("-rpcuser", ""); |
| 281 | pass = gArgs.GetArg("-rpcpassword", ""); |
| 282 | } |
| 283 | |
| 284 | // If there is a plaintext credential, hash it with a random salt before storage. |
| 285 | if (!user.empty() || !pass.empty()) { |
| 286 | // Generate a random 16 byte hex salt. |
| 287 | std::array<unsigned char, 16> raw_salt; |
| 288 | GetStrongRandBytes(raw_salt); |
| 289 | std::string salt = HexStr(raw_salt); |
| 290 | |
| 291 | // Compute HMAC. |
| 292 | std::array<unsigned char, CHMAC_SHA256::OUTPUT_SIZE> out; |
| 293 | CHMAC_SHA256(UCharCast(salt.data()), salt.size()).Write(UCharCast(pass.data()), pass.size()).Finalize(out.data()); |
| 294 | std::string hash = HexStr(out); |
| 295 | |
| 296 | g_rpcauth.push_back({user, salt, hash}); |
| 297 | } |
| 298 | |
| 299 | if (!gArgs.GetArgs("-rpcauth").empty()) { |
| 300 | LogInfo("Using rpcauth authentication.\n"); |
| 301 | for (const std::string& rpcauth : gArgs.GetArgs("-rpcauth")) { |
| 302 | std::vector<std::string> fields{SplitString(rpcauth, ':')}; |
| 303 | const std::vector<std::string> salt_hmac{SplitString(fields.back(), '$')}; |
| 304 | if (fields.size() == 2 && salt_hmac.size() == 2) { |
| 305 | fields.pop_back(); |
| 306 | fields.insert(fields.end(), salt_hmac.begin(), salt_hmac.end()); |
no test coverage detected