1 #include "config.h"
2 
3 #include "snmp_conf_manager.hpp"
4 
5 #include "snmp_serialize.hpp"
6 #include "snmp_util.hpp"
7 #include "xyz/openbmc_project/Common/error.hpp"
8 
9 #include <arpa/inet.h>
10 
11 #include <phosphor-logging/elog-errors.hpp>
12 #include <phosphor-logging/log.hpp>
13 
14 #include <experimental/filesystem>
15 
16 namespace phosphor
17 {
18 namespace network
19 {
20 namespace snmp
21 {
22 
23 using namespace phosphor::logging;
24 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
25 using Argument = xyz::openbmc_project::Common::InvalidArgument;
26 
27 ConfManager::ConfManager(sdbusplus::bus::bus& bus, const char* objPath) :
28     details::CreateIface(bus, objPath, true),
29     dbusPersistentLocation(SNMP_CONF_PERSIST_PATH), bus(bus),
30     objectPath(objPath)
31 {}
32 
33 std::string ConfManager::client(std::string address, uint16_t port)
34 {
35     // will throw exception if it is already configured.
36     checkClientConfigured(address, port);
37 
38     lastClientId++;
39     try
40     {
41         // just to check whether given address is valid or not.
42         resolveAddress(address);
43     }
44     catch (const InternalFailure& e)
45     {
46         log<level::ERR>("Not a valid address"),
47             entry("ADDRESS=%s", address.c_str());
48         elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"),
49                               Argument::ARGUMENT_VALUE(address.c_str()));
50     }
51 
52     // create the D-Bus object
53     std::experimental::filesystem::path objPath;
54     objPath /= objectPath;
55     objPath /= std::to_string(lastClientId);
56 
57     auto client = std::make_unique<phosphor::network::snmp::Client>(
58         bus, objPath.string().c_str(), *this, address, port);
59 
60     // save the D-Bus object
61     serialize(lastClientId, *client, dbusPersistentLocation);
62 
63     this->clients.emplace(lastClientId, std::move(client));
64     return objPath.string();
65 }
66 
67 void ConfManager::checkClientConfigured(const std::string& address,
68                                         uint16_t port)
69 {
70     if (address.empty())
71     {
72         log<level::ERR>("Invalid address");
73         elog<InvalidArgument>(Argument::ARGUMENT_NAME("ADDRESS"),
74                               Argument::ARGUMENT_VALUE(address.c_str()));
75     }
76 
77     unsigned char buf[sizeof(struct in6_addr)];
78     int isValid = inet_pton(AF_INET, address.c_str(), buf);
79     if (isValid < 1)
80     {
81         log<level::ERR>("Invalid address");
82         elog<InvalidArgument>(Argument::ARGUMENT_NAME("ADDRESS"),
83                               Argument::ARGUMENT_VALUE(address.c_str()));
84     }
85 
86     for (const auto& val : clients)
87     {
88         if (val.second.get()->address() == address &&
89             val.second.get()->port() == port)
90         {
91             log<level::ERR>("Client already exist");
92             // TODO Add the error(Object already exist) in the D-Bus interface
93             // then make the change here,meanwhile send the Internal Failure.
94             elog<InvalidArgument>(
95                 Argument::ARGUMENT_NAME("ADDRESS"),
96                 Argument::ARGUMENT_VALUE("Client already exist."));
97         }
98     }
99 }
100 
101 void ConfManager::deleteSNMPClient(Id id)
102 {
103     auto it = clients.find(id);
104     if (it == clients.end())
105     {
106         log<level::ERR>("Unable to delete the snmp client.",
107                         entry("ID=%d", id));
108         return;
109     }
110 
111     std::error_code ec;
112     // remove the persistent file
113     fs::path fileName = dbusPersistentLocation;
114     fileName /= std::to_string(id);
115 
116     if (fs::exists(fileName))
117     {
118         if (!fs::remove(fileName, ec))
119         {
120             log<level::ERR>("Unable to delete the file",
121                             entry("FILE=%s", fileName.c_str()),
122                             entry("ERROR=%d", ec.value()));
123         }
124     }
125     else
126     {
127         log<level::ERR>("File doesn't exist",
128                         entry("FILE=%s", fileName.c_str()));
129     }
130     // remove the D-Bus Object.
131     this->clients.erase(it);
132 }
133 
134 void ConfManager::restoreClients()
135 {
136     if (!fs::exists(dbusPersistentLocation) ||
137         fs::is_empty(dbusPersistentLocation))
138     {
139         return;
140     }
141 
142     for (auto& confFile :
143          fs::recursive_directory_iterator(dbusPersistentLocation))
144     {
145         if (!fs::is_regular_file(confFile))
146         {
147             continue;
148         }
149 
150         auto managerID = confFile.path().filename().string();
151         Id idNum = std::stol(managerID);
152 
153         fs::path objPath = objectPath;
154         objPath /= managerID;
155         auto manager =
156             std::make_unique<Client>(bus, objPath.string().c_str(), *this);
157         if (deserialize(confFile.path(), *manager))
158         {
159             manager->emit_object_added();
160             this->clients.emplace(idNum, std::move(manager));
161             if (idNum > lastClientId)
162             {
163                 lastClientId = idNum;
164             }
165         }
166     }
167 }
168 
169 } // namespace snmp
170 } // namespace network
171 } // namespace phosphor
172