| 607 | } |
| 608 | |
| 609 | void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorControlReply& reply) |
| 610 | { |
| 611 | if (reply.code == 250) { |
| 612 | std::set<std::string> methods; |
| 613 | std::string cookiefile; |
| 614 | /* |
| 615 | * 250-AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE="/home/x/.tor/control_auth_cookie" |
| 616 | * 250-AUTH METHODS=NULL |
| 617 | * 250-AUTH METHODS=HASHEDPASSWORD |
| 618 | */ |
| 619 | for (const std::string &s : reply.lines) { |
| 620 | std::pair<std::string,std::string> l = SplitTorReplyLine(s); |
| 621 | if (l.first == "AUTH") { |
| 622 | std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); |
| 623 | std::map<std::string,std::string>::iterator i; |
| 624 | if ((i = m.find("METHODS")) != m.end()) |
| 625 | boost::split(methods, i->second, boost::is_any_of(",")); |
| 626 | if ((i = m.find("COOKIEFILE")) != m.end()) |
| 627 | cookiefile = i->second; |
| 628 | } else if (l.first == "VERSION") { |
| 629 | std::map<std::string,std::string> m = ParseTorReplyMapping(l.second); |
| 630 | std::map<std::string,std::string>::iterator i; |
| 631 | if ((i = m.find("Tor")) != m.end()) { |
| 632 | LogPrint(BCLog::TOR, "tor: Connected to Tor version %s\n", i->second); |
| 633 | } |
| 634 | } |
| 635 | } |
| 636 | for (const std::string &s : methods) { |
| 637 | LogPrint(BCLog::TOR, "tor: Supported authentication method: %s\n", s); |
| 638 | } |
| 639 | // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD |
| 640 | /* Authentication: |
| 641 | * cookie: hex-encoded ~/.tor/control_auth_cookie |
| 642 | * password: "password" |
| 643 | */ |
| 644 | std::string torpassword = gArgs.GetArg("-torpassword", ""); |
| 645 | if (!torpassword.empty()) { |
| 646 | if (methods.count("HASHEDPASSWORD")) { |
| 647 | LogPrint(BCLog::TOR, "tor: Using HASHEDPASSWORD authentication\n"); |
| 648 | boost::replace_all(torpassword, "\"", "\\\""); |
| 649 | _conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); |
| 650 | } else { |
| 651 | LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); |
| 652 | } |
| 653 | } else if (methods.count("NULL")) { |
| 654 | LogPrint(BCLog::TOR, "tor: Using NULL authentication\n"); |
| 655 | _conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); |
| 656 | } else if (methods.count("SAFECOOKIE")) { |
| 657 | // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie |
| 658 | LogPrint(BCLog::TOR, "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); |
| 659 | std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); |
| 660 | if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { |
| 661 | // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2)); |
| 662 | cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end()); |
| 663 | clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0); |
| 664 | GetRandBytes(clientNonce.data(), TOR_NONCE_SIZE); |
| 665 | _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2)); |
| 666 | } else { |
nothing calls this directly
no test coverage detected