Fixes for doxygen comments
[oonf.git] / src-api / config / cfg_validate.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 #include <errno.h>
47 #include <stdio.h>
48
49 #include "common/autobuf.h"
50 #include "common/bitmap256.h"
51 #include "common/common_types.h"
52 #include "common/isonumber.h"
53 #include "common/netaddr.h"
54 #include "common/netaddr_acl.h"
55
56 #include "config/cfg.h"
57 #include "config/cfg_validate.h"
58
59 /**
60  * Validate if a value against a specific printable string
61  * @param out output buffer for error messages
62  * @param section_name name of configuration section
63  * @param entry_name name of configuration entry
64  * @param value value that needs to be validated
65  * @param len maximum length of printable string
66  * @return 0 if value is valid, -1 otherwise
67  */
68 int
69 cfg_validate_printable(
70   struct autobuf *out, const char *section_name, const char *entry_name, const char *value, size_t len) {
71   if (cfg_validate_strlen(out, section_name, entry_name, value, len)) {
72     return -1;
73   }
74   if (!str_is_printable(value)) {
75     /* not a printable ascii character */
76     cfg_append_printable_line(out,
77       "Value '%s' for entry '%s'"
78       " in section %s has non-printable characters",
79       value, entry_name, section_name);
80     return -1;
81   }
82   return 0;
83 }
84
85 /**
86  * Validate if a value against a specific string
87  * @param out output buffer for error messages
88  * @param section_name name of configuration section
89  * @param entry_name name of configuration entry
90  * @param value value that needs to be validated
91  * @param len maximum length of string
92  * @return 0 if value is valid, -1 otherwise
93  */
94 int
95 cfg_validate_strlen(
96   struct autobuf *out, const char *section_name, const char *entry_name, const char *value, size_t len) {
97   if (strlen(value) > len) {
98     cfg_append_printable_line(out,
99       "Value '%s' for entry '%s'"
100       " in section %s is longer than %" PRINTF_SIZE_T_SPECIFIER " characters",
101       value, entry_name, section_name, len);
102     return -1;
103   }
104   return 0;
105 }
106
107 /**
108  * Validate if a value against a specific list of strings
109  * @param out output buffer for error messages
110  * @param section_name name of configuration section
111  * @param entry_name name of configuration entry
112  * @param value value that needs to be validated
113  * @param callback callback function to get choices from
114  * @param choices_count number of strings in list
115  * @param ptr customization pointer for callback
116  * @return 0 if value is valid, -1 otherwise
117  */
118 int
119 cfg_validate_choice(struct autobuf *out, const char *section_name, const char *entry_name, const char *value,
120   const char *(*callback)(size_t idx, const void *ptr), size_t choices_count, const void *ptr) {
121   int i;
122   i = cfg_get_choice_index(value, callback, choices_count, ptr);
123   if (i >= 0) {
124     return 0;
125   }
126
127   cfg_append_printable_line(out,
128     "Unknown value '%s'"
129     " for entry '%s' in section %s",
130     value, entry_name, section_name);
131   return -1;
132 }
133
134 /**
135  * Validate if a value against a specific integer
136  * @param out output buffer for error messages
137  * @param section_name name of configuration section
138  * @param entry_name name of configuration entry
139  * @param value value that needs to be validated
140  * @param min minimum value of number including fractional digits
141  * @param max maximum value of number including fractional digits
142  * @param bytelen number of bytes available for target number
143  * @param fraction number of fractional digits of target number
144  * @return 0 if value is valid, -1 otherwise
145  */
146 int
147 cfg_validate_int(struct autobuf *out, const char *section_name, const char *entry_name, const char *value, int64_t min,
148   int64_t max, uint16_t bytelen, uint16_t fraction) {
149   int64_t i, min64, max64;
150   struct isonumber_str hbuf;
151
152   if (isonumber_to_s64(&i, value, fraction)) {
153     if (fraction) {
154       cfg_append_printable_line(out,
155         "Value '%s' for entry '%s'"
156         " in section %s is not a fractional %d-byte integer"
157         " with a maximum of %d fractional digits",
158         value, entry_name, section_name, bytelen, fraction);
159     }
160     else {
161       cfg_append_printable_line(out,
162         "Value '%s' for entry '%s'"
163         " in section %s is not a %d-byte integer.",
164         value, entry_name, section_name, bytelen);
165     }
166     return -1;
167   }
168
169   min64 = INT64_MIN >> (8 * (8 - bytelen));
170   max64 = INT64_MAX >> (8 * (8 - bytelen));
171
172   if (i < min64 || i > max64) {
173     cfg_append_printable_line(out,
174       "Value '%s' for entry '%s' in section %s is "
175       "too %s for a %d-hyte integer with %d fractional digits",
176       value, entry_name, section_name, i < min ? "small" : "large", bytelen, fraction);
177   }
178
179   if (i < min) {
180     cfg_append_printable_line(out,
181       "Value '%s' for entry '%s' in section %s is "
182       "smaller than %s",
183       value, entry_name, section_name, isonumber_from_s64(&hbuf, min, "", fraction, true));
184     return -1;
185   }
186   if (i > max) {
187     cfg_append_printable_line(out,
188       "Value '%s' for entry '%s' in section %s is "
189       "larger than %s",
190       value, entry_name, section_name, isonumber_from_s64(&hbuf, min, "", fraction, true));
191     return -1;
192   }
193   return 0;
194 }
195
196 /**
197  * Validate if a value against a specific network address
198  * @param out output buffer for error messages
199  * @param section_name name of configuration section
200  * @param entry_name name of configuration entry
201  * @param value value that needs to be validated
202  * @param prefix true if the address might be a network prefix
203  * @param af_types list of address families the address might be
204  * @param af_types_count number of address families specified
205  * @return 0 if value is valid, -1 otherwise
206  */
207 int
208 cfg_validate_netaddr(struct autobuf *out, const char *section_name, const char *entry_name, const char *value,
209   bool prefix, const int8_t *af_types, size_t af_types_count) {
210   struct netaddr addr;
211   uint8_t max_prefix;
212   size_t i;
213
214   if (netaddr_from_string(&addr, value)) {
215     cfg_append_printable_line(out,
216       "Value '%s' for entry '%s'"
217       " in section %s is no valid network address",
218       value, entry_name, section_name);
219     return -1;
220   }
221
222   max_prefix = netaddr_get_maxprefix(&addr);
223
224   /* check prefix length */
225   if (netaddr_get_prefix_length(&addr) > max_prefix) {
226     cfg_append_printable_line(out,
227       "Value '%s' for entry '%s'"
228       " in section %s has an illegal prefix length",
229       value, entry_name, section_name);
230     return -1;
231   }
232   if (!prefix && netaddr_get_prefix_length(&addr) != max_prefix) {
233     cfg_append_printable_line(out,
234       "Value '%s' for entry '%s'"
235       " in section %s must be a single address, not a prefix",
236       value, entry_name, section_name);
237     return -1;
238   }
239
240   for (i = 0; i < af_types_count; i++) {
241     if (af_types[i] == netaddr_get_address_family(&addr)) {
242       return 0;
243     }
244   }
245
246   /* at least one condition was set, but no one matched */
247   cfg_append_printable_line(out,
248     "Value '%s' for entry '%s'"
249     " in section '%s' is wrong address type",
250     value, entry_name, section_name);
251   return -1;
252 }
253
254 /**
255  * Validate if a value against a specific network access control list
256  * @param out output buffer for error messages
257  * @param section_name name of configuration section
258  * @param entry_name name of configuration entry
259  * @param value value that needs to be validated
260  * @param prefix true if the address might be a network prefix
261  * @param af_types list of address families the address might be
262  * @param af_types_count number of address families specified
263  * @return 0 if value is valid, -1 otherwise
264  */
265 int
266 cfg_validate_acl(struct autobuf *out, const char *section_name, const char *entry_name, const char *value, bool prefix,
267   const int8_t *af_types, size_t af_types_count) {
268   struct netaddr_acl dummy;
269
270   if (netaddr_acl_handle_keywords(&dummy, value) == 0) {
271     return 0;
272   }
273
274   if (*value == '+' || *value == '-') {
275     return cfg_validate_netaddr(out, section_name, entry_name, &value[1], prefix, af_types, af_types_count);
276   }
277
278   return cfg_validate_netaddr(out, section_name, entry_name, value, prefix, af_types, af_types_count);
279 }
280
281 /**
282  * Validates if a value is valid part of a bitmap256 definition
283  * @param out output buffer for error messages
284  * @param section_name name of configuration section
285  * @param entry_name name of configuration entry
286  * @param value value that needs to be validated
287  * @return 0 if value is valid, -1 otherwise
288  */
289 int
290 cfg_validate_bitmap256(struct autobuf *out, const char *section_name, const char *entry_name, const char *value) {
291   int num;
292   char *end;
293
294   if (strcasecmp(value, "all") == 0 || strcasecmp(value, "none") == 0) {
295     return 0;
296   }
297
298   errno = 0;
299   num = strtol(value, &end, 10);
300   if (errno != 0 || *end != 0 || num < -255 || num > 255) {
301     cfg_append_printable_line(out,
302       "Value '%s' for entry '%s'"
303       " in section %s must be a '" BITMAP256_ALL "', '" BITMAP256_NONE "' or a number between 0 and 255"
304       " (with optional '-' in front of the number)",
305       value, entry_name, section_name);
306     return -1;
307   }
308   return 0;
309 }
310
311 /**
312  * Validates if a value is defined as in a list of configuration
313  * entries split by whitespaces.
314  * @param out output buffer for error messages
315  * @param section_name name of configuration section
316  * @param entry_name name of configuration entry
317  * @param value value that needs to be validated
318  * @param entries pointer to array of configuration entries
319  * @param entry_count number of configuration entries
320  * @return 0 if value is valid, -1 otherwise
321  */
322 int
323 cfg_validate_tokens(struct autobuf *out, const char *section_name, const char *entry_name, const char *value,
324   struct cfg_schema_entry *entries, size_t entry_count, struct cfg_schema_token_customizer *custom) {
325   char buffer[256];
326   char section_name_entry[32];
327   const char *ptr;
328   size_t i;
329
330   if (str_countwords(value) < entry_count) {
331     cfg_append_printable_line(out,
332       "Missing token for entry '%s'"
333       " in section %s. At least %" PRINTF_SIZE_T_SPECIFIER " tokens"
334       " expected. Tokens must be separated by whitespaces.",
335       entry_name, section_name, entry_count);
336     return -1;
337   }
338   snprintf(section_name_entry, sizeof(section_name_entry), "%s.%s", section_name, entry_name);
339
340   /* check each token */
341   ptr = value;
342   for (i = 0; i < entry_count - 1; i++) {
343     ptr = str_cpynextword(buffer, ptr, sizeof(buffer));
344
345     /* see if token is valid */
346     if (entries[i].cb_validate(&entries[i], section_name_entry, buffer, out)) {
347       return -1;
348     }
349   }
350
351   /* see if the rest of the value is a valid "last" token */
352   if (entries[i].cb_validate(&entries[entry_count - 1], section_name_entry, ptr, out)) {
353     return -1;
354   }
355
356   if (custom && custom->cb_validator) {
357     return custom->cb_validator(out, section_name, entry_name, value, entries, entry_count);
358   }
359   return 0;
360 }