Kea 3.3.4
rbac_api.cc
Go to the documentation of this file.
1// Copyright (C) 2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10
11#include <rbac/rbac_api.h>
12#include <rbac_log.h>
13
14// C++11 has no directory walking tool.
15#include <cerrno>
16#include <iostream>
17
18#include <dirent.h>
19
20using namespace isc;
21using namespace isc::data;
22using namespace isc::rbac;
23using namespace std;
24
25namespace isc {
26namespace rbac {
27
29
30set<string> apiAccesses;
31
32set<string> apiHooks;
33
35Api::getApiByName(const string& name) {
36 auto const& it = apiTable.find(name);
37 if (it == apiTable.cend()) {
38 return (ApiPtr());
39 }
40 return (*it);
41}
42
43void
44Api::fillApiTable(const string& dirname) {
45 DIR* dir = 0;
46 try {
47 dir = opendir(dirname.c_str());
48 if (!dir) {
49 isc_throw(BadValue, "can't open directory '" << dirname
50 << "': " << string(strerror(errno)));
51 }
52 std::unique_ptr<DIR, void(*)(DIR*)> defer(dir, [](DIR* d) { closedir(d); });
53 for (;;) {
54 struct dirent *ent = readdir(dir);
55 if (!ent) {
56 // done or in error but do not care...
57 break;
58 }
59 string filename(ent->d_name);
60 size_t len = filename.size();
61 if (len < 6) {
62 // too short: skip it.
63 continue;
64 }
65 if ((filename[0] == '_') ||
66 (filename[len - 1] != 'n') ||
67 (filename[len - 2] != 'o') ||
68 (filename[len - 3] != 's') ||
69 (filename[len - 4] != 'j') ||
70 (filename[len - 5] != '.')) {
71 // not [^_]*.json: skip it.
72 continue;
73 }
74 filename = dirname + "/" + filename;
75 ConstElementPtr json = Element::fromJSONFile(filename, true);
76 Api::parse(json, true);
77 }
78 } catch (const std::exception& ex) {
79 isc_throw(BadValue, "fill API table from '" << dirname
80 << "' failed with " << ex.what());
81 }
82
83 if (apiTable.empty()) {
84 isc_throw(BadValue, "can't fill API table from '" << dirname
85 << "': got no command config?");
86 }
87
89 .arg(dirname)
90 .arg(apiTable.size())
91 .arg(apiAccesses.size())
92 .arg(apiHooks.size());
93}
94
95void
96Api::parse(ConstElementPtr cfg, bool others) {
97 if (!cfg) {
98 isc_throw(BadValue, "parse null command config");
99 }
100 if (cfg->getType() != Element::map) {
101 isc_throw(BadValue, "command config is not a map");
102 }
103 string name;
104 string access;
105 string hook;
106 for (auto const& entry : cfg->mapValue()) {
107 if (entry.first == "name") {
108 if (entry.second->getType() != Element::string) {
109 isc_throw(BadValue, "command name is not a string");
110 }
111 name = entry.second->stringValue();
112 if (name.empty()) {
113 isc_throw(BadValue, "command name is empty");
114 }
115 } else if (entry.first == "access") {
116 if (entry.second->getType() != Element::string) {
117 isc_throw(BadValue, "command access is not a string");
118 }
119 access = entry.second->stringValue();
120 if (access.empty()) {
121 isc_throw(BadValue, "command access is empty");
122 }
123 if ((access != "read") && (access != "write")) {
124 isc_throw(BadValue, "command access '" << access
125 << "' is not 'read' or 'write'");
126 }
127 } else if (entry.first == "hook") {
128 if (entry.second->getType() != Element::string) {
129 isc_throw(BadValue, "command hook is not a string");
130 }
131 hook = entry.second->stringValue();
132 } else if (!others) {
133 isc_throw(BadValue, "command spurious keyword '"
134 << entry.first << "'");
135 }
136 }
137 if (name.empty()) {
138 isc_throw(BadValue, "'name' is required in command config");
139 }
140 if (access.empty()) {
141 isc_throw(BadValue, "'access' is required in command config");
142 }
143 if (Api::getApiByName(name)) {
144 isc_throw(BadValue, "command '" << name << "' is already defined");
145 }
146 static_cast<void>(apiTable.insert(ApiPtr(new Api(name, access, hook))));
147 static_cast<void>(apiAccesses.insert(access));
148 if (!hook.empty()) {
149 static_cast<void>(apiHooks.insert(hook));
150 }
151}
152
153} // end of namespace rbac
154} // end of namespace isc
@ map
Definition data.h:160
@ string
Definition data.h:157
static ElementPtr fromJSONFile(const std::string &file_name, bool preproc=false)
Reads contents of specified file and interprets it as JSON.
Definition data.cc:884
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static ApiPtr getApiByName(const std::string &name)
Lookup in the table.
Definition rbac_api.cc:35
static void parse(data::ConstElementPtr cfg, bool others=false)
Parse a command config.
Definition rbac_api.cc:96
static void fillApiTable(const std::string &dirname)
Fill the API command table.
Definition rbac_api.cc:44
Api(const std::string &name, const std::string &access, const std::string &hook)
Constructor.
Definition rbac_api.h:37
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
isc::log::Logger rbac_logger("rbac-hooks")
Definition rbac_log.h:18
set< string > apiHooks
The API hook list.
Definition rbac_api.cc:32
boost::shared_ptr< Api > ApiPtr
Type of shared pointer to Api.
Definition rbac_api.h:26
ApiTable apiTable
The API command table.
Definition rbac_api.cc:28
set< string > apiAccesses
The API access list (should be "read" and "write").
Definition rbac_api.cc:30
boost::multi_index_container< ApiPtr, boost::multi_index::indexed_by< boost::multi_index::hashed_unique< boost::multi_index::tag< ApiNameIndexTag >, boost::multi_index::const_mem_fun< Api, std::string, &Api::getName > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ApiAccessIndexTag >, boost::multi_index::const_mem_fun< Api, std::string, &Api::getAccess > >, boost::multi_index::hashed_non_unique< boost::multi_index::tag< ApiHookIndexTag >, boost::multi_index::const_mem_fun< Api, std::string, &Api::getHook > > > > ApiTable
The type of the API command table.
Definition rbac_api.h:137
Defines the logger used by the top-level component of kea-lfc.
const isc::log::MessageID RBAC_READ_API_FILES