#include "config.h"
+#include "stg/user.h"
#include "stg/common.h"
#include <vector>
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 " + x2str(pos) + ". " + message),
position(pos),
return -1;
uid_t res = str2uid(values[0]);
if (res == static_cast<uid_t>(-1))
- throw ParserError(0, "Invalid user name: '" + values[0] + "'");
+ throw ParserError("Invalid user name: '" + values[0] + "'");
return res;
}
return -1;
gid_t res = str2gid(values[0]);
if (res == static_cast<gid_t>(-1))
- throw ParserError(0, "Invalid group name: '" + values[0] + "'");
+ throw ParserError("Invalid group name: '" + values[0] + "'");
return res;
}
return -1;
mode_t res = str2mode(values[0]);
if (res == static_cast<mode_t>(-1))
- throw ParserError(0, "Invalid mode: '" + values[0] + "'");
+ throw ParserError("Invalid mode: '" + values[0] + "'");
return res;
}
uint16_t res = 0;
if (str2x(value, res) == 0)
return res;
- throw ParserError(0, "'" + value + "' is not a valid port number.");
+ throw ParserError("'" + value + "' is not a valid port number.");
}
typedef std::map<std::string, Config::ReturnCode> Codes;
return Config::Pairs();
}
+Config::Authorize parseAuthorize(const std::string& paramName, const std::vector<PARAM_VALUE>& 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<PARAM_VALUE>& params)
{
for (size_t i = 0; i < params.size(); ++i)
{
size_t pos = value.find_first_of(':');
if (pos == std::string::npos)
- throw ParserError(0, "Connection type is not specified. Should be either 'unix' or 'tcp'.");
+ 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(0, "Port is not specified.");
+ throw ParserError("Port is not specified.");
return address.substr(0, pos - 1);
}
{
size_t pos = value.find_first_of(':');
if (pos == std::string::npos)
- throw ParserError(0, "Connection type is not specified. Should be either 'unix' or 'tcp'.");
+ 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(0, "Port is not specified.");
+ throw ParserError("Port is not specified.");
return address.substr(pos + 1);
}
{
size_t pos = address.find_first_of(':');
if (pos == std::string::npos)
- throw ParserError(0, "Connection type is not specified. Should be either 'unix' or 'tcp'.");
+ 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(0, "Invalid connection type. Should be either 'unix' or 'tcp', got '" + type + "'");
+ throw ParserError("Invalid connection type. Should be either 'unix' or 'tcp', got '" + type + "'");
}
Config::Section parseSection(const std::string& paramName, const std::vector<PARAM_VALUE>& params)
return Config::Section(parseVector("match", params[i].sections),
parseVector("modify", params[i].sections),
parseVector("reply", params[i].sections),
- parseReturnCode("no_match", params[i].sections));
+ parseReturnCode("no_match", params[i].sections),
+ parseAuthorize("authorize", params[i].sections));
return Config::Section();
}
} // 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 MODULE_SETTINGS& settings)
: autz(parseSection("autz", settings.moduleParams)),
auth(parseSection("auth", 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.");
}
#include <unistd.h> // uid_t, gid_t
#include <sys/stat.h> // mode_t
+class USER;
+
namespace STG
{
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() {}
- Section(const Pairs& ma, const Pairs& mo, const Pairs& re, ReturnCode code)
- : match(ma), modify(mo), reply(re), returnCode(code) {}
+ 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() {}
#include "conn.h"
+#include "radius.h"
#include "config.h"
#include "stg/json_parser.h"
class Conn::Impl
{
public:
- Impl(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote);
+ Impl(USERS& users, PLUGIN_LOGGER& logger, RADIUS& plugin, const Config& config, int fd, const std::string& remote);
~Impl();
int sock() const { return m_sock; }
private:
USERS& m_users;
PLUGIN_LOGGER& m_logger;
+ RADIUS& m_plugin;
const Config& m_config;
int m_sock;
std::string m_remote;
time_t m_lastPing;
time_t m_lastActivity;
ProtoParser m_parser;
+ std::set<std::string> m_authorized;
template <typename T>
const T& stageMember(T Config::Section::* member) const
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();
static bool write(void* data, const char* buf, size_t size);
};
-Conn::Conn(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote)
- : m_impl(new Impl(users, logger, config, fd, remote))
+Conn::Conn(USERS& users, PLUGIN_LOGGER& logger, RADIUS& plugin, const Config& config, int fd, const std::string& remote)
+ : m_impl(new Impl(users, logger, plugin, config, fd, remote))
{
}
return m_impl->isOk();
}
-Conn::Impl::Impl(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote)
+Conn::Impl::Impl(USERS& users, PLUGIN_LOGGER& 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),
Conn::Impl::~Impl()
{
close(m_sock);
+
+ std::set<std::string>::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()
if (!matched)
continue;
answer(*user);
+ if (authorize().check(*user, m_parser.data()))
+ {
+ m_plugin.authorize(*user);
+ m_authorized.insert(user->GetLogin());
+ }
break;
}
class USER;
class USERS;
class PLUGIN_LOGGER;
+class RADIUS;
namespace STG
{
class Conn
{
public:
- Conn(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote);
+ Conn(USERS& users, PLUGIN_LOGGER& logger, RADIUS& plugin, const Config& config, int fd, const std::string& remote);
~Conn();
int sock() const;
int RADIUS::Stop()
{
+ std::set<std::string>::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;
return;
}
printfd(__FILE__, "New UNIX connection: '%s'\n", addr.sun_path);
- m_conns.push_back(new Conn(*m_users, m_logger, m_config, res, addr.sun_path));
+ m_conns.push_back(new Conn(*m_users, m_logger, *this, m_config, res, addr.sun_path));
}
void RADIUS::acceptTCP()
}
std::string remote = inet_ntostring(addr.sin_addr.s_addr) + ":" + x2str(ntohs(addr.sin_port));
printfd(__FILE__, "New TCP connection: '%s'\n", remote.c_str());
- m_conns.push_back(new Conn(*m_users, m_logger, m_config, res, remote));
+ m_conns.push_back(new Conn(*m_users, m_logger, *this, m_config, res, remote));
+}
+
+void RADIUS::authorize(const 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<std::string>::const_iterator it = m_logins.find(login);
+ if (it == m_logins.end())
+ return;
+ m_logins.erase(it);
+ m_users->Unauthorize(login, this, reason);
}
#include <string>
#include <deque>
+#include <set>
#include <pthread.h>
#include <unistd.h>
bool IsRunning() { return m_running; }
const std::string& GetStrError() const { return m_error; }
- std::string GetVersion() const { return "RADIUS data access plugin v 1.0"; }
+ 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_MSG&, uint32_t) const { return 0; }
+ void authorize(const USER& user);
+ void unauthorize(const std::string& login, const std::string& reason);
+
private:
RADIUS(const RADIUS & rvalue);
RADIUS & operator=(const RADIUS & rvalue);
int m_listenSocket;
std::deque<STG::Conn*> m_conns;
+ std::set<std::string> m_logins;
pthread_t m_thread;