]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/radius/server.cpp
Sending attributes from <auth>/send section. (#13)
[stg.git] / projects / stargazer / plugins / other / radius / server.cpp
1 #include "server.h"
2 #include "radproto/attribute.h"
3 #include "radproto/packet_codes.h"
4 #include "radproto/attribute_codes.h"
5 #include "stg/user.h"
6 #include "stg/users.h"
7 #include "stg/common.h"
8 #include <vector>
9 #include <string>
10 #include <sstream>
11 #include <cstring>
12 #include <functional>
13 #include <cstdint> //uint8_t, uint32_t
14
15 using STG::Server;
16 using STG::User;
17 using boost::system::error_code;
18
19 Server::Server(boost::asio::io_context& io_context, const std::string& secret, uint16_t port, const std::string& filePath, std::stop_token token, PluginLogger& logger, Users* users, const Config& config)
20     : m_radius(io_context, secret, port),
21       m_dictionaries(filePath),
22       m_users(users),
23       m_config(config),
24       m_token(std::move(token)),
25       m_logger(logger)
26 {
27     start();
28 }
29
30 void Server::start()
31 {
32     startReceive();
33 }
34
35 void Server::stop()
36 {
37     error_code ec;
38     m_radius.close(ec);
39 }
40
41 void Server::startReceive()
42 {
43     m_radius.asyncReceive([this](const auto& error, const auto& packet, const boost::asio::ip::udp::endpoint& source){ handleReceive(error, packet, source); });
44 }
45
46 std::vector<RadProto::Attribute*> Server::makeAttributes(const User* user)
47 {
48     std::vector<RadProto::Attribute*> attributes;
49
50     for (const auto& at : m_config.getAuth().send)
51     {
52         std::string attrValue;
53
54         if (at.second.type == Config::AttrValue::Type::PARAM_NAME)
55             attrValue = user->GetParamValue(at.second.value);
56         else
57             attrValue = at.second.value;
58
59         const auto attrName = at.first;
60         const auto attrCode = m_dictionaries.attributeCode(attrName);
61         const auto attrType = m_dictionaries.attributeType(attrCode);
62
63         if ((attrType == "integer") && (m_dictionaries.attributeValueFindByName(attrName, attrValue)))
64             attributes.push_back(RadProto::Attribute::make(attrCode, attrType, std::to_string(m_dictionaries.attributeValueCode(attrName, attrValue))));
65         else
66             attributes.push_back(RadProto::Attribute::make(attrCode, attrType, attrValue));
67     }
68     return attributes;
69 }
70
71 RadProto::Packet Server::makeResponse(const RadProto::Packet& request)
72 {
73     if (request.code() != RadProto::ACCESS_REQUEST)
74         return RadProto::Packet(RadProto::ACCESS_REJECT, request.id(), request.auth(), {}, {});
75
76     const User* user;
77
78     user = findUser(request);
79
80     if (user != nullptr)
81         return RadProto::Packet(RadProto::ACCESS_ACCEPT, request.id(), request.auth(), makeAttributes(user), {});
82
83     printfd(__FILE__, "Error findUser\n");
84     return RadProto::Packet(RadProto::ACCESS_REJECT, request.id(), request.auth(), {}, {});
85 }
86
87 void Server::handleSend(const error_code& ec)
88 {
89     if (m_token.stop_requested())
90         return;
91
92     if (ec)
93     {
94         m_logger("Error asyncSend: %s", ec.message().c_str());
95         printfd(__FILE__, "Error asyncSend: '%s'\n", ec.message().c_str());
96     }
97     startReceive();
98 }
99
100 void Server::handleReceive(const error_code& error, const std::optional<RadProto::Packet>& packet, const boost::asio::ip::udp::endpoint& source)
101 {
102     if (m_token.stop_requested())
103         return;
104
105     if (error)
106     {
107         m_logger("Error asyncReceive: %s", error.message().c_str());
108         printfd(__FILE__, "Error asyncReceive: '%s'\n", error.message().c_str());
109         return;
110     }
111
112     if (packet == std::nullopt)
113     {
114         m_logger("Error asyncReceive: the request packet is missing\n");
115         printfd(__FILE__, "Error asyncReceive: the request packet is missing\n");
116         return;
117     }
118
119     m_radius.asyncSend(makeResponse(*packet), source, [this](const auto& ec){ handleSend(ec); });
120 }
121
122 const User* Server::findUser(const RadProto::Packet& packet)
123 {
124     std::string login;
125     std::string password;
126     for (const auto& attribute : packet.attributes())
127     {
128         if (attribute->code() == RadProto::USER_NAME)
129             login = attribute->toString();
130
131         if (attribute->code() == RadProto::USER_PASSWORD)
132             password = attribute->toString();
133     }
134
135     User* user = nullptr;
136     if (m_users->FindByName(login, &user))
137     {
138         m_logger("User '%s' not found.", login.c_str());
139         printfd(__FILE__, "User '%s' NOT found!\n", login.c_str());
140         return nullptr;
141     }
142
143     printfd(__FILE__, "User '%s' FOUND!\n", user->GetLogin().c_str());
144
145     if (password != user->GetProperties().password.Get())
146     {
147         m_logger("User's password is incorrect.");
148         printfd(__FILE__, "User's password is incorrect.\n");
149         return nullptr;
150     }
151     return user;
152 }