diff --git a/include/transport/storagebackend.h b/include/transport/storagebackend.h index 5289010447dea048ab47ae4fb6b00abc1f934bc6..a5d101be206572146936bdf8415b4a9690e1b76a 100644 --- a/include/transport/storagebackend.h +++ b/include/transport/storagebackend.h @@ -86,6 +86,14 @@ class Config; class StorageBackend { public: + static std::string encryptPassword(const std::string &password, const std::string &key); + + static std::string decryptPassword(std::string &encrypted, const std::string &key); + + static std::string serializeGroups(const std::vector &groups); + + static std::vector deserializeGroups(std::string &groups); + /// Virtual desctructor. virtual ~StorageBackend() {} diff --git a/include/transport/util.h b/include/transport/util.h index 3301ad90d6e3178021509343c6dd98dbdf1e3e82..490724bf37620b5d4567ef4386e2b6ecef1cf43f 100644 --- a/include/transport/util.h +++ b/include/transport/util.h @@ -26,19 +26,16 @@ #include #include "Swiften/StringCodecs/Base64.h" +#include +#include "transport/config.h" + namespace Transport { namespace Util { -void removeEverythingOlderThan(const std::vector &dirs, time_t t); - -std::string encryptPassword(const std::string &password, const std::string &key); +void createDirectories(Transport::Config *config, const boost::filesystem::path& ph); -std::string decryptPassword(std::string &encrypted, const std::string &key); - -std::string serializeGroups(const std::vector &groups); - -std::vector deserializeGroups(std::string &groups); +void removeEverythingOlderThan(const std::vector &dirs, time_t t); int getRandomPort(const std::string &s); diff --git a/plugin/cpp/CMakeLists.txt b/plugin/cpp/CMakeLists.txt index d80b8f599d094d8d2c4614299dfe7eb45a10a44b..75ea2aa156b5523670fc8c59824471e30a13e58c 100644 --- a/plugin/cpp/CMakeLists.txt +++ b/plugin/cpp/CMakeLists.txt @@ -5,6 +5,7 @@ FILE(GLOB HEADERS ../include/transport/*.h) set(EXTRA_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../src/memoryusage.cpp) set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/logging.cpp) set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/config.cpp) +set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/util.cpp) set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) if (NOT WIN32) diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 962b9d606a119bdd4daafcab1e4a017de5169e3b..2ae15fdcf957cd4e02f5318cc30123d6e4bc2bcb 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -22,6 +22,7 @@ #include #ifndef WIN32 #include "sys/signal.h" +#include "sys/stat.h" #include #include #include @@ -248,9 +249,14 @@ int main(int argc, char **argv) return 1; } +#ifndef WIN32 + mode_t old_cmask = umask(0007); +#endif + // create directories try { - boost::filesystem::create_directories(CONFIG_STRING(&config, "service.working_dir")); + + Transport::Util::createDirectories(&config, CONFIG_STRING(&config, "service.working_dir")); } catch (...) { std::cerr << "Can't create service.working_dir directory " << CONFIG_STRING(&config, "service.working_dir") << ".\n"; @@ -284,20 +290,6 @@ int main(int argc, char **argv) #endif #ifndef WIN32 - if (!CONFIG_STRING(&config, "service.group").empty() ||!CONFIG_STRING(&config, "service.user").empty() ) { - struct group *gr; - if ((gr = getgrnam(CONFIG_STRING(&config, "service.group").c_str())) == NULL) { - std::cerr << "Invalid service.group name " << CONFIG_STRING(&config, "service.group") << "\n"; - return 1; - } - struct passwd *pw; - if ((pw = getpwnam(CONFIG_STRING(&config, "service.user").c_str())) == NULL) { - std::cerr << "Invalid service.user name " << CONFIG_STRING(&config, "service.user") << "\n"; - return 1; - } - chown(CONFIG_STRING(&config, "service.working_dir").c_str(), pw->pw_uid, gr->gr_gid); - } - char backendport[20]; FILE* port_file_f; port_file_f = fopen(CONFIG_STRING(&config, "service.portfile").c_str(), "w+"); @@ -423,6 +415,10 @@ int main(int argc, char **argv) eventLoop.run(); +#ifndef WIN32 + umask(old_cmask); +#endif + if (userRegistration) { userRegistration->stop(); delete userRegistration; diff --git a/src/logging.cpp b/src/logging.cpp index f724993ef91b34f51756ffe97573e1147bd6be39..a7f8478b090172d28f076dfeb8dd0de89c02f510 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -20,6 +20,7 @@ #include "transport/logging.h" #include "transport/config.h" +#include "transport/util.h" #include #include #include @@ -31,6 +32,7 @@ #ifndef WIN32 #include "sys/signal.h" +#include #include #include #include @@ -136,35 +138,42 @@ static void initLogging(Config *config, std::string key) { break; } } - + mode_t old_cmask; if (!dir.empty()) { // create directories +#ifndef WIN32 + old_cmask = umask(0007); +#endif try { - boost::filesystem::create_directories( - boost::filesystem::path(dir).parent_path().string() - ); + Transport::Util::createDirectories(config, boost::filesystem::path(dir).parent_path()); } - catch (...) { - std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ".\n"; + catch (const boost::filesystem::filesystem_error &e) { + std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ": " << e.what() << ".\n"; } + } -#ifndef WIN32 - if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) { - struct group *gr; - if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) { - std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n"; - } - struct passwd *pw; - if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) { - std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n"; - } - chown(dir.c_str(), pw->pw_uid, gr->gr_gid); - } + log4cxx::PropertyConfigurator::configure(p); -#endif + // Change owner of main log file +#ifndef WIN32 + if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) { + struct group *gr; + if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) { + std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n"; } + struct passwd *pw; + if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) { + std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n"; + } + chown(dir.c_str(), pw->pw_uid, gr->gr_gid); + } +#endif - log4cxx::PropertyConfigurator::configure(p); +#ifndef WIN32 + if (!dir.empty()) { + umask(old_cmask); + } +#endif } } diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index 67aa6508e3b904045ee3f726aeb97543cff025b4..f0769368e1cb887385074e38c91a1a3dc92d4d43 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -421,7 +421,7 @@ bool MySQLBackend::exec(const std::string &query) { void MySQLBackend::setUser(const UserInfo &user) { std::string encrypted = user.password; if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { - encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); + encrypted = StorageBackend::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } *m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.uin << encrypted; EXEC(m_setUser, setUser(user)); @@ -439,7 +439,7 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { *m_getUser >> user.id >> user.jid >> user.uin >> user.password >> user.encoding >> user.language >> user.vip; if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { - user.password = Util::decryptPassword(user.password, CONFIG_STRING(m_config, "database.encryption_key")); + user.password = StorageBackend::decryptPassword(user.password, CONFIG_STRING(m_config, "database.encryption_key")); } } @@ -467,7 +467,7 @@ bool MySQLBackend::getOnlineUsers(std::vector &users) { long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { // "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)" - std::string groups = Util::serializeGroups(buddyInfo.groups); + std::string groups = StorageBackend::serializeGroups(buddyInfo.groups); *m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription; *m_addBuddy << groups; *m_addBuddy << buddyInfo.alias << buddyInfo.flags; @@ -517,7 +517,7 @@ void MySQLBackend::removeBuddy(long id) { void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { // "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?" - std::string groups = Util::serializeGroups(buddyInfo.groups); + std::string groups = StorageBackend::serializeGroups(buddyInfo.groups); *m_updateBuddy << groups; *m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription; *m_updateBuddy << userId << buddyInfo.legacyName; @@ -547,7 +547,7 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { *m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags; if (!group.empty()) { - b.groups = Util::deserializeGroups(group); + b.groups = StorageBackend::deserializeGroups(group); } roster.push_back(b); diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index c2ae45804d0d5f8f0f76dac9492fec2f4c13e430..90fffb87b69b48d92bf63bf12d0854a7251a42ef 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -157,7 +157,7 @@ bool PQXXBackend::exec(pqxx::nontransaction &txn, const std::string &query, bool void PQXXBackend::setUser(const UserInfo &user) { std::string encrypted = user.password; if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { - encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); + encrypted = StorageBackend::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } try { pqxx::nontransaction txn(*m_conn); @@ -236,7 +236,7 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { + "(" + pqxx::to_string(userId) + "," + quote(txn, buddyInfo.legacyName) + "," + quote(txn, buddyInfo.subscription) + "," - + quote(txn, Util::serializeGroups(buddyInfo.groups)) + "," + + quote(txn, StorageBackend::serializeGroups(buddyInfo.groups)) + "," + quote(txn, buddyInfo.alias) + "," + pqxx::to_string(buddyInfo.flags) + ") RETURNING id"); @@ -263,7 +263,7 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { try { pqxx::nontransaction txn(*m_conn); - txn.exec("UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); + txn.exec("UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, StorageBackend::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -287,7 +287,7 @@ bool PQXXBackend::getBuddies(long id, std::list &roster) { b.flags = r[0][5].as(); if (!group.empty()) { - b.groups = Util::deserializeGroups(group); + b.groups = StorageBackend::deserializeGroups(group); } roster.push_back(b); diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index 3de7371b0bddf798f3d93a765af1adecdd86ed23..b95deb3fe85ae96d41dc92d320bd8cb30f90c198 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -287,7 +287,7 @@ long SQLite3Backend::addBuddy(long userId, const BuddyInfo &buddyInfo) { BIND_INT(m_addBuddy, userId); BIND_STR(m_addBuddy, buddyInfo.legacyName); BIND_STR(m_addBuddy, buddyInfo.subscription); - BIND_STR(m_addBuddy, Util::serializeGroups(buddyInfo.groups)); + BIND_STR(m_addBuddy, StorageBackend::serializeGroups(buddyInfo.groups)); BIND_STR(m_addBuddy, buddyInfo.alias); BIND_INT(m_addBuddy, buddyInfo.flags); @@ -313,7 +313,7 @@ long SQLite3Backend::addBuddy(long userId, const BuddyInfo &buddyInfo) { void SQLite3Backend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { // UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=? BEGIN(m_updateBuddy); - BIND_STR(m_updateBuddy, Util::serializeGroups(buddyInfo.groups)); + BIND_STR(m_updateBuddy, StorageBackend::serializeGroups(buddyInfo.groups)); BIND_STR(m_updateBuddy, buddyInfo.alias); BIND_INT(m_updateBuddy, buddyInfo.flags); BIND_STR(m_updateBuddy, buddyInfo.subscription); @@ -355,7 +355,7 @@ bool SQLite3Backend::getBuddies(long id, std::list &roster) { b.subscription = GET_STR(m_getBuddies); b.alias = GET_STR(m_getBuddies); std::string groups = GET_STR(m_getBuddies); - b.groups = Util::deserializeGroups(groups); + b.groups = StorageBackend::deserializeGroups(groups); b.flags = GET_INT(m_getBuddies); if (buddy_id == b.id) { diff --git a/src/storagebackend.cpp b/src/storagebackend.cpp index ec87e33b3c2ae08eb8632a855408034138b8a032..ce27dfae0e46cb7914b86e68977b3befb73e2f27 100644 --- a/src/storagebackend.cpp +++ b/src/storagebackend.cpp @@ -5,6 +5,8 @@ #include "transport/mysqlbackend.h" #include "transport/pqxxbackend.h" +#include "Swiften/Swiften.h" + namespace Transport { StorageBackend *StorageBackend::createBackend(Config *config, std::string &error) { @@ -47,4 +49,56 @@ StorageBackend *StorageBackend::createBackend(Config *config, std::string &error return storageBackend; } +std::string StorageBackend::encryptPassword(const std::string &password, const std::string &key) { + std::string encrypted; + encrypted.resize(password.size()); + for (int i = 0; i < password.size(); i++) { + char c = password[i]; + char keychar = key[i % key.size()]; + c += keychar; + encrypted[i] = c; + } + + encrypted = Swift::Base64::encode(Swift::createByteArray(encrypted)); + return encrypted; +} + +std::string StorageBackend::decryptPassword(std::string &encrypted, const std::string &key) { + encrypted = Swift::byteArrayToString(Swift::Base64::decode(encrypted)); + std::string password; + password.resize(encrypted.size()); + for (int i = 0; i < encrypted.size(); i++) { + char c = encrypted[i]; + char keychar = key[i % key.size()]; + c -= keychar; + password[i] = c; + } + + return password; +} + +std::string StorageBackend::serializeGroups(const std::vector &groups) { + std::string ret; + BOOST_FOREACH(const std::string &group, groups) { + ret += group + "\n"; + } + if (!ret.empty()) { + ret.erase(ret.end() - 1); + } + return ret; +} + +std::vector StorageBackend::deserializeGroups(std::string &groups) { + std::vector ret; + if (groups.empty()) { + return ret; + } + + boost::split(ret, groups, boost::is_any_of("\n")); + if (ret.back().empty()) { + ret.erase(ret.end() - 1); + } + return ret; +} + } diff --git a/src/tests/util.cpp b/src/tests/util.cpp index f5c66819974148e45579dbfd2b4bb0f9b81f76d6..c091f2ece0832c8ce7c4f59230a9aa1523f36731 100644 --- a/src/tests/util.cpp +++ b/src/tests/util.cpp @@ -3,6 +3,7 @@ #include "transport/storagebackend.h" #include "transport/user.h" #include "transport/transport.h" +#include "transport/storagebackend.h" #include "transport/conversation.h" #include "transport/usermanager.h" #include "transport/localbuddy.h" @@ -36,8 +37,8 @@ class UtilTest : public CPPUNIT_NS :: TestFixture{ } void encryptDecryptPassword() { - std::string encrypted = Util::encryptPassword("password", "key"); - CPPUNIT_ASSERT_EQUAL(std::string("password"), Util::decryptPassword(encrypted, "key")); + std::string encrypted = StorageBackend::encryptPassword("password", "key"); + CPPUNIT_ASSERT_EQUAL(std::string("password"), StorageBackend::decryptPassword(encrypted, "key")); } }; diff --git a/src/util.cpp b/src/util.cpp index 7589f21314dd71dfe2e1c3918bd5f49a5da95782..b8c3adc590bfad40393e57da69843a0f7fc8ef96 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -19,6 +19,7 @@ */ #include "transport/util.h" +#include "transport/config.h" #include #include #include @@ -27,6 +28,19 @@ #include #include +#ifndef WIN32 +#include "sys/signal.h" +#include +#include +#include +#include +#include "libgen.h" +#else +#include +#include +#define getpid _getpid +#endif + using namespace boost::filesystem; using namespace boost; @@ -35,6 +49,32 @@ namespace Transport { namespace Util { +void createDirectories(Transport::Config *config, const boost::filesystem::path& ph) { + if (ph.empty() || exists(ph)) { + return; + } + + // First create branch, by calling ourself recursively + createDirectories(config, ph.branch_path()); + + // Now that parent's path exists, create the directory + create_directory(ph); + +#ifndef WIN32 + if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) { + struct group *gr; + if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) { + std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n"; + } + struct passwd *pw; + if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) { + std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n"; + } + chown(ph.string().c_str(), pw->pw_uid, gr->gr_gid); + } +#endif +} + void removeEverythingOlderThan(const std::vector &dirs, time_t t) { BOOST_FOREACH(const std::string &dir, dirs) { path p(dir); @@ -58,7 +98,7 @@ void removeEverythingOlderThan(const std::vector &dirs, time_t t) { std::vector nextDirs; nextDirs.push_back(itr->path().string()); removeEverythingOlderThan(nextDirs, t); - if (is_empty(itr->path())) { + if (boost::filesystem::is_empty(itr->path())) { remove_all(itr->path()); } } @@ -77,58 +117,6 @@ void removeEverythingOlderThan(const std::vector &dirs, time_t t) { } } -std::string encryptPassword(const std::string &password, const std::string &key) { - std::string encrypted; - encrypted.resize(password.size()); - for (int i = 0; i < password.size(); i++) { - char c = password[i]; - char keychar = key[i % key.size()]; - c += keychar; - encrypted[i] = c; - } - - encrypted = Swift::Base64::encode(Swift::createByteArray(encrypted)); - return encrypted; -} - -std::string decryptPassword(std::string &encrypted, const std::string &key) { - encrypted = Swift::byteArrayToString(Swift::Base64::decode(encrypted)); - std::string password; - password.resize(encrypted.size()); - for (int i = 0; i < encrypted.size(); i++) { - char c = encrypted[i]; - char keychar = key[i % key.size()]; - c -= keychar; - password[i] = c; - } - - return password; -} - -std::string serializeGroups(const std::vector &groups) { - std::string ret; - BOOST_FOREACH(const std::string &group, groups) { - ret += group + "\n"; - } - if (!ret.empty()) { - ret.erase(ret.end() - 1); - } - return ret; -} - -std::vector deserializeGroups(std::string &groups) { - std::vector ret; - if (groups.empty()) { - return ret; - } - - boost::split(ret, groups, boost::is_any_of("\n")); - if (ret.back().empty()) { - ret.erase(ret.end() - 1); - } - return ret; -} - int getRandomPort(const std::string &s) { unsigned long r = 0; BOOST_FOREACH(char c, s) {