]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/radius/server.cpp
9e6766d53826d8457ea5a796895bff15fb351911
[stg.git] / projects / stargazer / plugins / other / radius / server.cpp
1 #include "server.h"
2 #include "radproto/packet_codes.h"
3 #include "radproto/attribute_types.h"
4 #include "stg/user.h"
5 #include "stg/users.h"
6 #include "stg/common.h"
7 #include <cstring>
8 #include <functional>
9 #include <cstdint> //uint8_t, uint32_t
10
11 using STG::Server;
12 using boost::system::error_code;
13
14 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)
15     : m_radius(io_context, secret, port),
16       m_dictionaries(filePath),
17       m_users(users),
18       m_token(std::move(token)),
19       m_logger(logger)
20 {
21     start();
22 }
23
24 void Server::start()
25 {
26     startReceive();
27 }
28
29 void Server::stop()
30 {
31     error_code ec;
32     m_radius.close(ec);
33 }
34
35 void Server::startReceive()
36 {
37     m_radius.asyncReceive([this](const auto& error, const auto& packet, const boost::asio::ip::udp::endpoint& source){ handleReceive(error, packet, source); });
38 }
39
40 RadProto::Packet Server::makeResponse(const RadProto::Packet& request)
41 {
42     std::vector<RadProto::Attribute*> attributes;
43     attributes.push_back(new RadProto::String(m_dictionaries.attributeCode("User-Name"), "test"));
44     attributes.push_back(new RadProto::Integer(m_dictionaries.attributeCode("NAS-Port"), 20));
45     std::array<uint8_t, 4> address {127, 104, 22, 17};
46     attributes.push_back(new RadProto::IpAddress(m_dictionaries.attributeCode("NAS-IP-Address"), address));
47     std::vector<uint8_t> bytes {'1', '2', '3', 'a', 'b', 'c'};
48     attributes.push_back(new RadProto::Bytes(m_dictionaries.attributeCode("Callback-Number"), bytes));
49     std::vector<uint8_t> chapPassword {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
50     attributes.push_back(new RadProto::ChapPassword(m_dictionaries.attributeCode("CHAP-Password"), 1, chapPassword));
51
52     std::vector<RadProto::VendorSpecific> vendorSpecific;
53     std::vector<uint8_t> vendorValue {0, 0, 0, 3};
54     vendorSpecific.push_back(RadProto::VendorSpecific(m_dictionaries.vendorCode("Dlink"), m_dictionaries.vendorAttributeCode("Dlink", "Dlink-User-Level"), vendorValue));
55
56     if (request.type() != RadProto::ACCESS_REQUEST)
57         return RadProto::Packet(RadProto::ACCESS_REJECT, request.id(), request.auth(), {}, {});
58
59     if (findUser(request))
60         return RadProto::Packet(RadProto::ACCESS_ACCEPT, request.id(), request.auth(), attributes, vendorSpecific);
61
62     printfd(__FILE__, "Error findUser\n");
63     return RadProto::Packet(RadProto::ACCESS_REJECT, request.id(), request.auth(), {}, {});
64 }
65
66 void Server::handleSend(const error_code& ec)
67 {
68     if (m_token.stop_requested())
69         return;
70
71     if (ec)
72     {
73         m_logger("Error asyncSend: %s", ec.message().c_str());
74         printfd(__FILE__, "Error asyncSend: '%s'\n", ec.message().c_str());
75     }
76     startReceive();
77 }
78
79 void Server::handleReceive(const error_code& error, const std::optional<RadProto::Packet>& packet, const boost::asio::ip::udp::endpoint& source)
80 {
81     if (m_token.stop_requested())
82         return;
83
84     if (error)
85     {
86         m_logger("Error asyncReceive: %s", error.message().c_str());
87         printfd(__FILE__, "Error asyncReceive: '%s'\n", error.message().c_str());
88     }
89
90     if (packet == std::nullopt)
91     {
92         m_logger("Error asyncReceive: the request packet is missing\n");
93         printfd(__FILE__, "Error asyncReceive: the request packet is missing\n");
94         return;
95     }
96
97     m_radius.asyncSend(makeResponse(*packet), source, [this](const auto& ec){ handleSend(ec); });
98 }
99
100 bool Server::findUser(const RadProto::Packet& packet)
101 {
102     std::string login;
103     std::string password;
104     for (const auto& attribute : packet.attributes())
105     {
106         if (attribute->type() == RadProto::USER_NAME)
107             login = attribute->toString();
108
109         if (attribute->type() == RadProto::USER_PASSWORD)
110             password = attribute->toString();
111     }
112
113     User* user = nullptr;
114     if (m_users->FindByName(login, &user))
115     {
116         m_logger("User '%s' not found.", login.c_str());
117         printfd(__FILE__, "User '%s' NOT found!\n", login.c_str());
118         return false;
119     }
120
121     printfd(__FILE__, "User '%s' FOUND!\n", user->GetLogin().c_str());
122
123     if (password != user->GetProperties().password.Get())
124     {
125         m_logger("User's password is incorrect. %s", password.c_str());
126         printfd(__FILE__, "User's password is incorrect.\n", password.c_str());
127         return false;
128     }
129     return true;
130 }