Kea 3.1.1
client_dictionary.cc
Go to the documentation of this file.
1// Copyright (C) 2023-2025 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
9#include <util/str.h>
10#include <client_dictionary.h>
11#include <radius_log.h>
12#include <boost/lexical_cast.hpp>
13#include <fstream>
14#include <limits>
15#include <sstream>
16
17using namespace isc;
18using namespace isc::util;
19using namespace std;
20
21namespace isc {
22namespace radius {
23
24string
26 switch (static_cast<uint8_t>(value)) {
27 case PW_TYPE_STRING:
28 return ("string");
29 case PW_TYPE_INTEGER:
30 return ("integer");
31 case PW_TYPE_IPADDR:
32 return ("ipaddr");
34 return ("ipv6addr");
36 return ("ipv6prefix");
37 default:
38 // Impossible case.
39 return ("unknown?");
40 }
41}
42
44textToAttrValueType(const string& name) {
45 if (name == "string") {
46 return (PW_TYPE_STRING);
47 } else if ((name == "integer") || (name == "date")) {
48 return (PW_TYPE_INTEGER);
49 } else if (name == "ipaddr") {
50 return (PW_TYPE_IPADDR);
51 } else if (name == "ipv6addr") {
52 return (PW_TYPE_IPV6ADDR);
53 } else if (name == "ipv6prefix") {
54 return (PW_TYPE_IPV6PREFIX);
55 } else {
56 isc_throw(OutOfRange, "unknown AttrValueType name " << name);
57 }
58}
59
60AttrDefs&
62 static AttrDefs defs;
63 return (defs);
64}
65
67AttrDefs::getByType(const uint8_t type) const {
68 auto const& idx = container_.get<0>();
69 auto it = idx.find(type);
70 if (it != idx.end()) {
71 return (*it);
72 }
73 return (AttrDefPtr());
74}
75
77AttrDefs::getByName(const string& name) const {
78 auto const& idx = container_.get<1>();
79 auto it = idx.find(name);
80 if (it != idx.end()) {
81 return (*it);
82 }
83 auto alias = aliases_.find(name);
84 if (alias != aliases_.end()) {
85 auto ita = idx.find(alias->second);
86 if (ita != idx.end()) {
87 return (*ita);
88 }
89 }
90 return (AttrDefPtr());
91}
92
93void
95 if (!def) {
96 return;
97 }
98 auto& idx1 = container_.get<1>();
99 auto it1 = idx1.find(def->name_);
100 if (it1 != idx1.end()) {
101 if ((def->type_ == (*it1)->type_) &&
102 (def->value_type_ == (*it1)->value_type_)) {
103 // Duplicate: ignore.
104 return;
105 }
106 isc_throw(BadValue, "Illegal attribute redefinition of '" << def->name_
107 << "' type " << static_cast<unsigned>((*it1)->type_)
108 << " value type " << attrValueTypeToText((*it1)->value_type_)
109 << " by " << static_cast<unsigned>(def->type_)
110 << " " << attrValueTypeToText(def->value_type_));
111 }
112 auto& idx0 = container_.get<0>();
113 auto it0 = idx0.find(def->type_);
114 if (it0 != idx0.end()) {
115 if (def->value_type_ == (*it0)->value_type_) {
116 // Alias.
117 auto p = pair<string, string>(def->name_, (*it0)->name_);
118 static_cast<void>(aliases_.insert(p));
119 return;
120 }
121 isc_throw(BadValue, "Illegal attribute redefinition of '"
122 << (*it0)->name_ << "' type "
123 << static_cast<unsigned>((*it0)->type_) << " value type "
124 << attrValueTypeToText((*it0)->value_type_)
125 << " by '" << def->name_ << "' "
126 << static_cast<unsigned>(def->type_) << " "
127 << attrValueTypeToText(def->value_type_));
128 }
129 static_cast<void>(container_.insert(def));
130}
131
132string
133AttrDefs::getName(const uint8_t type) const {
134 AttrDefPtr def = getByType(type);
135 if (def) {
136 return (def->name_);
137 }
138 ostringstream oss;
139 oss << "Attribute-" << static_cast<unsigned>(type);
140 return (oss.str());
141}
142
144AttrDefs::getByName(const uint8_t type, const string& name) const {
145 auto const& idx = ic_container_.get<0>();
146 auto it = idx.find(boost::make_tuple(type, name));
147 if (it != idx.end()) {
148 return (*it);
149 }
150 return (IntCstDefPtr());
151}
152
154AttrDefs::getByValue(const uint8_t type, const uint32_t value) const {
155 auto const& idx = ic_container_.get<1>();
156 auto it = idx.find(boost::make_tuple(type, value));
157 if (it != idx.end()) {
158 return (*it);
159 }
160 return (IntCstDefPtr());
161}
162
163void
165 if (!def) {
166 return;
167 }
168 auto& idx = ic_container_.get<0>();
169 auto it = idx.find(boost::make_tuple(def->type_, def->name_));
170 if (it != idx.end()) {
171 if (def->value_ == (*it)->value_) {
172 // Duplicate: ignore.
173 return;
174 }
175 isc_throw(BadValue, "Illegal integer constant redefinition of '"
176 << def->name_ << "' for attribute '" << getName(def->type_)
177 << "' value " << (*it)->value_ << " by " << def->value_);
178 }
179 static_cast<void>(ic_container_.insert(def));
180}
181
182void
183AttrDefs::parseLine(const string& line) {
184 // Ignore empty lines.
185 if (line.empty()) {
186 return;
187 }
188 // Ignore comments.
190 if (line[0] == '#') {
191 return;
192 }
193 // Take tokens.
194 auto tokens = str::tokens(line);
195 // Ignore blank lines.
196 if (tokens.empty()) {
197 return;
198 }
199 // Attribute definition.
200 if (tokens[0] == "ATTRIBUTE") {
201 if (tokens.size() != 4) {
202 isc_throw(Unexpected, "expected 4 tokens, got " << tokens.size());
203 }
204 const string& name = tokens[1];
205 const string& type_str = tokens[2];
206 uint8_t type = 0;
207 try {
208 int64_t type64 = boost::lexical_cast<int64_t>(type_str);
209 // Ignore attribute types outside [0..255].
210 if ((type64 < numeric_limits<uint8_t>::min()) ||
211 (type64 > numeric_limits<uint8_t>::max())) {
212 return;
213 }
214 type = static_cast<uint8_t>(type64);
215 } catch (...) {
216 isc_throw(Unexpected, "can't parse attribute type " << type_str);
217 }
218 AttrValueType value_type = textToAttrValueType(tokens[3]);
219 AttrDefPtr def(new AttrDef(type, name, value_type));
220 add(def);
221 return;
222 }
223 // Integer constant definition.
224 if (tokens[0] == "VALUE") {
225 if (tokens.size() != 4) {
226 isc_throw(Unexpected, "expected 4 tokens, got " << tokens.size());
227 }
228 const string& attr_str = tokens[1];
229 AttrDefPtr attr = getByName(attr_str);
230 if (!attr) {
231 isc_throw(Unexpected, "unknown attribute '" << attr_str << "'");
232 }
233 if (attr->value_type_ != PW_TYPE_INTEGER) {
234 isc_throw(Unexpected, "attribute '" << attr_str
235 << "' is not an integer attribute");
236 }
237 const string& name = tokens[2];
238 const string& value_str = tokens[3];
239 uint32_t value = 0;
240 try {
241 int64_t val = boost::lexical_cast<int64_t>(value_str);
242 if ((val < numeric_limits<int32_t>::min()) ||
243 (val > numeric_limits<uint32_t>::max())) {
244 isc_throw(Unexpected, "not 32 bit " << value_str);
245 }
246 value = static_cast<uint32_t>(val);
247 } catch (...) {
248 isc_throw(Unexpected, "can't parse integer value " << value_str);
249 }
250 IntCstDefPtr def(new IntCstDef(attr->type_, name, value));
251 add(def);
252 return;
253 }
254 isc_throw(Unexpected, "unknown dictionary entry '" << tokens[0] << "'");
255}
256
257void
258AttrDefs::readDictionary(const string& path) {
259 ifstream ifs(path);
260 if (!ifs.is_open()) {
261 isc_throw(BadValue, "can't open dictionary '" << path << "': "
262 << strerror(errno));
263 }
264 if (!ifs.good()) {
265 isc_throw(BadValue, "bad dictionary '" << path << "'");
266 }
267 try {
268 readDictionary(ifs);
269 ifs.close();
270 } catch (const exception& ex) {
271 ifs.close();
272 isc_throw(BadValue, ex.what() << " in dictionary '" << path << "'");
273 }
274}
275
276void
278 size_t lines = 0;
279 string line;
280 try {
281 while (is.good()) {
282 ++lines;
283 getline(is, line);
284 parseLine(line);
285 }
286 if (!is.eof()) {
287 isc_throw(BadValue, "I/O error: " << strerror(errno));
288 }
289 } catch (const exception& ex) {
290 isc_throw(BadValue, ex.what() << " at line " << lines);
291 }
292}
293
294void
296 for (auto const& it : defs) {
297 // Check by name.
298 AttrDefPtr def = getByName(it.name_);
299 if (!def) {
300 isc_throw(Unexpected, "missing standard attribute definition for '"
301 << it.name_ << "'");
302 }
303 if (def->type_ != it.type_) {
304 isc_throw(Unexpected, "incorrect standard attribute definition "
305 << "for '" << it.name_ << "': type is "
306 << static_cast<unsigned>(def->type_) << ", must be "
307 << static_cast<unsigned>(it.type_));
308 }
309 if (def->value_type_ != it.value_type_) {
310 isc_throw(Unexpected, "incorrect standard attribute definition "
311 << "for '" << it.name_ << "': value type is "
312 << attrValueTypeToText(def->value_type_)
313 << ", must be "
314 << attrValueTypeToText(it.value_type_));
315 }
316 }
317}
318
319} // end of namespace isc::radius
320} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
RADIUS attribute definition.
void add(AttrDefPtr def)
Add (or replace) an attribute definition.
static AttrDefs & instance()
Returns a single instance.
void readDictionary(const std::string &path)
Read a dictionary from a file.
AttrDefContainer container_
Attribute definition container.
AttrDefPtr getByName(const std::string &name) const
Get attribute definition by name.
IntCstDefContainer ic_container_
Integer constant definition container.
AttrDefAliases aliases_
Attribute aliases.
std::string getName(const uint8_t type) const
Get attribute name.
AttrDefPtr getByType(const uint8_t type) const
Get attribute definition by type.
IntCstDefPtr getByValue(const uint8_t type, const uint32_t value) const
Get integer constant definition by attribute type and value.
void parseLine(const std::string &line)
Parse a dictionary line.
void checkStandardDefs(const AttrDefList &defs) const
Check if a list of standard attribute definitions are available and correct.
RADIUS integer constant definitions.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< IntCstDef > IntCstDefPtr
Shared pointers to Integer constant definition.
std::list< AttrDef > AttrDefList
List of Attribute definitions.
AttrValueType
Attribute value types.
boost::shared_ptr< AttrDef > AttrDefPtr
Shared pointers to Attribute definition.
AttrValueType textToAttrValueType(const string &name)
AttrValueType name -> value function.
string attrValueTypeToText(const AttrValueType value)
AttrValueType value -> name function.
vector< string > tokens(const string &text, const string &delim, bool escape)
Split string into tokens.
Definition str.cc:52
Defines the logger used by the top-level component of kea-lfc.