summaryrefslogtreecommitdiffstats
path: root/src/modules/UserBackendHome/UserBackendHome.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/UserBackendHome/UserBackendHome.cpp')
-rw-r--r--src/modules/UserBackendHome/UserBackendHome.cpp195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/modules/UserBackendHome/UserBackendHome.cpp b/src/modules/UserBackendHome/UserBackendHome.cpp
new file mode 100644
index 0000000..d524a52
--- /dev/null
+++ b/src/modules/UserBackendHome/UserBackendHome.cpp
@@ -0,0 +1,195 @@
+/*
+ * UserBackendHome.cpp
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "UserBackendHome.h"
+#include <Core/ConfigEntry.h>
+#include <Core/ConfigManager.h>
+
+#include <boost/filesystem.hpp>
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace Mad {
+namespace Modules {
+namespace UserBackendHome {
+
+bool UserBackendHome::handleConfigEntry(const Core::ConfigEntry &entry, bool handled) {
+ if(handled)
+ return false;
+
+ if(entry[0].getKey().matches("UserBackendHome")) {
+ if(entry[1].getKey().matches("Skeleton")) {
+ if(entry[2].empty())
+ skeleton = entry[1][0];
+ }
+ else if(entry[1].getKey().matches("HomeDir")) {
+ if(entry[2].empty())
+ homeDir = entry[1][0];
+ }
+ else if(!entry[1].empty())
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+void UserBackendHome::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 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 UserBackendHome::addUser(const Common::UserInfo &userInfo) throw(Core::Exception) {
+ boost::filesystem::path path(homeDir);
+ path /= userInfo.getUsername();
+
+ 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
+ }
+
+ boost::filesystem::path skeletonPath(skeleton);
+ 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 UserBackendHome::updateUser(const Common::UserInfo &oldUserInfo, const Common::UserInfo &userInfo) throw(Core::Exception) {
+ boost::filesystem::path oldPath(homeDir);
+ oldPath /= oldUserInfo.getUsername();
+
+ boost::filesystem::path path(homeDir);
+ path /= userInfo.getUsername();
+
+ 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 UserBackendHome::deleteUser(const Common::UserInfo &userInfo) throw(Core::Exception) {
+ boost::filesystem::path path(homeDir);
+ path /= userInfo.getUsername();
+
+ boost::filesystem::remove_all(path);
+}
+
+}
+}
+}