From: Maksym Mamontov Date: Mon, 11 May 2020 09:59:50 +0000 (+0300) Subject: Remove (always broken) FreeRADIUS support. X-Git-Url: https://git.stg.codes/stg.git/commitdiff_plain/6e6de2ae8f5f661500c565aca8c36277e860b834?hp=312c0eec08cfff18956ff4e238f6b6982bb0e721 Remove (always broken) FreeRADIUS support. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index c9b78497..2ca56686 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,6 @@ endif( CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.5 ) option ( BUILD_STG "Build Stargazer server." OFF ) option ( BUILD_SGCONF "Build SGConf client." OFF ) option ( BUILD_RSCRIPTD "Build RScriptD server." OFF ) -option ( BUILD_RLM_STG "Build rlm_stg FreeRADIUS module." OFF ) option ( BUILD_SGAUTH "Build SGAuth client." OFF ) # General modules @@ -36,7 +35,6 @@ option ( BUILD_MOD_STORE_MYSQL "Build MySQL store STG module." OFF ) option ( BUILD_MOD_RPCCONFIG "Build XML-RPC configuretion STG module." OFF ) option ( BUILD_MOD_CAP_PCAP "Build PCap capture STG module." OFF ) option ( BUILD_MOD_CAP_NFQUEUE "Build NFQueue capture STG module." OFF ) -option ( BUILD_MOD_RADIUS "Build rlm_stg backend STG module." OFF ) # Grouping option ( BUILD_ALL_MODS "Build all modules." OFF ) @@ -51,7 +49,6 @@ if ( BUILD_ALL ) set ( BUILD_TESTS ON ) set ( BUILD_SGAUTH ON ) set ( BUILD_RSCRIPTD ON ) - set ( BUILD_RLM_STG ON ) set ( BUILD_SGCONF ON ) set ( BUILD_STG ON ) endif ( BUILD_ALL ) @@ -76,10 +73,9 @@ if ( BUILD_RSCRIPTD OR BUILD_ALL_LIBS ) set ( BUILD_LIB_SCRIPTEXECUTER ON ) endif ( BUILD_RSCRIPTD OR BUILD_ALL_LIBS ) -if ( BUILD_RLM_STG OR BUILD_ALL_LIBS ) +if ( BUILD_ALL_LIBS ) set ( BUILD_LIB_CRYPTO ON ) - set ( BUILD_LIB_JSON ON ) -endif ( BUILD_RLM_STG OR BUILD_ALL_LIBS ) +endif ( BUILD_ALL_LIBS ) if ( BUILD_STG OR BUILD_ALL_LIBS ) set ( BUILD_LIB_CONFFILES ON ) @@ -95,18 +91,12 @@ if ( BUILD_ALL_MODS ) set ( BUILD_MOD_STORE_POSTGRESQL ON ) set ( BUILD_MOD_RPCCONFIG ON ) set ( BUILD_MOD_CAP_PCAP ON ) - set ( BUILD_MOD_RADIUS ON ) endif ( BUILD_ALL_MODS ) if ( BUILD_MOD_STORE_FIREBIRD OR BUILD_ALL_LIBS ) set ( BUILD_LIB_IBPP ON ) endif ( BUILD_MOD_STORE_FIREBIRD OR BUILD_ALL_LIBS ) -if ( BUILD_MOD_RADIUS OR BUILD_ALL_LIBS ) - set ( BUILD_LIB_JSON ON ) - set ( BUILD_LIB_IBPP ON ) -endif ( BUILD_MOD_RADIUS OR BUILD_ALL_LIBS ) - if ( BUILD_MOD_PING OR BUILD_ALL_LIBS ) set ( BUILD_LIB_PINGER ON ) endif ( BUILD_MOD_PING OR BUILD_ALL_LIBS ) @@ -154,10 +144,6 @@ include_directories ( include ) add_subdirectory ( libs ) -if ( BUILD_RLM_STG ) - add_subdirectory ( rlm_stg ) -endif ( BUILD_RLM_STG ) - if ( BUILD_RSCRIPTD ) add_subdirectory ( rscriptd ) endif ( BUILD_RSCRIPTD ) diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index f413010e..bc632f03 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -34,13 +34,6 @@ if ( BUILD_LIB_IBPP ) target_compile_options ( ibpp PRIVATE -Wno-old-style-cast $<$:-Wno-useless-cast> ) endif ( BUILD_LIB_IBPP ) -if ( BUILD_LIB_JSON ) - find_package ( YAJL REQUIRED ) - add_library ( json STATIC json/generator.cpp json/parser.cpp ) - target_include_directories ( json PUBLIC json/include ) - target_link_libraries ( json common YAJL::YAJL ) -endif ( BUILD_LIB_JSON ) - if ( BUILD_LIB_LOGGER ) add_library ( logger STATIC logger/logger.cpp ) target_include_directories ( logger PUBLIC logger/include ) diff --git a/rlm_stg/CMakeLists.txt b/rlm_stg/CMakeLists.txt deleted file mode 100644 index 70291038..00000000 --- a/rlm_stg/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -find_package ( YAJL REQUIRED ) - -set ( CPP_FILES conn.cpp iface.cpp stg_client.cpp ) -set ( C_FILES rlm_stg.c radlog.c ) - -set ( THREADS_PREFER_PTHREAD_FLAG ON ) -find_package ( Threads REQUIRED ) - -add_library ( rlm_stg MODULE ${CPP_FILES} ${C_FILES} ) - -target_link_libraries ( rlm_stg crypto common json dl YAJL::YAJL ) - -# TODO: install diff --git a/rlm_stg/conn.cpp b/rlm_stg/conn.cpp deleted file mode 100644 index 3589a901..00000000 --- a/rlm_stg/conn.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#include "conn.h" - -#include "radlog.h" -#include "stgpair.h" - -#include "stg/json_parser.h" -#include "stg/json_generator.h" -#include "stg/locker.h" - -#include -#include - -#include -#include -#include // UNIX -#include // IP -#include // TCP -#include - -namespace RLM = STG::RLM; - -using RLM::Conn; -using STG::JSON::Parser; -using STG::JSON::PairsParser; -using STG::JSON::EnumParser; -using STG::JSON::NodeParser; -using STG::JSON::Gen; -using STG::JSON::MapGen; -using STG::JSON::StringGen; - -namespace -{ - -double CONN_TIMEOUT = 60; -double PING_TIMEOUT = 10; - -struct ChannelConfig { - struct Error : std::runtime_error { - explicit Error(const std::string& message) : runtime_error(message) {} - }; - - explicit ChannelConfig(std::string address); - - std::string transport; - std::string key; - std::string address; - std::string portStr; - uint16_t port; -}; - -std::string toStage(RLM::REQUEST_TYPE type) -{ - switch (type) - { - case RLM::AUTHORIZE: return "authorize"; - case RLM::AUTHENTICATE: return "authenticate"; - case RLM::POST_AUTH: return "postauth"; - case RLM::PRE_ACCT: return "preacct"; - case RLM::ACCOUNT: return "accounting"; - } - return ""; -} - -enum Packet -{ - PING, - PONG, - DATA -}; - -std::map packetCodes; -std::map resultCodes; -std::map returnCodes; - -class PacketParser : public EnumParser -{ - public: - PacketParser(NodeParser* next, Packet& packet, std::string& packetStr) - : EnumParser(next, packet, packetStr, packetCodes) - { - if (!packetCodes.empty()) - return; - packetCodes["ping"] = PING; - packetCodes["pong"] = PONG; - packetCodes["data"] = DATA; - } -}; - -class ResultParser : public EnumParser -{ - public: - ResultParser(NodeParser* next, bool& result, std::string& resultStr) - : EnumParser(next, result, resultStr, resultCodes) - { - if (!resultCodes.empty()) - return; - resultCodes["no"] = false; - resultCodes["ok"] = true; - } -}; - -class ReturnCodeParser : public EnumParser -{ - public: - ReturnCodeParser(NodeParser* next, int& returnCode, std::string& returnCodeStr) - : EnumParser(next, returnCode, returnCodeStr, returnCodes) - { - if (!returnCodes.empty()) - return; - returnCodes["reject"] = STG_REJECT; - returnCodes["fail"] = STG_FAIL; - returnCodes["ok"] = STG_OK; - returnCodes["handled"] = STG_HANDLED; - returnCodes["invalid"] = STG_INVALID; - returnCodes["userlock"] = STG_USERLOCK; - returnCodes["notfound"] = STG_NOTFOUND; - returnCodes["noop"] = STG_NOOP; - returnCodes["updated"] = STG_UPDATED; - } -}; - -class TopParser : public NodeParser -{ - public: - typedef void (*Callback) (void* /*data*/); - TopParser(Callback callback, void* data) - : m_packet(PING), - m_result(false), - m_returnCode(STG_REJECT), - m_packetParser(this, m_packet, m_packetStr), - m_resultParser(this, m_result, m_resultStr), - m_returnCodeParser(this, m_returnCode, m_returnCodeStr), - m_replyParser(this, m_reply), - m_modifyParser(this, m_modify), - m_callback(callback), m_data(data) - {} - - virtual NodeParser* parseStartMap() { return this; } - virtual NodeParser* parseMapKey(const std::string& value) - { - std::string key = ToLower(value); - - if (key == "packet") - return &m_packetParser; - else if (key == "result") - return &m_resultParser; - else if (key == "reply") - return &m_replyParser; - else if (key == "modify") - return &m_modifyParser; - else if (key == "return_code") - return &m_returnCodeParser; - - return this; - } - virtual NodeParser* parseEndMap() { m_callback(m_data); return this; } - - const std::string& packetStr() const { return m_packetStr; } - Packet packet() const { return m_packet; } - const std::string& resultStr() const { return m_resultStr; } - bool result() const { return m_result; } - const std::string& returnCodeStr() const { return m_returnCodeStr; } - int returnCode() const { return m_returnCode; } - const PairsParser::Pairs& reply() const { return m_reply; } - const PairsParser::Pairs& modify() const { return m_modify; } - - private: - std::string m_packetStr; - Packet m_packet; - std::string m_resultStr; - bool m_result; - std::string m_returnCodeStr; - int m_returnCode; - PairsParser::Pairs m_reply; - PairsParser::Pairs m_modify; - - PacketParser m_packetParser; - ResultParser m_resultParser; - ReturnCodeParser m_returnCodeParser; - PairsParser m_replyParser; - PairsParser m_modifyParser; - - Callback m_callback; - void* m_data; -}; - -class ProtoParser : public Parser -{ - public: - ProtoParser(TopParser::Callback callback, void* data) - : Parser( &m_topParser ), - m_topParser(callback, data) - {} - - const std::string& packetStr() const { return m_topParser.packetStr(); } - Packet packet() const { return m_topParser.packet(); } - const std::string& resultStr() const { return m_topParser.resultStr(); } - bool result() const { return m_topParser.result(); } - const std::string& returnCodeStr() const { return m_topParser.returnCodeStr(); } - int returnCode() const { return m_topParser.returnCode(); } - const PairsParser::Pairs& reply() const { return m_topParser.reply(); } - const PairsParser::Pairs& modify() const { return m_topParser.modify(); } - - private: - TopParser m_topParser; -}; - -class PacketGen : public Gen -{ - public: - explicit PacketGen(const std::string& type) - : m_type(type) - { - m_gen.add("packet", m_type); - } - void run(yajl_gen_t* handle) const - { - m_gen.run(handle); - } - PacketGen& add(const std::string& key, const std::string& value) - { - m_gen.add(key, new StringGen(value)); - return *this; - } - PacketGen& add(const std::string& key, MapGen& map) - { - m_gen.add(key, map); - return *this; - } - private: - MapGen m_gen; - StringGen m_type; -}; - -} - -class Conn::Impl -{ -public: - Impl(const std::string& address, Callback callback, void* data); - ~Impl(); - - bool stop(); - bool connected() const { return m_connected; } - - bool request(REQUEST_TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs); - -private: - ChannelConfig m_config; - - int m_sock; - - bool m_running; - bool m_stopped; - - time_t m_lastPing; - time_t m_lastActivity; - - pthread_t m_thread; - pthread_mutex_t m_mutex; - - Callback m_callback; - void* m_data; - - ProtoParser m_parser; - - bool m_connected; - - void m_writeHeader(REQUEST_TYPE type, const std::string& userName, const std::string& password); - void m_writePairBlock(const PAIRS& source); - PAIRS m_readPairBlock(); - - static void* run(void* ); - - void runImpl(); - - bool start(); - - int connect(); - int connectTCP(); - int connectUNIX(); - - bool read(); - bool tick(); - - static void process(void* data); - void processPing(); - void processPong(); - void processData(); - bool sendPing(); - bool sendPong(); - - static bool write(void* data, const char* buf, size_t size); -}; - -ChannelConfig::ChannelConfig(std::string addr) -{ - // unix:pass@/var/run/stg.sock - // tcp:secret@192.168.0.1:12345 - // udp:key@isp.com.ua:54321 - - size_t pos = addr.find_first_of(':'); - if (pos == std::string::npos) - throw Error("Missing transport name."); - transport = ToLower(addr.substr(0, pos)); - addr = addr.substr(pos + 1); - if (addr.empty()) - throw Error("Missing address to connect to."); - pos = addr.find_first_of('@'); - if (pos != std::string::npos) { - key = addr.substr(0, pos); - addr = addr.substr(pos + 1); - if (addr.empty()) - throw Error("Missing address to connect to."); - } - if (transport == "unix") - { - address = addr; - return; - } - pos = addr.find_first_of(':'); - if (pos == std::string::npos) - throw Error("Missing port."); - address = addr.substr(0, pos); - portStr = addr.substr(pos + 1); - if (str2x(portStr, port)) - throw Error("Invalid port value."); -} - -Conn::Conn(const std::string& address, Callback callback, void* data) - : m_impl(new Impl(address, callback, data)) -{ -} - -Conn::~Conn() -{ -} - -bool Conn::stop() -{ - return m_impl->stop(); -} - -bool Conn::connected() const -{ - return m_impl->connected(); -} - -bool Conn::request(REQUEST_TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs) -{ - return m_impl->request(type, userName, password, pairs); -} - -Conn::Impl::Impl(const std::string& address, Callback callback, void* data) - : m_config(address), - m_sock(connect()), - m_running(false), - m_stopped(true), - m_lastPing(time(NULL)), - m_lastActivity(m_lastPing), - m_callback(callback), - m_data(data), - m_parser(&Conn::Impl::process, this), - m_connected(true) -{ - pthread_mutex_init(&m_mutex, NULL); -} - -Conn::Impl::~Impl() -{ - stop(); - shutdown(m_sock, SHUT_RDWR); - close(m_sock); - pthread_mutex_destroy(&m_mutex); -} - -bool Conn::Impl::stop() -{ - m_connected = false; - - if (m_stopped) - return true; - - m_running = false; - - for (size_t i = 0; i < 25 && !m_stopped; i++) { - struct timespec ts = {0, 200000000}; - nanosleep(&ts, NULL); - } - - if (m_stopped) { - pthread_join(m_thread, NULL); - return true; - } - - return false; -} - -bool Conn::Impl::request(REQUEST_TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs) -{ - if (!m_running) - if (!start()) - return false; - MapGen map; - for (PAIRS::const_iterator it = pairs.begin(); it != pairs.end(); ++it) - map.add(it->first, new StringGen(it->second)); - map.add("Radius-Username", new StringGen(userName)); - map.add("Radius-Userpass", new StringGen(password)); - - PacketGen gen("data"); - gen.add("stage", toStage(type)) - .add("pairs", map); - - STG_LOCKER lock(m_mutex); - - m_lastPing = time(NULL); - - return generate(gen, &Conn::Impl::write, this); -} - -void Conn::Impl::runImpl() -{ - m_running = true; - - while (m_running) { - fd_set fds; - - FD_ZERO(&fds); - FD_SET(m_sock, &fds); - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 500000; - - int res = select(m_sock + 1, &fds, NULL, NULL, &tv); - if (res < 0) - { - if (errno == EINTR) - continue; - RadLog("'select' is failed: %s", strerror(errno)); - break; - } - - - if (!m_running) - break; - - STG_LOCKER lock(m_mutex); - - if (res > 0) - { - if (FD_ISSET(m_sock, &fds)) - m_running = read(); - } - else - m_running = tick(); - } - - m_connected = false; - m_stopped = true; -} - -bool Conn::Impl::start() -{ - int res = pthread_create(&m_thread, NULL, &Conn::Impl::run, this); - if (res != 0) - return false; - return true; -} - -int Conn::Impl::connect() -{ - if (m_config.transport == "tcp") - return connectTCP(); - else if (m_config.transport == "unix") - return connectUNIX(); - throw Error("Invalid transport type: '" + m_config.transport + "'. Should be 'tcp' or 'unix'."); -} - -int Conn::Impl::connectTCP() -{ - addrinfo hints; - memset(&hints, 0, sizeof(addrinfo)); - - hints.ai_family = AF_INET; /* Allow IPv4 */ - hints.ai_socktype = SOCK_STREAM; /* Stream socket */ - hints.ai_flags = 0; /* For wildcard IP address */ - hints.ai_protocol = 0; /* Any protocol */ - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - addrinfo* ais = NULL; - int res = getaddrinfo(m_config.address.c_str(), m_config.portStr.c_str(), &hints, &ais); - if (res != 0) - throw Error("Error resolvin address '" + m_config.address + "': " + gai_strerror(res)); - - for (addrinfo* ai = ais; ai != NULL; ai = ai->ai_next) - { - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - { - Error error(std::string("Error creating TCP socket: ") + strerror(errno)); - freeaddrinfo(ais); - throw error; - } - if (::connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) - { - shutdown(fd, SHUT_RDWR); - close(fd); - RadLog("'connect' is failed: %s", strerror(errno)); - continue; - } - freeaddrinfo(ais); - return fd; - } - - freeaddrinfo(ais); - - throw Error("Failed to resolve '" + m_config.address); -}; - -int Conn::Impl::connectUNIX() -{ - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) - throw Error(std::string("Error creating UNIX socket: ") + strerror(errno)); - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, m_config.address.c_str(), m_config.address.length()); - if (::connect(fd, reinterpret_cast(&addr), sizeof(addr)) == -1) - { - Error error(std::string("Error connecting UNIX socket: ") + strerror(errno)); - shutdown(fd, SHUT_RDWR); - close(fd); - throw error; - } - return fd; -} - -bool Conn::Impl::read() -{ - static std::vector buffer(1024); - ssize_t res = ::read(m_sock, buffer.data(), buffer.size()); - if (res < 0) - { - RadLog("Failed to read data: %s", strerror(errno)); - return false; - } - m_lastActivity = time(NULL); - RadLog("Read %d bytes.\n%s\n", res, std::string(buffer.data(), res).c_str()); - if (res == 0) - { - m_parser.last(); - return false; - } - return m_parser.append(buffer.data(), res); -} - -bool Conn::Impl::tick() -{ - time_t now = time(NULL); - if (difftime(now, m_lastActivity) > CONN_TIMEOUT) - { - int delta = difftime(now, m_lastActivity); - RadLog("Connection timeout: %d sec.", delta); - //m_logger("Connection to " + m_remote + " timed out."); - return false; - } - if (difftime(now, m_lastPing) > PING_TIMEOUT) - { - int delta = difftime(now, m_lastPing); - RadLog("Ping timeout: %d sec. Sending ping...", delta); - sendPing(); - } - return true; -} - -void Conn::Impl::process(void* data) -{ - Impl& impl = *static_cast(data); - switch (impl.m_parser.packet()) - { - case PING: - impl.processPing(); - return; - case PONG: - impl.processPong(); - return; - case DATA: - impl.processData(); - return; - } - RadLog("Received invalid packet type: '%s'.", impl.m_parser.packetStr().c_str()); -} - -void Conn::Impl::processPing() -{ - sendPong(); -} - -void Conn::Impl::processPong() -{ - m_lastActivity = time(NULL); -} - -void Conn::Impl::processData() -{ - RESULT data; - if (m_parser.result()) - { - for (PairsParser::Pairs::const_iterator it = m_parser.reply().begin(); it != m_parser.reply().end(); ++it) - data.reply.push_back(std::make_pair(it->first, it->second)); - for (PairsParser::Pairs::const_iterator it = m_parser.modify().begin(); it != m_parser.modify().end(); ++it) - data.modify.push_back(std::make_pair(it->first, it->second)); - data.returnCode = STG_UPDATED; - } - else - data.returnCode = m_parser.returnCode(); - m_callback(m_data, data); -} - -bool Conn::Impl::sendPing() -{ - PacketGen gen("ping"); - - m_lastPing = time(NULL); - - return generate(gen, &Conn::Impl::write, this); -} - -bool Conn::Impl::sendPong() -{ - PacketGen gen("pong"); - - m_lastPing = time(NULL); - - return generate(gen, &Conn::Impl::write, this); -} - -bool Conn::Impl::write(void* data, const char* buf, size_t size) -{ - std::string json(buf, size); - RadLog("Sending JSON: %s", json.c_str()); - Conn::Impl& impl = *static_cast(data); - while (size > 0) - { - ssize_t res = ::send(impl.m_sock, buf, size, MSG_NOSIGNAL); - if (res < 0) - { - impl.m_connected = false; - RadLog("Failed to write data: %s.", strerror(errno)); - return false; - } - size -= res; - } - return true; -} - -void* Conn::Impl::run(void* data) -{ - Impl& impl = *static_cast(data); - impl.runImpl(); - return NULL; -} diff --git a/rlm_stg/conn.h b/rlm_stg/conn.h deleted file mode 100644 index 92fbff82..00000000 --- a/rlm_stg/conn.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#ifndef __STG_RLM_CONN_H__ -#define __STG_RLM_CONN_H__ - -#include "types.h" - -#include -#include -#include -#include - -namespace STG -{ -namespace RLM -{ - -class Conn -{ - public: - struct Error : std::runtime_error { - explicit Error(const std::string& message) : runtime_error(message) {} - }; - - typedef bool (*Callback)(void* /*data*/, const RESULT& /*result*/); - - Conn(const std::string& address, Callback callback, void* data); - ~Conn(); - - bool stop(); - bool connected() const; - - bool request(REQUEST_TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs); - - private: - class Impl; - std::unique_ptr m_impl; -}; - -} -} - -#endif diff --git a/rlm_stg/iface.cpp b/rlm_stg/iface.cpp deleted file mode 100644 index f97593f4..00000000 --- a/rlm_stg/iface.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "iface.h" - -#include "stg_client.h" -#include "types.h" -#include "radlog.h" - -#include -#include - -#include - -namespace RLM = STG::RLM; - -using RLM::Client; -using RLM::PAIRS; -using RLM::RESULT; -using RLM::REQUEST_TYPE; - -namespace -{ - -STG_PAIR* toSTGPairs(const PAIRS& source) -{ - STG_PAIR * pairs = new STG_PAIR[source.size() + 1]; - for (size_t pos = 0; pos < source.size(); ++pos) { - bzero(pairs[pos].key, sizeof(pairs[pos].key)); - bzero(pairs[pos].value, sizeof(pairs[pos].value)); - strncpy(pairs[pos].key, source[pos].first.c_str(), sizeof(pairs[pos].key)); - strncpy(pairs[pos].value, source[pos].second.c_str(), sizeof(pairs[pos].value)); - } - bzero(pairs[source.size()].key, sizeof(pairs[source.size()].key)); - bzero(pairs[source.size()].value, sizeof(pairs[source.size()].value)); - - return pairs; -} - -PAIRS fromSTGPairs(const STG_PAIR* pairs) -{ - const STG_PAIR* pair = pairs; - PAIRS res; - - while (!emptyPair(pair)) { - res.push_back(std::pair(pair->key, pair->value)); - ++pair; - } - - return res; -} - -STG_RESULT toResult(const RESULT& source) -{ - STG_RESULT result; - result.modify = toSTGPairs(source.modify); - result.reply = toSTGPairs(source.reply); - result.returnCode = source.returnCode; - return result; -} - -STG_RESULT emptyResult() -{ - STG_RESULT result = {NULL, NULL, STG_REJECT}; - return result; -} - -std::string toString(const char* value) -{ - if (value == NULL) - return ""; - else - return value; -} - -STG_RESULT stgRequest(REQUEST_TYPE type, const char* userName, const char* password, const STG_PAIR* pairs) -{ - Client* client = Client::get(); - if (client == NULL) { - RadLog("Client is not configured."); - return emptyResult(); - } - try { - return toResult(client->request(type, toString(userName), toString(password), fromSTGPairs(pairs))); - } catch (const std::runtime_error& ex) { - RadLog("Error: '%s'.", ex.what()); - return emptyResult(); - } -} - -} - -int stgInstantiateImpl(const char* address) -{ - if (Client::configure(toString(address))) - return 1; - - return 0; -} - -STG_RESULT stgAuthorizeImpl(const char* userName, const char* password, const STG_PAIR* pairs) -{ - return stgRequest(RLM::AUTHORIZE, userName, password, pairs); -} - -STG_RESULT stgAuthenticateImpl(const char* userName, const char* password, const STG_PAIR* pairs) -{ - return stgRequest(RLM::AUTHENTICATE, userName, password, pairs); -} - -STG_RESULT stgPostAuthImpl(const char* userName, const char* password, const STG_PAIR* pairs) -{ - return stgRequest(RLM::POST_AUTH, userName, password, pairs); -} - -STG_RESULT stgPreAcctImpl(const char* userName, const char* password, const STG_PAIR* pairs) -{ - return stgRequest(RLM::PRE_ACCT, userName, password, pairs); -} - -STG_RESULT stgAccountingImpl(const char* userName, const char* password, const STG_PAIR* pairs) -{ - return stgRequest(RLM::ACCOUNT, userName, password, pairs); -} diff --git a/rlm_stg/iface.h b/rlm_stg/iface.h deleted file mode 100644 index e863e939..00000000 --- a/rlm_stg/iface.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __STG_IFACE_H__ -#define __STG_IFACE_H__ - -#include - -#include "stgpair.h" - -#ifdef __cplusplus -extern "C" { -#endif - -int stgInstantiateImpl(const char* address); -STG_RESULT stgAuthorizeImpl(const char* userName, const char* password, const STG_PAIR* vps); -STG_RESULT stgAuthenticateImpl(const char* userName, const char* password, const STG_PAIR* vps); -STG_RESULT stgPostAuthImpl(const char* userName, const char* password, const STG_PAIR* vps); -STG_RESULT stgPreAcctImpl(const char* userName, const char* password, const STG_PAIR* vps); -STG_RESULT stgAccountingImpl(const char* userName, const char* password, const STG_PAIR* vps); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/rlm_stg/radlog.c b/rlm_stg/radlog.c deleted file mode 100644 index 523dc1c4..00000000 --- a/rlm_stg/radlog.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "radlog.h" - -//#ifndef NDEBUG -//#define NDEBUG -#include -#include -#include -//#undef NDEBUG -//#endif - -#include - -void RadLog(const char* format, ...) -{ - char buf[1024]; - - va_list vl; - va_start(vl, format); - vsnprintf(buf, sizeof(buf), format, vl); - va_end(vl); - - DEBUG("[rlm_stg] *** %s", buf); -} diff --git a/rlm_stg/radlog.h b/rlm_stg/radlog.h deleted file mode 100644 index 00a5dcb5..00000000 --- a/rlm_stg/radlog.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __STG_RADLOG_H__ -#define __STG_RADLOG_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -void RadLog(const char* format, ...); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/rlm_stg/rlm_stg.c b/rlm_stg/rlm_stg.c deleted file mode 100644 index 84df4e7b..00000000 --- a/rlm_stg/rlm_stg.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -/* - * FreeRADIUS module for data access via Stargazer - * - * $Revision: 1.8 $ - * $Date: 2010/08/14 04:15:08 $ - * - */ - -#include "iface.h" -#include "stgpair.h" - -#include -#include -#include - -#include // size_t - -typedef struct rlm_stg_t { - char* address; -} rlm_stg_t; - -static const CONF_PARSER module_config[] = { - { "address", PW_TYPE_STRING_PTR, offsetof(rlm_stg_t, address), NULL, "unix:/var/run/stg.sock"}, - - { NULL, -1, 0, NULL, NULL } /* end the list */ -}; - -static void deletePairs(STG_PAIR* pairs) -{ - free(pairs); -} - -static size_t toVPS(const STG_PAIR* pairs, VALUE_PAIR** vps) -{ - const STG_PAIR* pair = pairs; - size_t count = 0; - - while (!emptyPair(pair)) { - VALUE_PAIR* vp = pairmake(pair->key, pair->value, T_OP_SET); - if (vp != NULL) { - pairadd(vps, vp); - ++count; - } - ++pair; - } - - return count; -} - -static size_t toReply(STG_RESULT result, REQUEST* request) -{ - size_t count = 0; - - count += toVPS(result.modify, &request->config_items); - pairfree(&request->reply->vps); - count += toVPS(result.reply, &request->reply->vps); - - deletePairs(result.modify); - deletePairs(result.reply); - - return count; -} - -static int countVPS(const VALUE_PAIR* pairs) -{ - unsigned count = 0; - while (pairs != NULL) { - ++count; - pairs = pairs->next; - } - return count; -} - -static STG_PAIR* fromVPS(const VALUE_PAIR* pairs) -{ - unsigned size = countVPS(pairs); - STG_PAIR* res = (STG_PAIR*)malloc(sizeof(STG_PAIR) * (size + 1)); - size_t pos = 0; - while (pairs != NULL) { - bzero(res[pos].key, sizeof(res[0].key)); - bzero(res[pos].value, sizeof(res[0].value)); - strncpy(res[pos].key, pairs->name, sizeof(res[0].key)); - vp_prints_value(res[pos].value, sizeof(res[0].value), (VALUE_PAIR*)pairs, 0); - ++pos; - pairs = pairs->next; - } - bzero(res[pos].key, sizeof(res[0].key)); - bzero(res[pos].value, sizeof(res[0].value)); - return res; -} - -static int toRLMCode(int code) -{ - switch (code) - { - case STG_REJECT: return RLM_MODULE_REJECT; - case STG_FAIL: return RLM_MODULE_FAIL; - case STG_OK: return RLM_MODULE_OK; - case STG_HANDLED: return RLM_MODULE_HANDLED; - case STG_INVALID: return RLM_MODULE_INVALID; - case STG_USERLOCK: return RLM_MODULE_USERLOCK; - case STG_NOTFOUND: return RLM_MODULE_NOTFOUND; - case STG_NOOP: return RLM_MODULE_NOOP; - case STG_UPDATED: return RLM_MODULE_UPDATED; - } - return RLM_MODULE_REJECT; -} - -/* - * Do any per-module initialization that is separate to each - * configured instance of the module. e.g. set up connections - * to external databases, read configuration files, set up - * dictionary entries, etc. - * - * If configuration information is given in the config section - * that must be referenced in later calls, store a handle to it - * in *instance otherwise put a null pointer there. - */ -static int stg_instantiate(CONF_SECTION* conf, void** instance) -{ - rlm_stg_t* data; - - /* - * Set up a storage area for instance data - */ - data = rad_malloc(sizeof(*data)); - if (!data) - return -1; - - memset(data, 0, sizeof(*data)); - - /* - * If the configuration parameters can't be parsed, then - * fail. - */ - if (cf_section_parse(conf, data, module_config) < 0) { - free(data); - return -1; - } - - if (!stgInstantiateImpl(data->address)) { - free(data); - return -1; - } - - *instance = data; - - return 0; -} - -/* - * Find the named user in this modules database. Create the set - * of attribute-value pairs to check and reply with for this user - * from the database. The authentication code only needs to check - * the password, the rest is done here. - */ -static int stg_authorize(void* instance, REQUEST* request) -{ - STG_RESULT result; - STG_PAIR* pairs = fromVPS(request->packet->vps); - size_t count = 0; - const char* username = NULL; - const char* password = NULL; - - instance = instance; - - DEBUG("rlm_stg: stg_authorize()"); - - if (request->username) { - username = request->username->data.strvalue; - DEBUG("rlm_stg: stg_authorize() request username field: '%s'", username); - } - - if (request->password) { - password = request->password->data.strvalue; - DEBUG("rlm_stg: stg_authorize() request password field: '%s'", password); - } - - result = stgAuthorizeImpl(username, password, pairs); - deletePairs(pairs); - - if (!result.modify && !result.reply) { - DEBUG("rlm_stg: stg_authorize() failed."); - return RLM_MODULE_REJECT; - } - - count = toReply(result, request); - - if (count) - return RLM_MODULE_UPDATED; - - return toRLMCode(result.returnCode); -} - -/* - * Authenticate the user with the given password. - */ -static int stg_authenticate(void* instance, REQUEST* request) -{ - STG_RESULT result; - STG_PAIR* pairs = fromVPS(request->packet->vps); - size_t count = 0; - const char* username = NULL; - const char* password = NULL; - - instance = instance; - - DEBUG("rlm_stg: stg_authenticate()"); - - if (request->username) { - username = request->username->data.strvalue; - DEBUG("rlm_stg: stg_authenticate() request username field: '%s'", username); - } - - if (request->password) { - password = request->password->data.strvalue; - DEBUG("rlm_stg: stg_authenticate() request password field: '%s'", password); - } - - result = stgAuthenticateImpl(username, password, pairs); - deletePairs(pairs); - - if (!result.modify && !result.reply) { - DEBUG("rlm_stg: stg_authenticate() failed."); - return RLM_MODULE_REJECT; - } - - count = toReply(result, request); - - if (count) - return RLM_MODULE_UPDATED; - - return toRLMCode(result.returnCode); -} - -/* - * Massage the request before recording it or proxying it - */ -static int stg_preacct(void* instance, REQUEST* request) -{ - STG_RESULT result; - STG_PAIR* pairs = fromVPS(request->packet->vps); - size_t count = 0; - const char* username = NULL; - const char* password = NULL; - - DEBUG("rlm_stg: stg_preacct()"); - - instance = instance; - - if (request->username) { - username = request->username->data.strvalue; - DEBUG("rlm_stg: stg_preacct() request username field: '%s'", username); - } - - if (request->password) { - password = request->password->data.strvalue; - DEBUG("rlm_stg: stg_preacct() request password field: '%s'", password); - } - - result = stgPreAcctImpl(username, password, pairs); - deletePairs(pairs); - - if (!result.modify && !result.reply) { - DEBUG("rlm_stg: stg_preacct() failed."); - return RLM_MODULE_REJECT; - } - - count = toReply(result, request); - - if (count) - return RLM_MODULE_UPDATED; - - return toRLMCode(result.returnCode); -} - -/* - * Write accounting information to this modules database. - */ -static int stg_accounting(void* instance, REQUEST* request) -{ - STG_RESULT result; - STG_PAIR* pairs = fromVPS(request->packet->vps); - size_t count = 0; - const char* username = NULL; - const char* password = NULL; - - DEBUG("rlm_stg: stg_accounting()"); - - instance = instance; - - if (request->username) { - username = request->username->data.strvalue; - DEBUG("rlm_stg: stg_accounting() request username field: '%s'", username); - } - - if (request->password) { - password = request->password->data.strvalue; - DEBUG("rlm_stg: stg_accounting() request password field: '%s'", password); - } - - result = stgAccountingImpl(username, password, pairs); - deletePairs(pairs); - - if (!result.modify && !result.reply) { - DEBUG("rlm_stg: stg_accounting() failed."); - return RLM_MODULE_REJECT; - } - - count = toReply(result, request); - - if (count) - return RLM_MODULE_UPDATED; - - return toRLMCode(result.returnCode); -} - -/* - * See if a user is already logged in. Sets request->simul_count to the - * current session count for this user and sets request->simul_mpp to 2 - * if it looks like a multilink attempt based on the requested IP - * address, otherwise leaves request->simul_mpp alone. - * - * Check twice. If on the first pass the user exceeds his - * max. number of logins, do a second pass and validate all - * logins by querying the terminal server (using eg. SNMP). - */ -static int stg_checksimul(void* instance, REQUEST* request) -{ - DEBUG("rlm_stg: stg_checksimul()"); - - instance = instance; - - request->simul_count = 0; - - return RLM_MODULE_OK; -} - -static int stg_postauth(void* instance, REQUEST* request) -{ - STG_RESULT result; - STG_PAIR* pairs = fromVPS(request->packet->vps); - size_t count = 0; - const char* username = NULL; - const char* password = NULL; - - DEBUG("rlm_stg: stg_postauth()"); - - instance = instance; - - if (request->username) { - username = request->username->data.strvalue; - DEBUG("rlm_stg: stg_postauth() request username field: '%s'", username); - } - - if (request->password) { - password = request->password->data.strvalue; - DEBUG("rlm_stg: stg_postauth() request password field: '%s'", password); - } - - result = stgPostAuthImpl(username, password, pairs); - deletePairs(pairs); - - if (!result.modify && !result.reply) { - DEBUG("rlm_stg: stg_postauth() failed."); - return RLM_MODULE_REJECT; - } - - count = toReply(result, request); - - if (count) - return RLM_MODULE_UPDATED; - - return toRLMCode(result.returnCode); -} - -static int stg_detach(void* instance) -{ - free(((struct rlm_stg_t*)instance)->address); - free(instance); - return 0; -} - -module_t rlm_stg = { - RLM_MODULE_INIT, - "stg", - RLM_TYPE_THREAD_UNSAFE, /* type */ - stg_instantiate, /* instantiation */ - stg_detach, /* detach */ - { - stg_authenticate, /* authentication */ - stg_authorize, /* authorization */ - stg_preacct, /* preaccounting */ - stg_accounting, /* accounting */ - stg_checksimul, /* checksimul */ - NULL, /* pre-proxy */ - NULL, /* post-proxy */ - stg_postauth /* post-auth */ - }, -}; diff --git a/rlm_stg/stg_client.cpp b/rlm_stg/stg_client.cpp deleted file mode 100644 index 21727225..00000000 --- a/rlm_stg/stg_client.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#include "stg_client.h" - -#include "conn.h" -#include "radlog.h" - -#include "stg/locker.h" -#include "stg/common.h" - -#include -#include - -using STG::RLM::Client; -using STG::RLM::Conn; -using STG::RLM::RESULT; - -namespace { - -Client* stgClient = NULL; - -} - -class Client::Impl -{ - public: - explicit Impl(const std::string& address); - ~Impl(); - - bool stop() { return m_conn ? m_conn->stop() : true; } - - RESULT request(REQUEST_TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs); - - private: - std::string m_address; - std::unique_ptr m_conn; - - pthread_mutex_t m_mutex; - pthread_cond_t m_cond; - bool m_done; - RESULT m_result; - - static bool callback(void* data, const RESULT& result) - { - Impl& impl = *static_cast(data); - STG_LOCKER lock(impl.m_mutex); - impl.m_result = result; - impl.m_done = true; - pthread_cond_signal(&impl.m_cond); - return true; - } -}; - -Client::Impl::Impl(const std::string& address) - : m_address(address) -{ - try - { - m_conn.reset(new Conn(m_address, &Impl::callback, this)); - } - catch (const std::runtime_error& ex) - { - RadLog("Connection error: %s.", ex.what()); - } - pthread_mutex_init(&m_mutex, NULL); - pthread_cond_init(&m_cond, NULL); - m_done = false; -} - -Client::Impl::~Impl() -{ - pthread_cond_destroy(&m_cond); - pthread_mutex_destroy(&m_mutex); -} - -RESULT Client::Impl::request(REQUEST_TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs) -{ - STG_LOCKER lock(m_mutex); - if (!m_conn || !m_conn->connected()) - m_conn.reset(new Conn(m_address, &Impl::callback, this)); - if (!m_conn->connected()) - throw Conn::Error("Failed to create connection to '" + m_address + "'."); - - m_done = false; - m_conn->request(type, userName, password, pairs); - timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - int res = 0; - while (!m_done && res == 0) - res = pthread_cond_timedwait(&m_cond, &m_mutex, &ts); - if (res != 0) - throw Conn::Error("Request failed."); - return m_result; -} - -Client::Client(const std::string& address) - : m_impl(new Impl(address)) -{ -} - -Client::~Client() -{ -} - -bool Client::stop() -{ - return m_impl->stop(); -} - -RESULT Client::request(REQUEST_TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs) -{ - return m_impl->request(type, userName, password, pairs); -} - -Client* Client::get() -{ - return stgClient; -} - -bool Client::configure(const std::string& address) -{ - if ( stgClient != NULL ) - return stgClient->configure(address); - try { - stgClient = new Client(address); - return true; - } catch (const std::exception& ex) { - RadLog("Client configuration error: %s.", ex.what()); - } - return false; -} diff --git a/rlm_stg/stg_client.h b/rlm_stg/stg_client.h deleted file mode 100644 index 249b8871..00000000 --- a/rlm_stg/stg_client.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#ifndef __STG_RLM_CLIENT_H__ -#define __STG_RLM_CLIENT_H__ - -#include "types.h" - -#include -#include -#include - -namespace STG -{ -namespace RLM -{ - -class Client -{ -public: - explicit Client(const std::string& address); - ~Client(); - - bool stop(); - - static Client* get(); - static bool configure(const std::string& address); - - RESULT request(REQUEST_TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs); - -private: - class Impl; - std::unique_ptr m_impl; -}; - -} // namespace RLM -} // namespace STG - -#endif diff --git a/rlm_stg/stgpair.h b/rlm_stg/stgpair.h deleted file mode 100644 index ef7ab4b7..00000000 --- a/rlm_stg/stgpair.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __STG_STGPAIR_H__ -#define __STG_STGPAIR_H__ - -#include - -#define STGPAIR_KEYLENGTH 64 -#define STGPAIR_VALUELENGTH 256 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct STG_PAIR { - char key[STGPAIR_KEYLENGTH]; - char value[STGPAIR_VALUELENGTH]; -} STG_PAIR; - -typedef struct STG_RESULT { - STG_PAIR* modify; - STG_PAIR* reply; - int returnCode; -} STG_RESULT; - -inline -int emptyPair(const STG_PAIR* pair) -{ - return pair == NULL || pair->key[0] == '\0' || pair->value[0] == '\0'; -} - -enum -{ - STG_REJECT, - STG_FAIL, - STG_OK, - STG_HANDLED, - STG_INVALID, - STG_USERLOCK, - STG_NOTFOUND, - STG_NOOP, - STG_UPDATED -}; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/rlm_stg/types.h b/rlm_stg/types.h deleted file mode 100644 index 2bc721fc..00000000 --- a/rlm_stg/types.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#ifndef __STG_RLM_CLIENT_CONN_H__ -#define __STG_RLM_CLIENT_CONN_H__ - -#include -#include - -namespace STG -{ -namespace RLM -{ - -typedef std::vector > PAIRS; - -struct RESULT -{ - PAIRS modify; - PAIRS reply; - int returnCode; -}; - -enum REQUEST_TYPE { - AUTHORIZE, - AUTHENTICATE, - POST_AUTH, - PRE_ACCT, - ACCOUNT -}; - -} // namespace RLM -} // namespace STG - -#endif diff --git a/stargazer/plugins/CMakeLists.txt b/stargazer/plugins/CMakeLists.txt index db9af11c..a8958c43 100644 --- a/stargazer/plugins/CMakeLists.txt +++ b/stargazer/plugins/CMakeLists.txt @@ -95,15 +95,6 @@ if ( BUILD_MOD_PING ) set_target_properties ( mod_ping PROPERTIES PREFIX "" ) endif ( BUILD_MOD_PING ) -if ( BUILD_MOD_RADIUS ) - find_package ( YAJL REQUIRED ) - add_library ( mod_radius MODULE other/radius/radius.cpp - other/radius/config.cpp - other/radius/conn.cpp ) - target_link_libraries ( mod_radius logger json common YAJL::YAJL ) - set_target_properties ( mod_radius PROPERTIES PREFIX "" ) -endif ( BUILD_MOD_RADIUS ) - if ( BUILD_MOD_RSCRYPT ) add_library ( mod_remote_script MODULE other/rscript/rscript.cpp other/rscript/nrmap_parser.cpp ) target_link_libraries ( mod_remote_script crypto scriptexecuter logger common ) diff --git a/stargazer/plugins/other/radius/config.cpp b/stargazer/plugins/other/radius/config.cpp deleted file mode 100644 index a9150bff..00000000 --- a/stargazer/plugins/other/radius/config.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#include "config.h" - -#include "stg/user.h" -#include "stg/common.h" - -#include -#include - -#include // strncasecmp - -using STG::Config; - -namespace -{ - -struct ParserError : public std::runtime_error -{ - ParserError(const std::string& message) - : runtime_error("Config is not valid. " + message), - position(0), - error(message) - {} - ParserError(size_t pos, const std::string& message) - : runtime_error("Parsing error at position " + std::to_string(pos) + ". " + message), - position(pos), - error(message) - {} - - size_t position; - std::string error; -}; - -size_t skipSpaces(const std::string& value, size_t start) -{ - while (start < value.length() && std::isspace(value[start])) - ++start; - return start; -} - -size_t checkChar(const std::string& value, size_t start, char ch) -{ - if (start >= value.length()) - throw ParserError(start, "Unexpected end of string. Expected '" + std::string(1, ch) + "'."); - if (value[start] != ch) - throw ParserError(start, "Expected '" + std::string(1, ch) + "', got '" + std::string(1, value[start]) + "'."); - return start + 1; -} - -std::pair readString(const std::string& value, size_t start) -{ - std::string dest; - while (start < value.length() && !std::isspace(value[start]) && - value[start] != ',' && value[start] != '(' && value[start] != ')') - dest.push_back(value[start++]); - if (dest.empty()) { - if (start == value.length()) - throw ParserError(start, "Unexpected end of string. Expected string."); - else - throw ParserError(start, "Unexpected whitespace. Expected string."); - } - return std::make_pair(start, dest); -} - -Config::Pairs toPairs(const std::vector& values) -{ - if (values.empty()) - return Config::Pairs(); - std::string value(values[0]); - Config::Pairs res; - size_t start = 0; - while (start < value.size()) { - Config::Pair pair; - start = skipSpaces(value, start); - if (!res.empty()) - { - start = checkChar(value, start, ','); - start = skipSpaces(value, start); - } - size_t pairStart = start; - start = checkChar(value, start, '('); - const std::pair key = readString(value, start); - start = key.first; - pair.first = key.second; - start = skipSpaces(value, start); - start = checkChar(value, start, ','); - start = skipSpaces(value, start); - const std::pair val = readString(value, start); - start = val.first; - pair.second = val.second; - start = skipSpaces(value, start); - start = checkChar(value, start, ')'); - if (res.find(pair.first) != res.end()) - throw ParserError(pairStart, "Duplicate field."); - res.insert(pair); - } - return res; -} - -bool toBool(const std::vector& values) -{ - if (values.empty()) - return false; - std::string value(values[0]); - return strncasecmp(value.c_str(), "yes", 3) == 0; -} - -std::string toString(const std::vector& values) -{ - if (values.empty()) - return ""; - return values[0]; -} - -uid_t toUID(const std::vector& values) -{ - if (values.empty()) - return -1; - uid_t res = str2uid(values[0]); - if (res == static_cast(-1)) - throw ParserError("Invalid user name: '" + values[0] + "'"); - return res; -} - -gid_t toGID(const std::vector& values) -{ - if (values.empty()) - return -1; - gid_t res = str2gid(values[0]); - if (res == static_cast(-1)) - throw ParserError("Invalid group name: '" + values[0] + "'"); - return res; -} - -mode_t toMode(const std::vector& values) -{ - if (values.empty()) - return -1; - mode_t res = str2mode(values[0]); - if (res == static_cast(-1)) - throw ParserError("Invalid mode: '" + values[0] + "'"); - return res; -} - -template -T toInt(const std::vector& values) -{ - if (values.empty()) - return 0; - T res = 0; - if (str2x(values[0], res) == 0) - return res; - return 0; -} - -uint16_t toPort(const std::string& value) -{ - if (value.empty()) - return 0; - uint16_t res = 0; - if (str2x(value, res) == 0) - return res; - throw ParserError("'" + value + "' is not a valid port number."); -} - -typedef std::map Codes; - -// One-time call to initialize the list of codes. -Codes getCodes() -{ - Codes res; - res["reject"] = Config::REJECT; - res["fail"] = Config::FAIL; - res["ok"] = Config::OK; - res["handled"] = Config::HANDLED; - res["invalid"] = Config::INVALID; - res["userlock"] = Config::USERLOCK; - res["notfound"] = Config::NOTFOUND; - res["noop"] = Config::NOOP; - res["updated"] = Config::UPDATED; - return res; -} - -Config::ReturnCode toReturnCode(const std::vector& values) -{ - static Codes codes(getCodes()); - if (values.empty()) - return Config::REJECT; - std::string code = ToLower(values[0]); - const Codes::const_iterator it = codes.find(code); - if (it == codes.end()) - return Config::REJECT; - return it->second; -} - -Config::Pairs parseVector(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return toPairs(params[i].value); - return Config::Pairs(); -} - -Config::Authorize parseAuthorize(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return Config::Authorize(toPairs(params[i].value)); - return Config::Authorize(); -} - -Config::ReturnCode parseReturnCode(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return toReturnCode(params[i].value); - return Config::REJECT; -} - -bool parseBool(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return toBool(params[i].value); - return false; -} - -std::string parseString(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return toString(params[i].value); - return ""; -} - -std::string parseAddress(Config::Type connectionType, const std::string& value) -{ - size_t pos = value.find_first_of(':'); - if (pos == std::string::npos) - throw ParserError("Connection type is not specified. Should be either 'unix' or 'tcp'."); - if (connectionType == Config::UNIX) - return value.substr(pos + 1); - std::string address(value.substr(pos + 1)); - pos = address.find_first_of(':', pos + 1); - if (pos == std::string::npos) - throw ParserError("Port is not specified."); - return address.substr(0, pos - 1); -} - -std::string parsePort(Config::Type connectionType, const std::string& value) -{ - size_t pos = value.find_first_of(':'); - if (pos == std::string::npos) - throw ParserError("Connection type is not specified. Should be either 'unix' or 'tcp'."); - if (connectionType == Config::UNIX) - return ""; - std::string address(value.substr(pos + 1)); - pos = address.find_first_of(':', pos + 1); - if (pos == std::string::npos) - throw ParserError("Port is not specified."); - return address.substr(pos + 1); -} - -Config::Type parseConnectionType(const std::string& address) -{ - size_t pos = address.find_first_of(':'); - if (pos == std::string::npos) - throw ParserError("Connection type is not specified. Should be either 'unix' or 'tcp'."); - std::string type = ToLower(address.substr(0, pos)); - if (type == "unix") - return Config::UNIX; - else if (type == "tcp") - return Config::TCP; - throw ParserError("Invalid connection type. Should be either 'unix' or 'tcp', got '" + type + "'"); -} - -Config::Section parseSection(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return Config::Section(parseVector("match", params[i].sections), - parseVector("modify", params[i].sections), - parseVector("reply", params[i].sections), - parseReturnCode("no_match", params[i].sections), - parseAuthorize("authorize", params[i].sections)); - return Config::Section(); -} - -uid_t parseUID(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return toUID(params[i].value); - return -1; -} - -gid_t parseGID(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return toGID(params[i].value); - return -1; -} - -mode_t parseMode(const std::string& paramName, const std::vector& params) -{ - for (size_t i = 0; i < params.size(); ++i) - if (params[i].param == paramName) - return toMode(params[i].value); - return -1; -} - -} // namespace anonymous - -bool Config::Authorize::check(const User& user, const Config::Pairs& radiusData) const -{ - if (!m_auth) - return false; // No flag - no authorization. - - if (m_cond.empty()) - return true; // Empty parameter - always authorize. - - Config::Pairs::const_iterator it = m_cond.begin(); - for (; it != m_cond.end(); ++it) - { - const Config::Pairs::const_iterator pos = radiusData.find(it->first); - if (pos == radiusData.end()) - return false; // No required Radius parameter. - if (user.GetParamValue(it->second) != pos->second) - return false; // No match with the user. - } - - return true; -} - -Config::Config(const ModuleSettings& settings) - : autz(parseSection("autz", settings.moduleParams)), - auth(parseSection("auth", settings.moduleParams)), - postauth(parseSection("postauth", settings.moduleParams)), - preacct(parseSection("preacct", settings.moduleParams)), - acct(parseSection("acct", settings.moduleParams)), - verbose(parseBool("verbose", settings.moduleParams)), - address(parseString("bind_address", settings.moduleParams)), - connectionType(parseConnectionType(address)), - bindAddress(parseAddress(connectionType, address)), - portStr(parsePort(connectionType, address)), - port(toPort(portStr)), - key(parseString("key", settings.moduleParams)), - sockUID(parseUID("sock_owner", settings.moduleParams)), - sockGID(parseGID("sock_group", settings.moduleParams)), - sockMode(parseMode("sock_mode", settings.moduleParams)) -{ - size_t count = 0; - if (autz.authorize.exists()) - ++count; - if (auth.authorize.exists()) - ++count; - if (postauth.authorize.exists()) - ++count; - if (preacct.authorize.exists()) - ++count; - if (acct.authorize.exists()) - ++count; - if (count > 0) - throw ParserError("Authorization flag is specified in more than one section."); -} diff --git a/stargazer/plugins/other/radius/config.h b/stargazer/plugins/other/radius/config.h deleted file mode 100644 index cae7226d..00000000 --- a/stargazer/plugins/other/radius/config.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#pragma once - -#include "stg/module_settings.h" - -#include -#include -#include - -#include // uid_t, gid_t -#include // mode_t - -namespace STG -{ - -struct User; - -struct Config -{ - typedef std::map Pairs; - typedef std::pair Pair; - enum Type { UNIX, TCP }; - enum ReturnCode - { - REJECT, // Reject the request immediately. - FAIL, // Module failed. - OK, // Module is OK, continue. - HANDLED, // The request is handled, no further handling. - INVALID, // The request is invalud. - USERLOCK, // Reject the request, user is locked. - NOTFOUND, // User not found. - NOOP, // Module performed no action. - UPDATED // Module sends some updates. - }; - - class Authorize - { - public: - Authorize() : m_auth(false) {} - Authorize(const Pairs& cond) : m_auth(true), m_cond(cond) {} - - bool check(const User& user, const Pairs& radiusData) const; - bool exists() const { return m_auth; } - private: - bool m_auth; - Pairs m_cond; - }; - - struct Section - { - Section() = default; - Section(const Pairs& ma, const Pairs& mo, const Pairs& re, ReturnCode code, const Authorize& auth) - : match(ma), modify(mo), reply(re), returnCode(code), authorize(auth) {} - Pairs match; - Pairs modify; - Pairs reply; - ReturnCode returnCode; - Authorize authorize; - }; - - Config() = default; - Config(const ModuleSettings& settings); - - Section autz; - Section auth; - Section postauth; - Section preacct; - Section acct; - - bool verbose; - - std::string address; - Type connectionType; - std::string bindAddress; - std::string portStr; - uint16_t port; - std::string key; - - uid_t sockUID; - gid_t sockGID; - mode_t sockMode; -}; - -} // namespace STG diff --git a/stargazer/plugins/other/radius/conn.cpp b/stargazer/plugins/other/radius/conn.cpp deleted file mode 100644 index 4b2f0dcf..00000000 --- a/stargazer/plugins/other/radius/conn.cpp +++ /dev/null @@ -1,532 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#include "conn.h" - -#include "radius.h" -#include "config.h" - -#include "stg/json_parser.h" -#include "stg/json_generator.h" -#include "stg/users.h" -#include "stg/user.h" -#include "stg/logger.h" -#include "stg/common.h" - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#ifndef MSG_NOSIGNAL -// On OSX this flag does not exist. -#define MSG_NOSIGNAL 0 -#endif - -using STG::Conn; -using STG::Config; -using STG::JSON::Parser; -using STG::JSON::PairsParser; -using STG::JSON::EnumParser; -using STG::JSON::NodeParser; -using STG::JSON::Gen; -using STG::JSON::MapGen; -using STG::JSON::StringGen; - -namespace -{ - -double CONN_TIMEOUT = 60; -double PING_TIMEOUT = 10; - -enum Packet -{ - PING, - PONG, - DATA -}; - -enum Stage -{ - AUTHORIZE, - AUTHENTICATE, - PREACCT, - ACCOUNTING, - POSTAUTH -}; - -std::map packetCodes; -std::map stageCodes; - -class PacketParser : public EnumParser -{ - public: - PacketParser(NodeParser* next, Packet& packet, std::string& packetStr) - : EnumParser(next, packet, packetStr, packetCodes) - { - if (!packetCodes.empty()) - return; - packetCodes["ping"] = PING; - packetCodes["pong"] = PONG; - packetCodes["data"] = DATA; - } -}; - -class StageParser : public EnumParser -{ - public: - StageParser(NodeParser* next, Stage& stage, std::string& stageStr) - : EnumParser(next, stage, stageStr, stageCodes) - { - if (!stageCodes.empty()) - return; - stageCodes["authorize"] = AUTHORIZE; - stageCodes["authenticate"] = AUTHENTICATE; - stageCodes["preacct"] = PREACCT; - stageCodes["accounting"] = ACCOUNTING; - stageCodes["postauth"] = POSTAUTH; - } -}; - -class TopParser : public NodeParser -{ - public: - typedef void (*Callback) (void* /*data*/); - TopParser(Callback callback, void* data) - : m_packetParser(this, m_packet, m_packetStr), - m_stageParser(this, m_stage, m_stageStr), - m_pairsParser(this, m_data), - m_callback(callback), m_callbackData(data) - {} - - virtual NodeParser* parseStartMap() { return this; } - virtual NodeParser* parseMapKey(const std::string& value) - { - std::string key = ToLower(value); - - if (key == "packet") - return &m_packetParser; - else if (key == "stage") - return &m_stageParser; - else if (key == "pairs") - return &m_pairsParser; - - return this; - } - virtual NodeParser* parseEndMap() { m_callback(m_callbackData); return this; } - - const std::string& packetStr() const { return m_packetStr; } - Packet packet() const { return m_packet; } - const std::string& stageStr() const { return m_stageStr; } - Stage stage() const { return m_stage; } - const Config::Pairs& data() const { return m_data; } - - private: - std::string m_packetStr; - Packet m_packet; - std::string m_stageStr; - Stage m_stage; - Config::Pairs m_data; - - PacketParser m_packetParser; - StageParser m_stageParser; - PairsParser m_pairsParser; - - Callback m_callback; - void* m_callbackData; -}; - -class ProtoParser : public Parser -{ - public: - ProtoParser(TopParser::Callback callback, void* data) - : Parser( &m_topParser ), - m_topParser(callback, data) - {} - - const std::string& packetStr() const { return m_topParser.packetStr(); } - Packet packet() const { return m_topParser.packet(); } - const std::string& stageStr() const { return m_topParser.stageStr(); } - Stage stage() const { return m_topParser.stage(); } - const Config::Pairs& data() const { return m_topParser.data(); } - - private: - TopParser m_topParser; -}; - -class PacketGen : public Gen -{ - public: - PacketGen(const std::string& type) - : m_type(type) - { - m_gen.add("packet", m_type); - } - void run(yajl_gen_t* handle) const - { - m_gen.run(handle); - } - PacketGen& add(const std::string& key, const std::string& value) - { - m_gen.add(key, new StringGen(value)); - return *this; - } - PacketGen& add(const std::string& key, MapGen* map) - { - m_gen.add(key, map); - return *this; - } - PacketGen& add(const std::string& key, MapGen& map) - { - m_gen.add(key, map); - return *this; - } - private: - MapGen m_gen; - StringGen m_type; -}; - -std::string toString(Config::ReturnCode code) -{ - switch (code) - { - case Config::REJECT: return "reject"; - case Config::FAIL: return "fail"; - case Config::OK: return "ok"; - case Config::HANDLED: return "handled"; - case Config::INVALID: return "invalid"; - case Config::USERLOCK: return "userlock"; - case Config::NOTFOUND: return "notfound"; - case Config::NOOP: return "noop"; - case Config::UPDATED: return "noop"; - } - return "reject"; -} - -} - -class Conn::Impl -{ - public: - Impl(Users& users, PluginLogger& logger, RADIUS& plugin, const Config& config, int fd, const std::string& remote); - ~Impl(); - - int sock() const { return m_sock; } - - bool read(); - bool tick(); - - bool isOk() const { return m_ok; } - - private: - Users& m_users; - PluginLogger& m_logger; - RADIUS& m_plugin; - const Config& m_config; - int m_sock; - std::string m_remote; - bool m_ok; - time_t m_lastPing; - time_t m_lastActivity; - ProtoParser m_parser; - std::set m_authorized; - - template - const T& stageMember(T Config::Section::* member) const - { - switch (m_parser.stage()) - { - case AUTHORIZE: return m_config.autz.*member; - case AUTHENTICATE: return m_config.auth.*member; - case POSTAUTH: return m_config.postauth.*member; - case PREACCT: return m_config.preacct.*member; - case ACCOUNTING: return m_config.acct.*member; - } - throw std::runtime_error("Invalid stage: '" + m_parser.stageStr() + "'."); - } - - const Config::Pairs& match() const { return stageMember(&Config::Section::match); } - const Config::Pairs& modify() const { return stageMember(&Config::Section::modify); } - const Config::Pairs& reply() const { return stageMember(&Config::Section::reply); } - Config::ReturnCode returnCode() const { return stageMember(&Config::Section::returnCode); } - const Config::Authorize& authorize() const { return stageMember(&Config::Section::authorize); } - - static void process(void* data); - void processPing(); - void processPong(); - void processData(); - bool answer(const User& user); - bool answerNo(); - bool sendPing(); - bool sendPong(); - - static bool write(void* data, const char* buf, size_t size); -}; - -Conn::Conn(Users& users, PluginLogger& logger, RADIUS& plugin, const Config& config, int fd, const std::string& remote) - : m_impl(new Impl(users, logger, plugin, config, fd, remote)) -{ -} - -Conn::~Conn() -{ -} - -int Conn::sock() const -{ - return m_impl->sock(); -} - -bool Conn::read() -{ - return m_impl->read(); -} - -bool Conn::tick() -{ - return m_impl->tick(); -} - -bool Conn::isOk() const -{ - return m_impl->isOk(); -} - -Conn::Impl::Impl(Users& users, PluginLogger& logger, RADIUS& plugin, const Config& config, int fd, const std::string& remote) - : m_users(users), - m_logger(logger), - m_plugin(plugin), - m_config(config), - m_sock(fd), - m_remote(remote), - m_ok(true), - m_lastPing(time(NULL)), - m_lastActivity(m_lastPing), - m_parser(&Conn::Impl::process, this) -{ -} - -Conn::Impl::~Impl() -{ - close(m_sock); - - std::set::const_iterator it = m_authorized.begin(); - for (; it != m_authorized.end(); ++it) - m_plugin.unauthorize(*it, "Lost connection to RADIUS server " + m_remote + "."); -} - -bool Conn::Impl::read() -{ - static std::vector buffer(1024); - ssize_t res = ::read(m_sock, buffer.data(), buffer.size()); - if (res < 0) - { - m_logger("Failed to read data from '" + m_remote + "': " + strerror(errno)); - m_ok = false; - return false; - } - printfd(__FILE__, "Read %d bytes.\n%s\n", res, std::string(buffer.data(), res).c_str()); - m_lastActivity = time(NULL); - if (res == 0) - { - m_ok = false; - return true; - } - return m_parser.append(buffer.data(), res); -} - -bool Conn::Impl::tick() -{ - time_t now = time(NULL); - if (difftime(now, m_lastActivity) > CONN_TIMEOUT) - { - int delta = difftime(now, m_lastActivity); - printfd(__FILE__, "Connection to '%s' timed out: %d sec.\n", m_remote.c_str(), delta); - m_logger("Connection to " + m_remote + " timed out."); - m_ok = false; - return false; - } - if (difftime(now, m_lastPing) > PING_TIMEOUT) - { - int delta = difftime(now, m_lastPing); - printfd(__FILE__, "Ping timeout: %d sec. Sending ping...\n", delta); - sendPing(); - } - return true; -} - -void Conn::Impl::process(void* data) -{ - Impl& impl = *static_cast(data); - try - { - switch (impl.m_parser.packet()) - { - case PING: - impl.processPing(); - return; - case PONG: - impl.processPong(); - return; - case DATA: - impl.processData(); - return; - } - } - catch (const std::exception& ex) - { - printfd(__FILE__, "Processing error. %s", ex.what()); - impl.m_logger("Processing error. %s", ex.what()); - } - printfd(__FILE__, "Received invalid packet type: '%s'.\n", impl.m_parser.packetStr().c_str()); - impl.m_logger("Received invalid packet type: " + impl.m_parser.packetStr()); -} - -void Conn::Impl::processPing() -{ - printfd(__FILE__, "Got ping. Sending pong...\n"); - sendPong(); -} - -void Conn::Impl::processPong() -{ - printfd(__FILE__, "Got pong.\n"); - m_lastActivity = time(NULL); -} - -void Conn::Impl::processData() -{ - printfd(__FILE__, "Got data.\n"); - int handle = m_users.OpenSearch(); - - User* user = NULL; - bool matched = false; - while (m_users.SearchNext(handle, &user) == 0) - { - if (user == NULL) - continue; - - matched = true; - for (Config::Pairs::const_iterator it = match().begin(); it != match().end(); ++it) - { - Config::Pairs::const_iterator pos = m_parser.data().find(it->first); - if (pos == m_parser.data().end()) - { - matched = false; - break; - } - if (user->GetParamValue(it->second) != pos->second) - { - matched = false; - break; - } - } - if (!matched) - continue; - answer(*user); - if (authorize().check(*user, m_parser.data())) - { - m_plugin.authorize(*user); - m_authorized.insert(user->GetLogin()); - } - break; - } - - if (!matched) - answerNo(); - - m_users.CloseSearch(handle); -} - -bool Conn::Impl::answer(const User& user) -{ - printfd(__FILE__, "Got match. Sending answer...\n"); - MapGen replyData; - for (Config::Pairs::const_iterator it = reply().begin(); it != reply().end(); ++it) - replyData.add(it->first, new StringGen(user.GetParamValue(it->second))); - - MapGen modifyData; - for (Config::Pairs::const_iterator it = modify().begin(); it != modify().end(); ++it) - modifyData.add(it->first, new StringGen(user.GetParamValue(it->second))); - - PacketGen gen("data"); - gen.add("result", "ok") - .add("reply", replyData) - .add("modify", modifyData); - - m_lastPing = time(NULL); - - return generate(gen, &Conn::Impl::write, this); -} - -bool Conn::Impl::answerNo() -{ - printfd(__FILE__, "No match. Sending answer...\n"); - PacketGen gen("data"); - gen.add("result", "no"); - gen.add("return_code", toString(returnCode())); - - m_lastPing = time(NULL); - - return generate(gen, &Conn::Impl::write, this); -} - -bool Conn::Impl::sendPing() -{ - PacketGen gen("ping"); - - m_lastPing = time(NULL); - - return generate(gen, &Conn::Impl::write, this); -} - -bool Conn::Impl::sendPong() -{ - PacketGen gen("pong"); - - m_lastPing = time(NULL); - - return generate(gen, &Conn::Impl::write, this); -} - -bool Conn::Impl::write(void* data, const char* buf, size_t size) -{ - std::string json(buf, size); - printfd(__FILE__, "Writing JSON:\n%s\n", json.c_str()); - Conn::Impl& conn = *static_cast(data); - while (size > 0) - { - ssize_t res = ::send(conn.m_sock, buf, size, MSG_NOSIGNAL); - if (res < 0) - { - conn.m_logger("Failed to write pong to '" + conn.m_remote + "': " + strerror(errno)); - conn.m_ok = false; - return false; - } - size -= res; - } - return true; -} diff --git a/stargazer/plugins/other/radius/conn.h b/stargazer/plugins/other/radius/conn.h deleted file mode 100644 index 0f902e9a..00000000 --- a/stargazer/plugins/other/radius/conn.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#pragma once - -#include -#include - -class RADIUS; - -namespace STG -{ - -struct Users; -class PluginLogger; - -struct Config; - -class Conn -{ - public: - Conn(Users& users, PluginLogger& logger, RADIUS& plugin, const Config& config, int fd, const std::string& remote); - ~Conn(); - - int sock() const; - - bool read(); - bool tick(); - - bool isOk() const; - - private: - class Impl; - std::unique_ptr m_impl; -}; - -} diff --git a/stargazer/plugins/other/radius/radius.cpp b/stargazer/plugins/other/radius/radius.cpp deleted file mode 100644 index dcfb4e69..00000000 --- a/stargazer/plugins/other/radius/radius.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#include "radius.h" - -#include "stg/store.h" -#include "stg/users.h" -#include "stg/user.h" -#include "stg/common.h" - -#include -#include -#include -#include -#include - -#include -#include -#include // UNIX -#include // IP -#include // TCP -#include - -using STG::Config; -using STG::Conn; - -extern "C" STG::Plugin* GetPlugin() -{ - static RADIUS plugin; - return &plugin; -} - -RADIUS::RADIUS() - : m_running(false), - m_stopped(true), - m_users(NULL), - m_store(NULL), - m_listenSocket(0), - m_logger(STG::PluginLogger::get("radius")) -{ -} - -int RADIUS::ParseSettings() -{ - try { - m_config = STG::Config(m_settings); - return reconnect() ? 0 : -1; - } catch (const std::runtime_error& ex) { - m_logger("Failed to parse settings. %s", ex.what()); - return -1; - } -} - -int RADIUS::Start() -{ - if (m_running) - return 0; - - int res = pthread_create(&m_thread, NULL, run, this); - if (res == 0) - return 0; - - m_error = strerror(res); - m_logger("Failed to create thread: '" + m_error + "'."); - return -1; -} - -int RADIUS::Stop() -{ - std::set::const_iterator it = m_logins.begin(); - for (; it != m_logins.end(); ++it) - m_users->Unauthorize(*it, this, "Stopping RADIUS plugin."); - m_logins.clear(); - - if (m_stopped) - return 0; - - m_running = false; - - for (size_t i = 0; i < 25 && !m_stopped; i++) { - struct timespec ts = {0, 200000000}; - nanosleep(&ts, NULL); - } - - if (m_stopped) { - pthread_join(m_thread, NULL); - return 0; - } - - if (m_config.connectionType == Config::UNIX) - unlink(m_config.bindAddress.c_str()); - - m_error = "Failed to stop thread."; - m_logger(m_error); - return -1; -} -//----------------------------------------------------------------------------- -void* RADIUS::run(void* d) -{ - sigset_t signalSet; - sigfillset(&signalSet); - pthread_sigmask(SIG_BLOCK, &signalSet, NULL); - - static_cast(d)->runImpl(); - - return NULL; -} - -bool RADIUS::reconnect() -{ - if (!m_conns.empty()) - { - std::deque::const_iterator it; - for (it = m_conns.begin(); it != m_conns.end(); ++it) - delete(*it); - m_conns.clear(); - } - if (m_listenSocket != 0) - { - shutdown(m_listenSocket, SHUT_RDWR); - close(m_listenSocket); - } - if (m_config.connectionType == Config::UNIX) - m_listenSocket = createUNIX(); - else - m_listenSocket = createTCP(); - if (m_listenSocket == 0) - return false; - if (listen(m_listenSocket, 100) == -1) - { - m_error = std::string("Error starting to listen socket: ") + strerror(errno); - m_logger(m_error); - return false; - } - return true; -} - -int RADIUS::createUNIX() const -{ - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) - { - m_error = std::string("Error creating UNIX socket: ") + strerror(errno); - m_logger(m_error); - return 0; - } - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, m_config.bindAddress.c_str(), m_config.bindAddress.length()); - unlink(m_config.bindAddress.c_str()); - if (bind(fd, reinterpret_cast(&addr), sizeof(addr)) == -1) - { - shutdown(fd, SHUT_RDWR); - close(fd); - m_error = std::string("Error binding UNIX socket: ") + strerror(errno); - m_logger(m_error); - return 0; - } - chown(m_config.bindAddress.c_str(), m_config.sockUID, m_config.sockGID); - if (m_config.sockMode != static_cast(-1)) - chmod(m_config.bindAddress.c_str(), m_config.sockMode); - return fd; -} - -int RADIUS::createTCP() const -{ - addrinfo hints; - memset(&hints, 0, sizeof(addrinfo)); - - hints.ai_family = AF_INET; /* Allow IPv4 */ - hints.ai_socktype = SOCK_STREAM; /* Stream socket */ - hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ - hints.ai_protocol = 0; /* Any protocol */ - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - addrinfo* ais = NULL; - int res = getaddrinfo(m_config.bindAddress.c_str(), m_config.portStr.c_str(), &hints, &ais); - if (res != 0) - { - m_error = "Error resolving address '" + m_config.bindAddress + "': " + gai_strerror(res); - m_logger(m_error); - return 0; - } - - for (addrinfo* ai = ais; ai != NULL; ai = ai->ai_next) - { - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - { - m_error = std::string("Error creating TCP socket: ") + strerror(errno); - m_logger(m_error); - freeaddrinfo(ais); - return 0; - } - if (bind(fd, ai->ai_addr, ai->ai_addrlen) == -1) - { - shutdown(fd, SHUT_RDWR); - close(fd); - m_error = std::string("Error binding TCP socket: ") + strerror(errno); - m_logger(m_error); - continue; - } - freeaddrinfo(ais); - return fd; - } - - m_error = "Failed to resolve '" + m_config.bindAddress; - m_logger(m_error); - - freeaddrinfo(ais); - return 0; -} - -void RADIUS::runImpl() -{ - m_running = true; - m_stopped = false; - - while (m_running) { - fd_set fds; - - buildFDSet(fds); - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 500000; - - int res = select(maxFD() + 1, &fds, NULL, NULL, &tv); - if (res < 0) - { - if (errno == EINTR) - continue; - m_error = std::string("'select' is failed: '") + strerror(errno) + "'."; - m_logger(m_error); - break; - } - - if (!m_running) - break; - - if (res > 0) - handleEvents(fds); - else - { - for (std::deque::iterator it = m_conns.begin(); it != m_conns.end(); ++it) - (*it)->tick(); - } - - cleanupConns(); - } - - m_stopped = true; -} - -int RADIUS::maxFD() const -{ - int maxFD = m_listenSocket; - std::deque::const_iterator it; - for (it = m_conns.begin(); it != m_conns.end(); ++it) - if (maxFD < (*it)->sock()) - maxFD = (*it)->sock(); - return maxFD; -} - -void RADIUS::buildFDSet(fd_set & fds) const -{ - FD_ZERO(&fds); - FD_SET(m_listenSocket, &fds); - std::deque::const_iterator it; - for (it = m_conns.begin(); it != m_conns.end(); ++it) - FD_SET((*it)->sock(), &fds); -} - -void RADIUS::cleanupConns() -{ - std::deque::iterator pos; - for (pos = m_conns.begin(); pos != m_conns.end(); ++pos) - if (!(*pos)->isOk()) { - delete *pos; - *pos = NULL; - } - - pos = std::remove(m_conns.begin(), m_conns.end(), static_cast(NULL)); - m_conns.erase(pos, m_conns.end()); -} - -void RADIUS::handleEvents(const fd_set & fds) -{ - if (FD_ISSET(m_listenSocket, &fds)) - acceptConnection(); - else - { - std::deque::iterator it; - for (it = m_conns.begin(); it != m_conns.end(); ++it) - if (FD_ISSET((*it)->sock(), &fds)) - (*it)->read(); - else - (*it)->tick(); - } -} - -void RADIUS::acceptConnection() -{ - if (m_config.connectionType == Config::UNIX) - acceptUNIX(); - else - acceptTCP(); -} - -void RADIUS::acceptUNIX() -{ - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - socklen_t size = sizeof(addr); - int res = accept(m_listenSocket, reinterpret_cast(&addr), &size); - if (res == -1) - { - m_error = std::string("Failed to accept UNIX connection: ") + strerror(errno); - m_logger(m_error); - return; - } - printfd(__FILE__, "New UNIX connection: '%s'\n", addr.sun_path); - m_conns.push_back(new Conn(*m_users, m_logger, *this, m_config, res, addr.sun_path)); -} - -void RADIUS::acceptTCP() -{ - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - socklen_t size = sizeof(addr); - int res = accept(m_listenSocket, reinterpret_cast(&addr), &size); - if (res == -1) - { - m_error = std::string("Failed to accept TCP connection: ") + strerror(errno); - m_logger(m_error); - return; - } - std::string remote = inet_ntostring(addr.sin_addr.s_addr) + ":" + std::to_string(ntohs(addr.sin_port)); - printfd(__FILE__, "New TCP connection: '%s'\n", remote.c_str()); - m_conns.push_back(new Conn(*m_users, m_logger, *this, m_config, res, remote)); -} - -void RADIUS::authorize(const STG::User& user) -{ - uint32_t ip = 0; - const std::string& login(user.GetLogin()); - if (!m_users->Authorize(login, ip, 0xffFFffFF, this)) - { - m_error = "Unable to authorize user '" + login + "' with ip " + inet_ntostring(ip) + "."; - m_logger(m_error); - } - else - m_logins.insert(login); -} - -void RADIUS::unauthorize(const std::string& login, const std::string& reason) -{ - const std::set::const_iterator it = m_logins.find(login); - if (it == m_logins.end()) - return; - m_logins.erase(it); - m_users->Unauthorize(login, this, reason); -} diff --git a/stargazer/plugins/other/radius/radius.h b/stargazer/plugins/other/radius/radius.h deleted file mode 100644 index 5a7b2290..00000000 --- a/stargazer/plugins/other/radius/radius.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Author : Maxim Mamontov - */ - -#pragma once - -#include "stg/auth.h" -#include "stg/module_settings.h" -#include "stg/logger.h" - -#include "config.h" -#include "conn.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace STG -{ -struct Store; -struct Users; -struct User; -} - -class RADIUS : public STG::Auth { -public: - RADIUS(); - virtual ~RADIUS() {} - - void SetUsers(STG::Users* u) { m_users = u; } - void SetStore(STG::Store* s) { m_store = s; } - void SetStgSettings(const STG::Settings*) {} - void SetSettings(const STG::ModuleSettings& s) { m_settings = s; } - int ParseSettings(); - - int Start(); - int Stop(); - int Reload(const STG::ModuleSettings & /*ms*/) { return 0; } - bool IsRunning() { return m_running; } - - const std::string& GetStrError() const { return m_error; } - std::string GetVersion() const { return "RADIUS data access plugin v. 2.0"; } - uint16_t GetStartPosition() const { return 30; } - uint16_t GetStopPosition() const { return 30; } - - int SendMessage(const STG::Message&, uint32_t) const { return 0; } - - void authorize(const STG::User& user); - void unauthorize(const std::string& login, const std::string& reason); - -private: - RADIUS(const RADIUS & rvalue); - RADIUS & operator=(const RADIUS & rvalue); - - static void* run(void*); - - bool reconnect(); - int createUNIX() const; - int createTCP() const; - void runImpl(); - int maxFD() const; - void buildFDSet(fd_set & fds) const; - void cleanupConns(); - void handleEvents(const fd_set & fds); - void acceptConnection(); - void acceptUNIX(); - void acceptTCP(); - - mutable std::string m_error; - STG::Config m_config; - - STG::ModuleSettings m_settings; - - bool m_running; - bool m_stopped; - - STG::Users* m_users; - const STG::Store* m_store; - - int m_listenSocket; - std::deque m_conns; - std::set m_logins; - - pthread_t m_thread; - - STG::PluginLogger m_logger; -};