diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp index f26096b4f7f783e5463cd5247dbeb032500c31a2..cb21ea95af628428e85d4e209fe043fef4f72db3 100644 --- a/src/sip/sipaccount.cpp +++ b/src/sip/sipaccount.cpp @@ -422,7 +422,7 @@ void SIPAccount::serialize(YAML::Emitter &out) out << YAML::Key << Conf::PORT_KEY << YAML::Value << localPort_; // each credential is a map, and we can have multiple credentials - out << YAML::Key << Conf::CRED_KEY << YAML::Value << credentials_; + out << YAML::Key << Conf::CRED_KEY << YAML::Value << getCredentials(); out << YAML::Key << Conf::KEEP_ALIVE_ENABLED << YAML::Value << keepAliveEnabled_; out << YAML::Key << PRESENCE_MODULE_ENABLED_KEY << YAML::Value << (presence_ and presence_->isEnabled()); @@ -528,9 +528,11 @@ void SIPAccount::unserialize(const YAML::Node &node) stunServerName_ = pj_str((char*) stunServer_.data()); const auto &credsNode = node[Conf::CRED_KEY]; - const auto creds = parseVectorMap(credsNode, {Conf::CONFIG_ACCOUNT_PASSWORD, - Conf::CONFIG_ACCOUNT_REALM, Conf::CONFIG_ACCOUNT_USERNAME}); - setCredentials(creds); + setCredentials(parseVectorMap(credsNode, { + Conf::CONFIG_ACCOUNT_REALM, + Conf::CONFIG_ACCOUNT_USERNAME, + Conf::CONFIG_ACCOUNT_PASSWORD + })); // get zrtp submap const auto &zrtpMap = node[Conf::ZRTP_KEY]; @@ -643,38 +645,20 @@ void SIPAccount::setAccountDetails(const std::map<std::string, std::string> &det } } -static std::string retrievePassword(const std::map<std::string, std::string>& map, const std::string &username) -{ - std::map<std::string, std::string>::const_iterator map_iter_username; - std::map<std::string, std::string>::const_iterator map_iter_password; - map_iter_username = map.find(Conf::CONFIG_ACCOUNT_USERNAME); - - if (map_iter_username != map.end()) { - if (map_iter_username->second == username) { - map_iter_password = map.find(Conf::CONFIG_ACCOUNT_PASSWORD); - - if (map_iter_password != map.end()) { - return map_iter_password->second; - } - } - } - - return ""; -} - std::map<std::string, std::string> SIPAccount::getAccountDetails() const { auto a = SIPAccountBase::getAccountDetails(); - a[Conf::CONFIG_ACCOUNT_PASSWORD] = ""; + std::string password {}; if (hasCredentials()) { - for (const auto &vect_item : credentials_) { - const std::string password = retrievePassword(vect_item, username_); - if (not password.empty()) - a.emplace(Conf::CONFIG_ACCOUNT_PASSWORD, password); - } + for (const auto &cred : credentials_) + if (cred.username == username_) { + password = cred.password; + break; + } } + a.emplace(Conf::CONFIG_ACCOUNT_PASSWORD, std::move(password)); a.emplace(Conf::CONFIG_LOCAL_PORT, ring::to_string(localPort_)); a.emplace(Conf::CONFIG_ACCOUNT_ROUTESET, serviceRoute_); @@ -1578,10 +1562,8 @@ void SIPAccount::keepAliveRegistrationCb(UNUSED pj_timer_heap_t *th, pj_timer_en sipAccount->doRegister(); } -static std::string -computeMd5HashFromCredential(const std::string& username, - const std::string& password, - const std::string& realm) +void +SIPAccount::Credentials::computePasswordHash() { #define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len) @@ -1604,77 +1586,61 @@ computeMd5HashFromCredential(const std::string& username, for (int i = 0; i < 16; ++i) pj_val_to_hex_digit(digest[i], &hash[2 * i]); - return std::string(hash, 32); + password_h = {hash, 32}; } void SIPAccount::setCredentials(const std::vector<std::map<std::string, std::string> >& creds) { - // we can not authenticate without credentials if (creds.empty()) { RING_ERR("Cannot authenticate with empty credentials list"); return; } - - using std::vector; - using std::string; - using std::map; + credentials_.clear(); + cred_.clear(); bool md5HashingEnabled = Manager::instance().preferences.getMd5Hash(); - credentials_ = creds; - - /* md5 hashing */ - for (auto &it : credentials_) { - map<string, string>::const_iterator val = it.find(Conf::CONFIG_ACCOUNT_USERNAME); - const std::string username = val != it.end() ? val->second : ""; - val = it.find(Conf::CONFIG_ACCOUNT_REALM); - const std::string realm(val != it.end() ? val->second : ""); - val = it.find(Conf::CONFIG_ACCOUNT_PASSWORD); - const std::string password(val != it.end() ? val->second : ""); - - if (md5HashingEnabled) { - // TODO: Fix this. - // This is an extremly weak test in order to check - // if the password is a hashed value. This is done - // because deleteCredential() is called before this - // method. Therefore, we cannot check if the value - // is different from the one previously stored in - // the configuration file. This is to avoid to - // re-hash a hashed password. - - if (password.length() != 32) - it[Conf::CONFIG_ACCOUNT_PASSWORD] = computeMd5HashFromCredential(username, password, realm); - } - } - - // Create the credential array - cred_.resize(credentials_.size()); - - size_t i = 0; - - for (const auto &item : credentials_) { - auto val = item.find(Conf::CONFIG_ACCOUNT_USERNAME); - if (val != item.end()) - cred_[i].username = pj_str((char*) val->second.c_str()); - - val = item.find(Conf::CONFIG_ACCOUNT_REALM); - if (val != item.end()) - cred_[i].realm = pj_str((char*) val->second.c_str()); - - val = item.find(Conf::CONFIG_ACCOUNT_PASSWORD); - cred_[i].data = pj_str((char*) (val != item.end() ? val->second.c_str() : "")); - cred_[i].data_type = (md5HashingEnabled and cred_[i].data.slen == 32) - ? PJSIP_CRED_DATA_DIGEST - : PJSIP_CRED_DATA_PLAIN_PASSWD; - cred_[i].scheme = pj_str((char*) "digest"); - ++i; - } -} - -const std::vector<std::map<std::string, std::string> > & + credentials_.reserve(creds.size()); + cred_.reserve(creds.size()); + for (const auto& cred : creds) { + auto realm = cred.find(Conf::CONFIG_ACCOUNT_REALM); + auto user = cred.find(Conf::CONFIG_ACCOUNT_USERNAME); + auto passw = cred.find(Conf::CONFIG_ACCOUNT_PASSWORD); + credentials_.emplace_back(realm != cred.end() ? realm->second : "", + user != cred.end() ? user->second : "", + passw != cred.end() ? passw->second : ""); + auto& c = credentials_.back(); + if (md5HashingEnabled) + c.computePasswordHash(); + + cred_.emplace_back(pjsip_cred_info { + .realm = pj_str((char*) c.realm.c_str()), + .scheme = pj_str((char*) "digest"), + .username = pj_str((char*) c.username.c_str()), + .data_type = (c.password_h.empty() + ? PJSIP_CRED_DATA_PLAIN_PASSWD + : PJSIP_CRED_DATA_DIGEST), + .data = pj_str((char*) (c.password_h.empty() + ? c.password.c_str() + : c.password_h.c_str())), + .ext = {} + }); + } +} + +std::vector<std::map<std::string, std::string>> SIPAccount::getCredentials() const { - return credentials_; + std::vector<std::map<std::string, std::string>> ret; + ret.reserve(credentials_.size()); + for (const auto& c : credentials_) { + ret.emplace_back(std::map<std::string, std::string>{ + {Conf::CONFIG_ACCOUNT_REALM, c.realm}, + {Conf::CONFIG_ACCOUNT_USERNAME, c.username}, + {Conf::CONFIG_ACCOUNT_PASSWORD, c.password} + }); + } + return ret; } void diff --git a/src/sip/sipaccount.h b/src/sip/sipaccount.h index f863635eb5d77bae6d9bd481a67aec03e7701a0c..1d0a208f71b3ba7f032e599c7f84f1bafac8e8dc 100644 --- a/src/sip/sipaccount.h +++ b/src/sip/sipaccount.h @@ -217,7 +217,7 @@ class SIPAccount : public SIPAccountBase { void setCredentials(const std::vector<std::map<std::string, std::string> >& details); - const std::vector<std::map<std::string, std::string> > & + std::vector<std::map<std::string, std::string>> getCredentials() const; void setRegistrationState(RegistrationState state, unsigned code=0); @@ -579,7 +579,16 @@ class SIPAccount : public SIPAccountBase { /** * Map of credential for this account */ - std::vector< std::map<std::string, std::string > > credentials_; + struct Credentials { + std::string realm {}; + std::string username {}; + std::string password {}; + std::string password_h {}; + Credentials(const std::string& r, const std::string& u, const std::string& p) + : realm(r), username(u), password(p) {} + void computePasswordHash(); + }; + std::vector<Credentials> credentials_; std::shared_ptr<SipTransport> transport_ {}; @@ -659,9 +668,9 @@ class SIPAccount : public SIPAccountBase { */ std::string serviceRoute_; - /** * Credential information stored for further registration. + * Points to credentials_ members. */ std::vector<pjsip_cred_info> cred_;