/* * AuthBackendFile.cpp * * Copyright (C) 2009 Matthias Schiffer * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this program. If not, see . */ #include "AuthProviderFile.h" #include #include #include #include #include #include namespace Mad { namespace Modules { namespace AuthProviderFile { void AuthProviderFile::readFile(const std::string &name) { std::ifstream stream(name.c_str()); if(!stream.good()) { application->logf(Core::Logger::LOG_WARNING, "AuthProviderFile: Can't read file '%s'.", name.c_str()); return; } while(stream.good() && !stream.eof()) { std::string line; std::getline(stream, line); if(line.empty()) continue; static const boost::regex regex("([^:]+):(.+)", boost::regex_constants::perl); boost::smatch match; if(!boost::regex_match(line, match, regex)) { application->logf(Core::Logger::LOG_WARNING, "AuthProviderFile: Malformed line in file '%s'.", name.c_str()); continue; } Core::String password = match[2].str().c_str(); if(filehash.isEmpty()) { std::string utf8pass = password.extractUTF8(); boost::lock_guard lock(mutex); userMap.insert(std::make_pair(match[1].str().c_str(), std::vector(utf8pass.begin(), utf8pass.end()))); } else { std::vector data; data.reserve(password.length()/2); for(boost::int32_t c = 0; c < password.length()-1; c += 2) { char buffer[3] = {password[c], password[c+1], 0}; unsigned char byte; if(std::sscanf(buffer, "%hhx", &byte) != 1) { application->logf(Core::Logger::LOG_WARNING, "AuthProviderFile: Malformed hash in file '%s'.", name.c_str()); data.clear(); break; } data.push_back(byte); } if(!data.empty()) { boost::lock_guard lock(mutex); userMap.insert(std::make_pair(match[1].str().c_str(), data)); } } } } bool AuthProviderFile::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handled*/) { if(!entry[0].getKey().matches("AuthProviderFile")) return false; if(entry[1].isEmpty()) return true; if(entry[1].getKey().matches("Hash")) { if(entry[2].isEmpty()) { filehash = entry[1][0]; if(!Common::Hash::isHashSupported(filehash)) application->logf(Core::Logger::LOG_WARNING, "AuthProviderFile: Unsupported hash '%s'", filehash.extract().c_str()); } } else if(entry[1].getKey().matches("File")) { if(entry[2].isEmpty()) { files.push_back(entry[1][0]); } } else if(!entry[2].isEmpty()) return false; return true; } void AuthProviderFile::configFinished() { if(filehash.isEmpty() || filehash.matches("clear")) { hashes = Common::Hash::getHashList(); filehash.remove(); } else { hashes.clear(); hashes.push_back(filehash); } hashes.push_back("Clear"); for(std::vector::iterator file = files.begin(); file != files.end(); ++file) readFile(file->extract()); } bool AuthProviderFile::checkPassword(const Core::String &user, const std::vector &data, const Core::String &hash) throw(Core::Exception) { if((hash.isEmpty() || hash.matches("clear")) && !filehash.isEmpty()) { std::vector password = getPassword(user, filehash); std::vector hashdata = Common::Hash::hash(data, filehash); return (!password.empty() && hashdata.size() == password.size() && std::equal(hashdata.begin(), hashdata.end(), password.begin())); } else { std::vector password = getPassword(user, hash); return (!password.empty() && data.size() == password.size() && std::equal(data.begin(), data.end(), password.begin())); } } std::vector AuthProviderFile::getPassword(const Core::String &user, const Core::String &hash) throw(Core::Exception) { boost::lock_guard lock(mutex); std::map >::iterator userIt = userMap.find(user); if(userIt == userMap.end()) return std::vector(); if(filehash.isEmpty()) { if(hash.matches("clear")) return userIt->second; else return Common::Hash::hash(userIt->second, hash); } else if(filehash.matches(hash)) { return userIt->second; } else throw Core::Exception(Core::Exception::NOT_AVAILABLE); } } } }