| 478 | } |
| 479 | |
| 480 | void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorControlReply& reply) |
| 481 | { |
| 482 | if (reply.code == 250) { |
| 483 | std::set<std::string> methods; |
| 484 | std::string cookiefile; |
| 485 | /* |
| 486 | * 250-AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE="/home/x/.tor/control_auth_cookie" |
| 487 | * 250-AUTH METHODS=NULL |
| 488 | * 250-AUTH METHODS=HASHEDPASSWORD |
| 489 | */ |
| 490 | for (const std::string &s : reply.lines) { |
| 491 | std::pair<std::string,std::string> l = SplitTorReplyLine(s); |
| 492 | if (l.first == "AUTH") { |
| 493 | std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); |
| 494 | std::map<std::string,std::string>::iterator i; |
| 495 | if ((i = m.find("METHODS")) != m.end()) |
| 496 | boost::split(methods, i->second, boost::is_any_of(",")); |
| 497 | if ((i = m.find("COOKIEFILE")) != m.end()) |
| 498 | cookiefile = i->second; |
| 499 | } else if (l.first == "VERSION") { |
| 500 | std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); |
| 501 | std::map<std::string,std::string>::iterator i; |
| 502 | if ((i = m.find("Tor")) != m.end()) { |
| 503 | LogPrint(BCLog::TOR, "tor: Connected to Tor version %s\n", i->second); |
| 504 | } |
| 505 | } |
| 506 | } |
| 507 | for (const std::string &s : methods) { |
| 508 | LogPrint(BCLog::TOR, "tor: Supported authentication method: %s\n", s); |
| 509 | } |
| 510 | // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD |
| 511 | /* Authentication: |
| 512 | * cookie: hex-encoded ~/.tor/control_auth_cookie |
| 513 | * password: "password" |
| 514 | */ |
| 515 | std::string torpassword = gArgs.GetArg("-torpassword", ""); |
| 516 | if (!torpassword.empty()) { |
| 517 | if (methods.count("HASHEDPASSWORD")) { |
| 518 | LogPrint(BCLog::TOR, "tor: Using HASHEDPASSWORD authentication\n"); |
| 519 | boost::replace_all(torpassword, "\"", "\\\""); |
| 520 | _conn.Command("AUTHENTICATE \"" + torpassword + "\"", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); |
| 521 | } else { |
| 522 | LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); |
| 523 | } |
| 524 | } else if (methods.count("NULL")) { |
| 525 | LogPrint(BCLog::TOR, "tor: Using NULL authentication\n"); |
| 526 | _conn.Command("AUTHENTICATE", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); |
| 527 | } else if (methods.count("SAFECOOKIE")) { |
| 528 | // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie |
| 529 | LogPrint(BCLog::TOR, "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); |
| 530 | std::pair<bool,std::string> status_cookie = ReadBinaryFile(fs::PathFromString(cookiefile), TOR_COOKIE_SIZE); |
| 531 | if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { |
| 532 | // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); |
| 533 | cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end()); |
| 534 | clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0); |
| 535 | GetRandBytes(clientNonce.data(), TOR_NONCE_SIZE); |
| 536 | _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), std::bind(&TorController::authchallenge_cb, this, std::placeholders::_1, std::placeholders::_2)); |
| 537 | } else { |