]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/radius/radius.cpp
Radiusю (#12)
[stg.git] / projects / stargazer / plugins / other / radius / radius.cpp
1 #include "radius.h"
2 #include "radproto/error.h"
3 #include "stg/common.h"
4 #include <boost/tokenizer.hpp>
5
6 #include <vector>
7 #include <utility>
8 #include <iterator>
9 #include <algorithm>
10 #include <iostream>
11
12 using STG::RADIUS;
13 using STG::RAD_SETTINGS;
14 using AttrValue = RAD_SETTINGS::AttrValue;
15 using ASection = RAD_SETTINGS::ASection;
16
17 extern "C" STG::Plugin* GetPlugin()
18 {
19     static RADIUS plugin;
20     return &plugin;
21 }
22
23 namespace
24 {
25     std::string ShowRules(const std::vector<std::pair<std::string, AttrValue>>& attributes)
26     {
27         std::string result;
28         for (const auto& at : attributes)
29         {
30             if (!result.empty())
31                 result += ", ";
32
33             if (at.second.type == AttrValue::Type::PARAM_NAME)
34                 result.append(at.first + " = " + at.second.value);
35             else
36                 result.append(at.first + " = '" + at.second.value + "'");
37         }
38         return result;
39     }
40 }
41
42 std::vector<std::pair<std::string, AttrValue>> RAD_SETTINGS::ParseRules(const std::string& value, const std::string& paramName)
43 {
44     using tokenizer =  boost::tokenizer<boost::char_separator<char>>;
45     const boost::char_separator<char> sep(",");
46
47     const tokenizer tokens(value, sep);
48
49     std::vector<std::pair<std::string, AttrValue>> res;
50     for (const auto& token : tokens)
51     {
52         const boost::char_separator<char> sp(" =");
53         const tokenizer tok(token, sp);
54
55         std::vector<std::string> keyValue;
56         for (const auto& t : tok)
57             keyValue.push_back(t);
58
59         if (keyValue.size() != 2)
60         {
61             m_logger("The '%s' attribute specification has an incorrect format: '%s'.", paramName.c_str(),  token.c_str());
62             printfd(__FILE__, "The '%s' attribute specification has an incorrect format: '%s'.", paramName.c_str(), token.c_str());
63             return {};
64         }
65
66         auto type = AttrValue::Type::PARAM_NAME;
67         std::string valueName = keyValue[1];
68         if (valueName.front() == '\'' && valueName.back() == '\'')
69         {
70             type = AttrValue::Type::VALUE;
71             valueName.erase(0, 1);
72             valueName.erase(valueName.length() - 1, 1);
73         }
74         else if ((valueName.front() == '\'' && valueName.back() != '\'') || (valueName.front() != '\'' && valueName.back() == '\''))
75         {
76             m_logger("Error ParseRules: '%s' attribute parameter value is invalid.\n", paramName.c_str());
77             printfd(__FILE__, "Error ParseRules: '%s' attribute parameter value is invalid.\n", paramName.c_str());
78             return {};
79         }
80         res.emplace_back(keyValue[0], AttrValue{valueName, type});
81     }
82     return res;
83 }
84
85 ASection RAD_SETTINGS::parseASection(const std::vector<ParamValue>& conf)
86 {
87     ASection res;
88     const auto mit = std::find(conf.begin(), conf.end(), ParamValue("match", {}));
89     if (mit != conf.end())
90         res.match = ParseRules(mit->value[0], mit->param);
91
92     const auto sit = std::find(conf.begin(), conf.end(), ParamValue("send", {}));
93     if (sit != conf.end())
94         res.send = ParseRules(sit->value[0], sit->param);
95
96     return res;
97 }
98
99 RAD_SETTINGS::RAD_SETTINGS()
100     : m_port(1812),
101       m_dictionaries("/usr/share/freeradius/dictionary"),
102       m_logger(PluginLogger::get("radius"))
103 {}
104
105 int RAD_SETTINGS::ParseSettings(const ModuleSettings & s)
106 {
107     ParamValue pv;
108     int p;
109
110     pv.param = "Port";
111     auto pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
112     if (pvi != s.moduleParams.end() && !pvi->value.empty())
113     {
114         if (ParseIntInRange(pvi->value[0], 2, 65535, &p) != 0)
115         {
116             m_errorStr = "Cannot parse parameter \'Port\': " + m_errorStr;
117             printfd(__FILE__, "Cannot parse parameter 'Port'\n");
118             return -1;
119         }
120         m_port = static_cast<uint16_t>(p);
121     }
122
123     pv.param = "Secret";
124     pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
125     if (pvi == s.moduleParams.end() || pvi->value.empty())
126     {
127         m_errorStr = "Parameter \'Secret\' not found.";
128         printfd(__FILE__, "Parameter 'Secret' not found\n");
129         m_secret = "";
130     }
131     else
132         m_secret = pvi->value[0];
133
134     pv.param = "Dictionaries";
135     pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
136     if (pvi != s.moduleParams.end() && !pvi->value.empty())
137         m_dictionaries = pvi->value[0];
138
139     const auto authIt = std::find(s.moduleParams.begin(), s.moduleParams.end(), ParamValue("auth", {}));
140     if (authIt != s.moduleParams.end())
141         m_auth = parseASection(authIt->sections);
142
143     const auto autzIt = std::find(s.moduleParams.begin(), s.moduleParams.end(), ParamValue("autz", {}));
144     if (autzIt != s.moduleParams.end())
145         m_autz = parseASection(autzIt->sections);
146
147     printfd(__FILE__, " auth.match = \"%s\"\n", ShowRules(m_auth.match).c_str());
148     printfd(__FILE__, " auth.send = \"%s\"\n", ShowRules(m_auth.send).c_str());
149     printfd(__FILE__, " autz.match = \"%s\"\n", ShowRules(m_autz.match).c_str());
150     printfd(__FILE__, " autz.send = \"%s\"\n", ShowRules(m_autz.send).c_str());
151
152     return 0;
153 }
154
155 RADIUS::RADIUS()
156     : m_running(false),
157       m_users(NULL),
158       m_logger(PluginLogger::get("radius"))
159 {
160 }
161
162 int RADIUS::ParseSettings()
163 {
164     auto ret = m_radSettings.ParseSettings(m_settings);
165     if (ret != 0)
166         m_errorStr = m_radSettings.GetStrError();
167
168     return ret;
169 }
170
171 std::string RADIUS::GetVersion() const
172 {
173     return "Radius v.1.0";
174 }
175
176 int RADIUS::Start()
177 {
178     m_thread = std::jthread([this](auto token){ Run(std::move(token)); });
179     return 0;
180 }
181
182 int RADIUS::Stop()
183 {
184     if (!m_thread.joinable())
185         return 0;
186
187     m_thread.request_stop();
188
189     if (m_server)
190         m_server->stop();
191
192     m_thread.join();
193     return 0;
194 }
195
196 bool RADIUS::IsRunning()
197 {
198     const std::lock_guard lock(m_mutex);
199     return m_running;
200 }
201
202 void RADIUS::SetRunning(bool val)
203 {
204     const std::lock_guard lock(m_mutex);
205     m_running = val;
206 }
207
208 int RADIUS::Run(std::stop_token token)
209 {
210     SetRunning(true);
211
212     try
213     {
214         if (!m_server)
215            m_server = std::make_unique<Server>(m_ioContext, m_radSettings.GetSecret(), m_radSettings.GetPort(), m_radSettings.GetDictionaries(), std::move(token), m_logger, m_users);
216         m_ioContext.run();
217     }
218     catch (const std::exception& e)
219     {
220         m_errorStr = "Exception in RADIUS::Run(): " + std::string(e.what());
221         m_logger("Exception in RADIUS:: Run(): %s", e.what());
222         printfd(__FILE__, "Exception in RADIUS:: Run(). Message: '%s'\n", e.what());
223     }
224
225     SetRunning(false);
226     return 0;
227 }