aboutsummaryrefslogtreecommitdiffstats
path: root/src/libserver/cfg_rcl.h
blob: e33656b72ee6eadab8083e5b635b7bd2890a478b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
/*
 * Copyright 2023 Vsevolod Stakhov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef CFG_RCL_H_
#define CFG_RCL_H_

#include "config.h"
#include "cfg_file.h"
#include "ucl.h"
#include "mem_pool.h"

#define CFG_RCL_ERROR cfg_rcl_error_quark()
static inline GQuark
cfg_rcl_error_quark(void)
{
	return g_quark_from_static_string("cfg-rcl-error-quark");
}

#ifdef __cplusplus
extern "C" {
#endif

struct rspamd_rcl_section;
struct rspamd_rcl_sections_map;
struct rspamd_config;
struct rspamd_rcl_default_handler_data;

enum rspamd_rcl_flag {
	RSPAMD_CL_FLAG_TIME_FLOAT = 0x1 << 0,
	RSPAMD_CL_FLAG_TIME_TIMEVAL = 0x1 << 1,
	RSPAMD_CL_FLAG_TIME_TIMESPEC = 0x1 << 2,
	RSPAMD_CL_FLAG_TIME_INTEGER = 0x1 << 3,
	RSPAMD_CL_FLAG_TIME_UINT_32 = 0x1 << 4,
	RSPAMD_CL_FLAG_INT_16 = 0x1 << 5,
	RSPAMD_CL_FLAG_INT_32 = 0x1 << 6,
	RSPAMD_CL_FLAG_INT_64 = 0x1 << 7,
	RSPAMD_CL_FLAG_UINT = 0x1 << 8,
	RSPAMD_CL_FLAG_INT_SIZE = 0x1 << 9,
	RSPAMD_CL_FLAG_STRING_PATH = 0x1 << 10,
	RSPAMD_CL_FLAG_BOOLEAN_INVERSE = 0x1 << 11,
	RSPAMD_CL_FLAG_STRING_LIST_HASH = 0x1 << 12,
	RSPAMD_CL_FLAG_MULTIPLE = 0x1 << 13,
	RSPAMD_CL_FLAG_SIGNKEY = 0x1 << 14,
	RSPAMD_CL_FLAG_NISTKEY = 0x1 << 15,
};

struct rspamd_rcl_struct_parser {
	struct rspamd_config *cfg;
	gpointer user_struct;
	goffset offset;
	int flags; /* enum rspamd_rcl_flag */
};


/**
 * Common handler type
 * @param cfg configuration
 * @param obj object to parse
 * @param ud user data (depends on section)
 * @param err error object
 * @return TRUE if a section has been parsed
 */
typedef gboolean (*rspamd_rcl_handler_t)(rspamd_mempool_t *pool,
										 const ucl_object_t *obj,
										 const char *key,
										 gpointer ud,
										 struct rspamd_rcl_section *section,
										 GError **err);

typedef gboolean (*rspamd_rcl_default_handler_t)(rspamd_mempool_t *pool,
												 const ucl_object_t *obj,
												 gpointer ud,
												 struct rspamd_rcl_section *section,
												 GError **err);

/**
 * A handler type that is called at the end of section parsing
 * @param cfg configuration
 * @param ud user data
 */
typedef void (*rspamd_rcl_section_fin_t)(rspamd_mempool_t *pool, gpointer ud);

/**
 * Add a default handler for a section
 * @param section section pointer
 * @param name name of param
 * @param handler handler of param
 * @param offset offset in a structure
 * @param flags flags for the parser
 * @return newly created structure
 */
struct rspamd_rcl_default_handler_data *rspamd_rcl_add_default_handler(
	struct rspamd_rcl_section *section,
	const char *name,
	rspamd_rcl_default_handler_t handler,
	goffset offset,
	int flags,
	const char *doc_string);

/**
 * Add new section to the configuration
 * @param top top section
 * @param name the name of the section
 * @param key_attr name of the attribute that should be used as key attribute
 * @param handler handler function for all attributes
 * @param type type of object handled by a handler
 * @param required whether at least one of these sections is required
 * @param strict_type turn on strict check for types for this section
 * @return newly created structure
 */
struct rspamd_rcl_section *rspamd_rcl_add_section(
	struct rspamd_rcl_sections_map **top,
	struct rspamd_rcl_section *parent_section,
	const char *name,
	const char *key_attr,
	rspamd_rcl_handler_t handler,
	enum ucl_type type,
	gboolean required,
	gboolean strict_type);

struct rspamd_rcl_section *rspamd_rcl_add_section_doc(
	struct rspamd_rcl_sections_map **top,
	struct rspamd_rcl_section *parent_section,
	const char *name, const char *key_attr,
	rspamd_rcl_handler_t handler,
	enum ucl_type type, gboolean required,
	gboolean strict_type,
	ucl_object_t *doc_target,
	const char *doc_string);

/**
 * Init common sections known to rspamd
 * @return top section
 */
struct rspamd_rcl_sections_map *rspamd_rcl_config_init(struct rspamd_config *cfg,
													   GHashTable *skip_sections);

/**
 * Parse configuration
 * @param top top section
 * @param cfg rspamd configuration
 * @param ptr pointer to the target
 * @param pool pool object
 * @param obj ucl object to parse
 * @param err error pointer
 * @return
 */
gboolean rspamd_rcl_parse(struct rspamd_rcl_sections_map *top,
						  struct rspamd_config *cfg,
						  gpointer ptr, rspamd_mempool_t *pool,
						  const ucl_object_t *obj, GError **err);

/**
 * Here is a section of common handlers that accepts rcl_struct_parser
 * which itself contains a struct pointer and the offset of a member in a
 * specific structure
 */

/**
 * Parse a string field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a string value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_string(rspamd_mempool_t *pool,
										const ucl_object_t *obj,
										gpointer ud,
										struct rspamd_rcl_section *section,
										GError **err);

/**
 * Parse an integer field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_integer(rspamd_mempool_t *pool,
										 const ucl_object_t *obj,
										 gpointer ud,
										 struct rspamd_rcl_section *section,
										 GError **err);


/**
 * Parse a float field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_double(rspamd_mempool_t *pool,
										const ucl_object_t *obj,
										gpointer ud,
										struct rspamd_rcl_section *section,
										GError **err);

/**
 * Parse a time field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure (flags mean the exact structure used)
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_time(rspamd_mempool_t *pool,
									  const ucl_object_t *obj,
									  gpointer ud,
									  struct rspamd_rcl_section *section,
									  GError **err);

/**
 * Parse a string list field of a structure presented by a GList* object
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure (flags mean the exact structure used)
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_string_list(rspamd_mempool_t *pool,
											 const ucl_object_t *obj,
											 gpointer ud,
											 struct rspamd_rcl_section *section,
											 GError **err);

/**
 * Parse a boolean field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure (flags mean the exact structure used)
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_boolean(rspamd_mempool_t *pool,
										 const ucl_object_t *obj,
										 gpointer ud,
										 struct rspamd_rcl_section *section,
										 GError **err);

/**
 * Parse a keypair field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure (flags mean the exact structure used)
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_keypair(rspamd_mempool_t *pool,
										 const ucl_object_t *obj,
										 gpointer ud,
										 struct rspamd_rcl_section *section,
										 GError **err);

/**
 * Parse a pubkey field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure (flags mean the exact structure used)
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_pubkey(rspamd_mempool_t *pool,
										const ucl_object_t *obj,
										gpointer ud,
										struct rspamd_rcl_section *section,
										GError **err);

/**
 * Parse a inet addr field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure (flags mean the exact structure used)
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_addr(rspamd_mempool_t *pool,
									  const ucl_object_t *obj,
									  gpointer ud,
									  struct rspamd_rcl_section *section,
									  GError **err);

/**
 * Parse a gmime inet address field of a structure
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure (flags mean the exact structure used)
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_mime_addr(rspamd_mempool_t *pool,
										   const ucl_object_t *obj,
										   gpointer ud,
										   struct rspamd_rcl_section *section,
										   GError **err);

/**
 * Parse a raw ucl object
 * @param cfg config pointer
 * @param obj object to parse
 * @param ud struct_parser structure (flags mean the exact structure used)
 * @param section the current section
 * @param err error pointer
 * @return TRUE if a value has been successfully parsed
 */
gboolean rspamd_rcl_parse_struct_ucl(rspamd_mempool_t *pool,
									 const ucl_object_t *obj,
									 gpointer ud,
									 struct rspamd_rcl_section *section,
									 GError **err);


/**
 * Utility functions
 */

/**
 * Register new parser for a worker type of an option with the specified name
 * @param cfg config structure
 * @param type type of worker (GQuark)
 * @param name name of option
 * @param handler handler of option
 * @param target opaque target structure, note it **MUST** be worker ctx due to some reasons I don't really remember
 * @param offset offset inside a structure
 */
void rspamd_rcl_register_worker_option(struct rspamd_config *cfg,
									   GQuark type,
									   const char *name,
									   rspamd_rcl_default_handler_t handler,
									   gpointer target,
									   glong offset,
									   int flags,
									   const char *doc_string);

/**
 * Adds new documentation object to the configuration
 * @param doc_target target object where to insert documentation (top object is used if this is NULL)
 * @param doc_object documentation object to insert
 */
ucl_object_t *rspamd_rcl_add_doc_obj(ucl_object_t *doc_target,
									 const char *doc_string,
									 const char *doc_name,
									 ucl_type_t type,
									 rspamd_rcl_default_handler_t handler,
									 int flags,
									 const char *default_value,
									 gboolean required);

/**
 * Adds new documentation option specified by path `doc_path` that should be
 * split by dots
 */
ucl_object_t *rspamd_rcl_add_doc_by_path(struct rspamd_config *cfg,
										 const char *doc_path,
										 const char *doc_string,
										 const char *doc_name,
										 ucl_type_t type,
										 rspamd_rcl_default_handler_t handler,
										 int flags,
										 const char *default_value,
										 gboolean required);


/**
 * Parses example and adds documentation according to the example:
 *
 * ```
 * section {
 *   param1 = value; # explanation
 *   param2 = value; # explanation
 * }
 * ```
 *
 * will produce the following documentation strings:
 * section ->
 *   section.param1 : explanation
 *   section.param2 : explanation
 *
 * @param cfg
 * @param root_path
 * @param example_data
 * @param example_len
 * @return
 */
ucl_object_t *rspamd_rcl_add_doc_by_example(struct rspamd_config *cfg,
											const char *root_path,
											const char *doc_string,
											const char *doc_name,
											const char *example_data, gsize example_len);

/**
 * Add lua modules path
 * @param cfg
 * @param path
 * @param err
 * @return
 */
gboolean rspamd_rcl_add_lua_plugins_path(struct rspamd_rcl_sections_map *sections,
										 struct rspamd_config *cfg,
										 const char *path,
										 gboolean main_path,
										 GError **err);


/**
 * Calls for an external lua function to apply potential config transformations
 * if needed. This function can change the cfg->rcl_obj.
 *
 * Example of transformation function:
 *
 * function(obj)
 *   if obj.something == 'foo' then
 *     obj.something = "bla"
 *     return true, obj
 *   end
 *
 *   return false, nil
 * end
 *
 * If function returns 'false' then rcl_obj is not touched. Otherwise,
 * it is changed, then rcl_obj is imported from lua. Old config is dereferenced.
 * @param cfg
 */
void rspamd_rcl_maybe_apply_lua_transform(struct rspamd_config *cfg);
void rspamd_rcl_sections_free(struct rspamd_rcl_sections_map *sections);

void rspamd_config_calculate_cksum(struct rspamd_config *cfg);

/*
 * Read configuration file
 */
gboolean rspamd_config_parse_ucl(struct rspamd_config *cfg,
								 const char *filename,
								 GHashTable *vars,
								 ucl_include_trace_func_t inc_trace,
								 void *trace_data,
								 gboolean skip_jinja,
								 GError **err);
gboolean rspamd_config_read(struct rspamd_config *cfg,
							const char *filename,
							rspamd_rcl_section_fin_t logger_fin,
							gpointer logger_ud,
							GHashTable *vars,
							gboolean skip_jinja,
							char **lua_env);

#ifdef __cplusplus
}
#endif

#endif /* CFG_RCL_H_ */