1 /*-
2  * Copyright 2016 Vsevolod Stakhov
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef CFG_RCL_H_
17 #define CFG_RCL_H_
18 
19 #include "config.h"
20 #include "cfg_file.h"
21 #include "ucl.h"
22 #include "mem_pool.h"
23 
24 #define CFG_RCL_ERROR cfg_rcl_error_quark ()
25 static inline GQuark
cfg_rcl_error_quark(void)26 cfg_rcl_error_quark (void)
27 {
28 	return g_quark_from_static_string ("cfg-rcl-error-quark");
29 }
30 
31 #ifdef  __cplusplus
32 extern "C" {
33 #endif
34 
35 struct rspamd_rcl_section;
36 struct rspamd_config;
37 struct rspamd_rcl_default_handler_data;
38 
39 enum rspamd_rcl_flag {
40 	RSPAMD_CL_FLAG_TIME_FLOAT = 0x1 << 0,
41 	RSPAMD_CL_FLAG_TIME_TIMEVAL = 0x1 << 1,
42 	RSPAMD_CL_FLAG_TIME_TIMESPEC = 0x1 << 2,
43 	RSPAMD_CL_FLAG_TIME_INTEGER = 0x1 << 3,
44 	RSPAMD_CL_FLAG_TIME_UINT_32 = 0x1 << 4,
45 	RSPAMD_CL_FLAG_INT_16 = 0x1 << 5,
46 	RSPAMD_CL_FLAG_INT_32 = 0x1 << 6,
47 	RSPAMD_CL_FLAG_INT_64 = 0x1 << 7,
48 	RSPAMD_CL_FLAG_UINT = 0x1 << 8,
49 	RSPAMD_CL_FLAG_INT_SIZE = 0x1 << 9,
50 	RSPAMD_CL_FLAG_STRING_PATH = 0x1 << 10,
51 	RSPAMD_CL_FLAG_BOOLEAN_INVERSE = 0x1 << 11,
52 	RSPAMD_CL_FLAG_STRING_LIST_HASH = 0x1 << 12,
53 	RSPAMD_CL_FLAG_MULTIPLE = 0x1 << 13,
54 	RSPAMD_CL_FLAG_SIGNKEY = 0x1 << 14,
55 	RSPAMD_CL_FLAG_NISTKEY = 0x1 << 15,
56 };
57 
58 struct rspamd_rcl_struct_parser {
59 	struct rspamd_config *cfg;
60 	gpointer user_struct;
61 	goffset offset;
62 	enum rspamd_rcl_flag flags;
63 };
64 
65 
66 /**
67  * Common handler type
68  * @param cfg configuration
69  * @param obj object to parse
70  * @param ud user data (depends on section)
71  * @param err error object
72  * @return TRUE if a section has been parsed
73  */
74 typedef gboolean (*rspamd_rcl_handler_t) (rspamd_mempool_t *pool,
75 	const ucl_object_t *obj,
76 	const gchar *key,
77 	gpointer ud,
78 	struct rspamd_rcl_section *section,
79 	GError **err);
80 
81 typedef gboolean (*rspamd_rcl_default_handler_t) (rspamd_mempool_t *pool,
82 	const ucl_object_t *obj,
83 	gpointer ud,
84 	struct rspamd_rcl_section *section,
85 	GError **err);
86 
87 /**
88  * A handler type that is called at the end of section parsing
89  * @param cfg configuration
90  * @param ud user data
91  */
92 typedef void (*rspamd_rcl_section_fin_t)(rspamd_mempool_t *pool, gpointer ud);
93 
94 /**
95  * Add a default handler for a section
96  * @param section section pointer
97  * @param name name of param
98  * @param handler handler of param
99  * @param offset offset in a structure
100  * @param flags flags for the parser
101  * @return newly created structure
102  */
103 struct rspamd_rcl_default_handler_data *rspamd_rcl_add_default_handler (
104 		struct rspamd_rcl_section *section,
105 		const gchar *name,
106 		rspamd_rcl_default_handler_t handler,
107 		goffset offset,
108 		gint flags,
109 		const gchar *doc_string);
110 
111 /**
112  * Add new section to the configuration
113  * @param top top section
114  * @param name the name of the section
115  * @param key_attr name of the attribute that should be used as key attribute
116  * @param handler handler function for all attributes
117  * @param type type of object handled by a handler
118  * @param required whether at least one of these sections is required
119  * @param strict_type turn on strict check for types for this section
120  * @return newly created structure
121  */
122 struct rspamd_rcl_section *rspamd_rcl_add_section (
123 		struct rspamd_rcl_section **top,
124 		const gchar *name, const gchar *key_attr,
125 		rspamd_rcl_handler_t handler,
126 		enum ucl_type type, gboolean required, gboolean strict_type);
127 
128 struct rspamd_rcl_section *rspamd_rcl_add_section_doc (
129 		struct rspamd_rcl_section **top,
130 		const gchar *name, const gchar *key_attr,
131 		rspamd_rcl_handler_t handler,
132 		enum ucl_type type, gboolean required,
133 		gboolean strict_type,
134 		ucl_object_t *doc_target,
135 		const gchar *doc_string);
136 
137 /**
138  * Init common sections known to rspamd
139  * @return top section
140  */
141 struct rspamd_rcl_section * rspamd_rcl_config_init (struct rspamd_config *cfg,
142 		GHashTable *skip_sections);
143 
144 /**
145  * Get a section specified by path, it understand paths separated by '/' character
146  * @param top top section
147  * @param path '/' divided path
148  * @return
149  */
150 struct rspamd_rcl_section * rspamd_rcl_config_get_section (
151 	struct rspamd_rcl_section *top,
152 	const char *path);
153 
154 /**
155  * Parse configuration
156  * @param top top section
157  * @param cfg rspamd configuration
158  * @param ptr pointer to the target
159  * @param pool pool object
160  * @param obj ucl object to parse
161  * @param err error pointer
162  * @return
163  */
164 gboolean rspamd_rcl_parse (struct rspamd_rcl_section *top,
165 		struct rspamd_config *cfg,
166 		gpointer ptr, rspamd_mempool_t *pool,
167 		const ucl_object_t *obj, GError **err);
168 
169 
170 /**
171  * Parse default structure for a section
172  * @param section section
173  * @param cfg config file
174  * @param obj object to parse
175  * @param ptr ptr to pass
176  * @param err error ptr
177  * @return TRUE if the object has been parsed
178  */
179 gboolean rspamd_rcl_section_parse_defaults (struct rspamd_config *cfg,
180 		struct rspamd_rcl_section *section,
181 		rspamd_mempool_t *pool, const ucl_object_t *obj, gpointer ptr,
182 		GError **err);
183 /**
184  * Here is a section of common handlers that accepts rcl_struct_parser
185  * which itself contains a struct pointer and the offset of a member in a
186  * specific structure
187  */
188 
189 /**
190  * Parse a string field of a structure
191  * @param cfg config pointer
192  * @param obj object to parse
193  * @param ud struct_parser structure
194  * @param section the current section
195  * @param err error pointer
196  * @return TRUE if a string value has been successfully parsed
197  */
198 gboolean rspamd_rcl_parse_struct_string (rspamd_mempool_t *pool,
199 	const ucl_object_t *obj,
200 	gpointer ud,
201 	struct rspamd_rcl_section *section,
202 	GError **err);
203 
204 /**
205  * Parse an integer field of a structure
206  * @param cfg config pointer
207  * @param obj object to parse
208  * @param ud struct_parser structure
209  * @param section the current section
210  * @param err error pointer
211  * @return TRUE if a value has been successfully parsed
212  */
213 gboolean rspamd_rcl_parse_struct_integer (rspamd_mempool_t *pool,
214 	const ucl_object_t *obj,
215 	gpointer ud,
216 	struct rspamd_rcl_section *section,
217 	GError **err);
218 
219 
220 /**
221  * Parse a float field of a structure
222  * @param cfg config pointer
223  * @param obj object to parse
224  * @param ud struct_parser structure
225  * @param section the current section
226  * @param err error pointer
227  * @return TRUE if a value has been successfully parsed
228  */
229 gboolean rspamd_rcl_parse_struct_double (rspamd_mempool_t *pool,
230 	const ucl_object_t *obj,
231 	gpointer ud,
232 	struct rspamd_rcl_section *section,
233 	GError **err);
234 
235 /**
236  * Parse a time field of a structure
237  * @param cfg config pointer
238  * @param obj object to parse
239  * @param ud struct_parser structure (flags mean the exact structure used)
240  * @param section the current section
241  * @param err error pointer
242  * @return TRUE if a value has been successfully parsed
243  */
244 gboolean rspamd_rcl_parse_struct_time (rspamd_mempool_t *pool,
245 	const ucl_object_t *obj,
246 	gpointer ud,
247 	struct rspamd_rcl_section *section,
248 	GError **err);
249 
250 /**
251  * Parse a string list field of a structure presented by a GList* object
252  * @param cfg config pointer
253  * @param obj object to parse
254  * @param ud struct_parser structure (flags mean the exact structure used)
255  * @param section the current section
256  * @param err error pointer
257  * @return TRUE if a value has been successfully parsed
258  */
259 gboolean rspamd_rcl_parse_struct_string_list (rspamd_mempool_t *pool,
260 	const ucl_object_t *obj,
261 	gpointer ud,
262 	struct rspamd_rcl_section *section,
263 	GError **err);
264 
265 /**
266  * Parse a boolean field of a structure
267  * @param cfg config pointer
268  * @param obj object to parse
269  * @param ud struct_parser structure (flags mean the exact structure used)
270  * @param section the current section
271  * @param err error pointer
272  * @return TRUE if a value has been successfully parsed
273  */
274 gboolean rspamd_rcl_parse_struct_boolean (rspamd_mempool_t *pool,
275 	const ucl_object_t *obj,
276 	gpointer ud,
277 	struct rspamd_rcl_section *section,
278 	GError **err);
279 
280 /**
281  * Parse a keypair field of a structure
282  * @param cfg config pointer
283  * @param obj object to parse
284  * @param ud struct_parser structure (flags mean the exact structure used)
285  * @param section the current section
286  * @param err error pointer
287  * @return TRUE if a value has been successfully parsed
288  */
289 gboolean rspamd_rcl_parse_struct_keypair (rspamd_mempool_t *pool,
290 	const ucl_object_t *obj,
291 	gpointer ud,
292 	struct rspamd_rcl_section *section,
293 	GError **err);
294 
295 /**
296  * Parse a pubkey field of a structure
297  * @param cfg config pointer
298  * @param obj object to parse
299  * @param ud struct_parser structure (flags mean the exact structure used)
300  * @param section the current section
301  * @param err error pointer
302  * @return TRUE if a value has been successfully parsed
303  */
304 gboolean rspamd_rcl_parse_struct_pubkey (rspamd_mempool_t *pool,
305 	const ucl_object_t *obj,
306 	gpointer ud,
307 	struct rspamd_rcl_section *section,
308 	GError **err);
309 
310 /**
311  * Parse a inet addr field of a structure
312  * @param cfg config pointer
313  * @param obj object to parse
314  * @param ud struct_parser structure (flags mean the exact structure used)
315  * @param section the current section
316  * @param err error pointer
317  * @return TRUE if a value has been successfully parsed
318  */
319 gboolean rspamd_rcl_parse_struct_addr (rspamd_mempool_t *pool,
320 	const ucl_object_t *obj,
321 	gpointer ud,
322 	struct rspamd_rcl_section *section,
323 	GError **err);
324 
325 /**
326  * Parse a gmime inet address field of a structure
327  * @param cfg config pointer
328  * @param obj object to parse
329  * @param ud struct_parser structure (flags mean the exact structure used)
330  * @param section the current section
331  * @param err error pointer
332  * @return TRUE if a value has been successfully parsed
333  */
334 gboolean rspamd_rcl_parse_struct_mime_addr (rspamd_mempool_t *pool,
335 	const ucl_object_t *obj,
336 	gpointer ud,
337 	struct rspamd_rcl_section *section,
338 	GError **err);
339 
340 /**
341  * Parse a raw ucl object
342  * @param cfg config pointer
343  * @param obj object to parse
344  * @param ud struct_parser structure (flags mean the exact structure used)
345  * @param section the current section
346  * @param err error pointer
347  * @return TRUE if a value has been successfully parsed
348  */
349 gboolean rspamd_rcl_parse_struct_ucl (rspamd_mempool_t *pool,
350 	const ucl_object_t *obj,
351 	gpointer ud,
352 	struct rspamd_rcl_section *section,
353 	GError **err);
354 
355 
356 /**
357  * Utility functions
358  */
359 
360 /**
361  * Register new parser for a worker type of an option with the specified name
362  * @param cfg config structure
363  * @param type type of worker (GQuark)
364  * @param name name of option
365  * @param handler handler of option
366  * @param target opaque target structure
367  * @param offset offset inside a structure
368  */
369 void rspamd_rcl_register_worker_option (struct rspamd_config *cfg,
370 		GQuark type,
371 		const gchar *name,
372 		rspamd_rcl_default_handler_t handler,
373 		gpointer target,
374 		glong offset,
375 		gint flags,
376 		const gchar *doc_string);
377 
378 /**
379  * Register a default parser for a worker
380  * @param cfg config structure
381  * @param type type of worker (GQuark)
382  * @param func handler function
383  * @param ud userdata for handler function
384  */
385 void rspamd_rcl_register_worker_parser (struct rspamd_config *cfg, gint type,
386 	gboolean (*func)(ucl_object_t *, gpointer), gpointer ud);
387 
388 /**
389  * Adds new documentation object to the configuration
390  * @param doc_target target object where to insert documentation (top object is used if this is NULL)
391  * @param doc_object documentation object to insert
392  */
393 ucl_object_t *rspamd_rcl_add_doc_obj (ucl_object_t *doc_target,
394 		const char *doc_string,
395 		const char *doc_name,
396 		ucl_type_t type,
397 		rspamd_rcl_default_handler_t handler,
398 		gint flags,
399 		const char *default_value,
400 		gboolean required);
401 
402 /**
403  * Adds new documentation option specified by path `doc_path` that should be
404  * split by dots
405  */
406 ucl_object_t *rspamd_rcl_add_doc_by_path (struct rspamd_config *cfg,
407 		const gchar *doc_path,
408 		const char *doc_string,
409 		const char *doc_name,
410 		ucl_type_t type,
411 		rspamd_rcl_default_handler_t handler,
412 		gint flags,
413 		const char *default_value,
414 		gboolean required);
415 
416 
417 /**
418  * Parses example and adds documentation according to the example:
419  *
420  * ```
421  * section {
422  *   param1 = value; # explanation
423  *   param2 = value; # explanation
424  * }
425  * ```
426  *
427  * will produce the following documentation strings:
428  * section ->
429  *   section.param1 : explanation
430  *   section.param2 : explanation
431  *
432  * @param cfg
433  * @param root_path
434  * @param example_data
435  * @param example_len
436  * @return
437  */
438 ucl_object_t *rspamd_rcl_add_doc_by_example (struct rspamd_config *cfg,
439 		const gchar *root_path,
440 		const gchar *doc_string,
441 		const gchar *doc_name,
442 		const gchar *example_data, gsize example_len);
443 
444 /**
445  * Add lua modules path
446  * @param cfg
447  * @param path
448  * @param err
449  * @return
450  */
451 gboolean rspamd_rcl_add_lua_plugins_path (struct rspamd_config *cfg,
452 		const gchar *path,
453 		gboolean main_path,
454 		GHashTable *modules_seen,
455 		GError **err);
456 
457 
458 /**
459  * Calls for an external lua function to apply potential config transformations
460  * if needed. This function can change the cfg->rcl_obj.
461  *
462  * Example of transformation function:
463  *
464  * function(obj)
465  *   if obj.something == 'foo' then
466  *     obj.something = "bla"
467  *     return true, obj
468  *   end
469  *
470  *   return false, nil
471  * end
472  *
473  * If function returns 'false' then rcl_obj is not touched. Otherwise,
474  * it is changed, then rcl_obj is imported from lua. Old config is dereferenced.
475  * @param cfg
476  */
477 void rspamd_rcl_maybe_apply_lua_transform (struct rspamd_config *cfg);
478 void rspamd_rcl_section_free (gpointer p);
479 
480 void rspamd_config_calculate_cksum (struct rspamd_config *cfg);
481 
482 /*
483  * Read configuration file
484  */
485 gboolean rspamd_config_parse_ucl (struct rspamd_config *cfg,
486 								  const gchar *filename,
487 								  GHashTable *vars,
488 								  ucl_include_trace_func_t inc_trace,
489 								  void *trace_data,
490 								  gboolean skip_jinja,
491 								  GError **err);
492 gboolean rspamd_config_read (struct rspamd_config *cfg,
493 							 const gchar *filename,
494 							 rspamd_rcl_section_fin_t logger_fin,
495 							 gpointer logger_ud,
496 							 GHashTable *vars,
497 							 gboolean skip_jinja,
498 							 gchar **lua_env);
499 
500 #ifdef  __cplusplus
501 }
502 #endif
503 
504 #endif /* CFG_RCL_H_ */
505