/* * UserManager.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 "UserManager.h" #include "Application.h" #include "UserCache.h" #include "UserConfigBackend.h" #include #include namespace Mad { namespace Common { UserManager::UserManager(Application *application0) : application(application0), minUid(1000), maxUid(29999), minGid(1000), maxGid(29999) { application->getConfigManager()->registerConfigurable(this); } UserManager::~UserManager() { application->getConfigManager()->unregisterConfigurable(this); } bool UserManager::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handled*/) { if(entry[0].getKey().matches("UserManager")) { if(entry[1].getKey().matches("MinUid")) { if(entry[2].empty()) { char *endptr; unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 10); if(entry[1][0].empty() || *endptr) { application->logf(Core::LoggerBase::LOG_WARNING, "UserBackendHome: Invalid configuration: MinUid '%s'", entry[1][0].c_str()); } else { minUid = val; } } } else if(entry[1].getKey().matches("MaxUid")) { if(entry[2].empty()) { char *endptr; unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 10); if(entry[1][0].empty() || *endptr) { application->logf(Core::LoggerBase::LOG_WARNING, "UserBackendHome: Invalid configuration: MaxUid '%s'", entry[1][0].c_str()); } else { maxUid = val; } } } else if(entry[1].getKey().matches("MinGid")) { if(entry[2].empty()) { char *endptr; unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 10); if(entry[1][0].empty() || *endptr) { application->logf(Core::LoggerBase::LOG_WARNING, "UserBackendHome: Invalid configuration: MinGid '%s'", entry[1][0].c_str()); } else { minGid = val; } } } else if(entry[1].getKey().matches("MaxGid")) { if(entry[2].empty()) { char *endptr; unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 10); if(entry[1][0].empty() || *endptr) { application->logf(Core::LoggerBase::LOG_WARNING, "UserBackendHome: Invalid configuration: MaxGid '%s'", entry[1][0].c_str()); } else { maxGid = val; } } } else if(!entry[1].empty()) return false; return true; } return false; } void UserManager::registerBackend(boost::shared_ptr backend) { boost::lock_guard lock(mutex); const std::string &name = backend->getName(); dbBackends.insert(std::make_pair(backend, std::make_pair(backend, name))); dbBackendNames.insert(std::make_pair(name, backend)); if(!dbBackend) dbBackend = backend; } void UserManager::registerBackendCached(boost::shared_ptr backend) { boost::lock_guard lock(mutex); const std::string &name = backend->getName(); boost::shared_ptr cache(new UserCache(application, backend)); dbBackends.insert(std::make_pair(backend, std::make_pair(cache, name))); dbBackendNames.insert(std::make_pair(name, backend)); if(!dbBackend) dbBackend = cache; } boost::shared_ptr > UserManager::getUserList(boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getUserList(timestamp); } boost::shared_ptr UserManager::getUserInfo(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getUserInfo(uid, timestamp); } boost::shared_ptr UserManager::getUserInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getUserInfoByName(name, timestamp); } boost::shared_ptr > UserManager::getUserGroupList(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getUserGroupList(uid, timestamp); } boost::shared_ptr > UserManager::getGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getGroupList(timestamp); } boost::shared_ptr UserManager::getGroupInfo(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getGroupInfo(gid, timestamp); } boost::shared_ptr UserManager::getGroupInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getGroupInfoByName(name, timestamp); } boost::shared_ptr > UserManager::getGroupUserList(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getGroupUserList(gid, timestamp); } boost::shared_ptr > UserManager::getFullUserGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); return dbBackend->getFullUserGroupList(timestamp); } void UserManager::checkUserInfo(const UserInfo &userInfo) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); if(userInfo.getUid() < minUid || userInfo.getUid() > maxUid) throw Core::Exception(Core::Exception::INVALID_INPUT); dbBackend->checkUserInfo(userInfo); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { (*configBackend)->checkUserInfo(userInfo); } } void UserManager::addUser(const UserInfo &userInfo) throw(Core::Exception) { checkUserInfo(userInfo); boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); dbBackend->addUser(userInfo); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->addUser(userInfo); } catch(Core::Exception e) { application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } } void UserManager::updateUser(unsigned long uid, const UserInfo &userInfo) throw(Core::Exception) { checkUserInfo(userInfo); boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr oldUserInfo = dbBackend->getUserInfo(uid, 0); if(!oldUserInfo) throw Core::Exception(Core::Exception::NOT_FOUND); dbBackend->updateUser(uid, userInfo); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->updateUser(*oldUserInfo, userInfo); } catch(Core::Exception e) { application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } } void UserManager::deleteUser(unsigned long uid) throw(Core::Exception) { boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr userInfo = dbBackend->getUserInfo(uid, 0); if(!userInfo) throw Core::Exception(Core::Exception::NOT_FOUND); dbBackend->deleteUser(uid); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->deleteUser(*userInfo); } catch(Core::Exception e) { application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } } void UserManager::checkGroupInfo(const GroupInfo &groupInfo) throw(Core::Exception) { boost::shared_lock lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); if(groupInfo.getGid() < minGid || groupInfo.getGid() > maxGid) throw Core::Exception(Core::Exception::INVALID_INPUT); dbBackend->checkGroupInfo(groupInfo); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { (*configBackend)->checkGroupInfo(groupInfo); } } void UserManager::addGroup(const GroupInfo &groupInfo) throw(Core::Exception) { checkGroupInfo(groupInfo); boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); dbBackend->addGroup(groupInfo); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->addGroup(groupInfo); } catch(Core::Exception e) { application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } } void UserManager::updateGroup(unsigned long gid, const GroupInfo &groupInfo) throw(Core::Exception) { checkGroupInfo(groupInfo); boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr oldGroupInfo = dbBackend->getGroupInfo(gid, 0); if(!oldGroupInfo) throw Core::Exception(Core::Exception::NOT_FOUND); dbBackend->updateGroup(gid, groupInfo); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->updateGroup(*oldGroupInfo, groupInfo); } catch(Core::Exception e) { application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } } void UserManager::deleteGroup(unsigned long gid) throw(Core::Exception) { boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr groupInfo = dbBackend->getGroupInfo(gid, 0); if(!groupInfo) throw Core::Exception(Core::Exception::NOT_FOUND); dbBackend->deleteGroup(gid); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->deleteGroup(*groupInfo); } catch(Core::Exception e) { application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } } void UserManager::addUserToGroup(unsigned long uid, unsigned long gid) throw(Core::Exception) { boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr userInfo = dbBackend->getUserInfo(uid, 0); if(!userInfo) throw Core::Exception(Core::Exception::NOT_FOUND); boost::shared_ptr groupInfo = dbBackend->getGroupInfo(gid, 0); if(!groupInfo) throw Core::Exception(Core::Exception::NOT_FOUND); dbBackend->addUserToGroup(uid, gid); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->addUserToGroup(*userInfo, *groupInfo); } catch(Core::Exception e) { application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } } void UserManager::deleteUserFromGroup(unsigned long uid, unsigned long gid) throw(Core::Exception) { boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr userInfo = dbBackend->getUserInfo(uid, 0); if(!userInfo) throw Core::Exception(Core::Exception::NOT_FOUND); boost::shared_ptr groupInfo = dbBackend->getGroupInfo(gid, 0); if(!groupInfo) throw Core::Exception(Core::Exception::NOT_FOUND); dbBackend->deleteUserFromGroup(uid, gid); for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->deleteUserFromGroup(*userInfo, *groupInfo); } catch(Core::Exception e) { application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } } void UserManager::setPassword(unsigned long uid, const std::string &password) throw(Core::Exception) { boost::lock_guard lock(mutex); if(!dbBackend) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr userInfo = dbBackend->getUserInfo(uid, 0); if(!userInfo) throw Core::Exception(Core::Exception::NOT_FOUND); bool ok = false; Core::Exception exception; try { dbBackend->setPassword(uid, password); ok = true; } catch(Core::Exception e) { exception = e; if(e.getErrorCode() != Core::Exception::NOT_IMPLEMENTED) application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } for(std::set >::iterator configBackend = configBackends.begin(); configBackend != configBackends.end(); ++configBackend) { try { (*configBackend)->setPassword(*userInfo, password); ok = true; } catch(Core::Exception e) { if(e.getErrorCode() != Core::Exception::NOT_IMPLEMENTED) application->log(Core::LoggerBase::LOG_USER, Core::LoggerBase::LOG_WARNING, e.strerror()); } } if(!ok) throw exception; } } }