/* * UserConfigBackendHome.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 "UserConfigBackendHome.h" #include #include #include #include #include #include namespace Mad { namespace Modules { namespace UserConfigBackendHome { bool UserConfigBackendHome::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handled*/) { if(entry[0].getKey().matches("UserManager")) { if(entry[1].getKey().matches("Skeleton")) { if(entry[2].isEmpty()) skeleton = entry[1][0]; } else if(entry[1].getKey().matches("HomeDir")) { if(entry[2].isEmpty()) homeDir = entry[1][0]; } else if(entry[1].getKey().matches("UserDirMode")) { if(entry[2].isEmpty()) { if(entry[1][0].isEmpty()) { dirMode = 0755; } else { char *endptr; unsigned long val = std::strtoul(entry[1][0].extract().c_str(), &endptr, 8); if(*endptr || val > 07777) { application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: DirMode '%s'", entry[1][0].extract().c_str()); } else { dirMode = val; } } } } else if(!entry[1].isEmpty()) return false; return true; } return false; } void UserConfigBackendHome::setOwnerAndCopyMode(const std::string &source, const std::string &dest, const Common::UserInfo &userInfo, bool isSymlink) { if((isSymlink ? lchown : chown)(dest.c_str(), (uid_t)userInfo.getUid(), (gid_t)userInfo.getGid()) != 0) { // TODO Error } struct stat st; if((isSymlink ? lstat : stat)(source.c_str(), &st) == 0) { if((isSymlink ? lchmod : chmod)(dest.c_str(), st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != 0) { // TODO Error } } } void UserConfigBackendHome::migrateOwner(const std::string &path, const Common::UserInfo &oldUserInfo, const Common::UserInfo &userInfo, bool isSymlink) { struct stat st; if((isSymlink ? lstat : stat)(path.c_str(), &st) != 0) { // TODO Error return; } uid_t uid = -1; gid_t gid = -1; if(st.st_uid == oldUserInfo.getUid()) uid = (uid_t)userInfo.getUid(); if(st.st_gid == oldUserInfo.getGid()) gid = (gid_t)userInfo.getGid(); if(uid != (uid_t)-1 || gid != (gid_t)-1) { if((isSymlink ? lchown : chown)(path.c_str(), uid, gid) != 0) { // TODO Error } } } void UserConfigBackendHome::addUser(const Common::UserInfo &userInfo) throw(Core::Exception) { boost::filesystem::path path(homeDir.extract()); path /= userInfo.getUsername().extract(); boost::filesystem::create_directories(path); std::string nativePath = path.directory_string(); if(chown(nativePath.c_str(), (uid_t)userInfo.getUid(), (gid_t)userInfo.getGid()) != 0) { // TODO Error } if(chmod(nativePath.c_str(), (mode_t)dirMode)) { // TODO Error } boost::filesystem::path skeletonPath(skeleton.extract()); if(!boost::filesystem::is_directory(skeletonPath)) return; boost::filesystem::path oldPath = boost::filesystem::current_path(); boost::filesystem::current_path(skeletonPath); boost::filesystem::recursive_directory_iterator end; for(boost::filesystem::recursive_directory_iterator it("."); it != end; ++it) { boost::filesystem::path source = it->path(); boost::filesystem::path dest = path / source; try { if(boost::filesystem::is_symlink(it->symlink_status())) { it.no_push(); std::string sourceStr = source.file_string(); char link[PATH_MAX]; int ret = ::readlink(sourceStr.c_str(), link, PATH_MAX); if(ret <= 0) continue; boost::filesystem::create_symlink(boost::filesystem::path(std::string(link, ret)), dest); setOwnerAndCopyMode(sourceStr, dest.file_string(), userInfo, true); } else if(boost::filesystem::is_directory(it->status())) { boost::filesystem::create_directory(dest); setOwnerAndCopyMode(source.directory_string(), dest.directory_string(), userInfo, false); } else { boost::filesystem::copy_file(source, dest); setOwnerAndCopyMode(source.file_string(), dest.file_string(), userInfo, false); } } catch(...) {} } boost::filesystem::current_path(oldPath); } void UserConfigBackendHome::updateUser(const Common::UserInfo &oldUserInfo, const Common::UserInfo &userInfo) throw(Core::Exception) { boost::filesystem::path oldPath(homeDir.extract()); oldPath /= oldUserInfo.getUsername().extract(); boost::filesystem::path path(homeDir.extract()); path /= userInfo.getUsername().extract(); if(oldPath != path) { try { boost::filesystem::rename(oldPath, path); } catch(...) { return; } } if(oldUserInfo.getUid() == userInfo.getUid() && oldUserInfo.getGid() == userInfo.getGid()) return; std::string nativePath = path.directory_string(); if(chown(nativePath.c_str(), (uid_t)userInfo.getUid(), (gid_t)userInfo.getGid()) != 0) { // TODO Error } boost::filesystem::recursive_directory_iterator end; for(boost::filesystem::recursive_directory_iterator it(path); it != end; ++it) { if(boost::filesystem::is_symlink(it->symlink_status())) { it.no_push(); migrateOwner(it->path().file_string(), oldUserInfo, userInfo, true); } else if(boost::filesystem::is_directory(it->status())) { migrateOwner(it->path().directory_string(), oldUserInfo, userInfo, false); } else { migrateOwner(it->path().file_string(), oldUserInfo, userInfo, false); } } } void UserConfigBackendHome::deleteUser(const Common::UserInfo &userInfo) throw(Core::Exception) { boost::filesystem::path path(homeDir.extract()); path /= userInfo.getUsername().extract(); boost::filesystem::remove_all(path); } } } }