The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
global_lib.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /*
18  * $Id: 1eb22d8b3c1a8ec9520730c37dbd24dbec9fe0d5 $
19  *
20  * @file global_lib.c
21  * @brief Handle global configuration, initialisation and freeing for libraries
22  *
23  * @copyright 2022 The FreeRADIUS server project
24  */
25 #include <freeradius-devel/server/global_lib.h>
26 #include <freeradius-devel/server/main_config.h>
27 #include <freeradius-devel/util/atexit.h>
28 
29 /*
30  * Terminator for array of global_lib_autoinst_t
31  */
33 
34 /*
35  * Global list of libraries
36  */
37 typedef struct {
40 
42 
43 /** Structure to track use of libraries.
44  *
45  */
46 typedef struct {
47  fr_rb_node_t entry; //!< Entry in tree of libraries
48  global_lib_autoinst_t const *autoinit; //!< Autoinit structure used to manage this library
49  uint32_t instance_count; //!< Number of current uses of this library
50  bool initialised; //!< Has the init callback been run for this library
52 
53 /** Parse the global config section for a library and call its init function
54  *
55  * @param[in] lib to configure and initialise
56  * @return
57  * - 0 on success
58  * - -1 on failure
59  */
61 {
62  CONF_SECTION *global_cs, *cs;
63 
64  /*
65  * Find relevant config section
66  * If the section does not exist allocate an empty one
67  * so default rules can be evaluated.
68  */
69  global_cs = cf_section_find(cf_root(main_config->root_cs), "global", NULL);
70  if (!global_cs) global_cs = cf_section_alloc(main_config->root_cs, main_config->root_cs, "global", NULL);
71 
72  cs = cf_section_find(global_cs, lib->autoinit->name, NULL);
73  if (!cs) cs = cf_section_alloc(global_cs, global_cs, lib->autoinit->name, NULL);
74 
75  if ((cf_section_rules_push(cs, lib->autoinit->config)) < 0 ||
76  (cf_section_parse(lib, lib->autoinit->inst, cs) < 0)) {
77  cf_log_err(cs, "Failed evaluating configuration for libldap");
78  return -1;
79  }
80 
81  /*
82  * Call the init callback if defined
83  */
84  if (lib->autoinit->init && (lib->autoinit->init()) < 0) return -1;
85 
86  lib->initialised = true;
87 
88  return 0;
89 }
90 
91 /** Instantiate a list of libraries
92  *
93  * @param to_init Array of autoinit structures detailing libraries to initialise
94  * @return
95  * - 0 on success
96  * - -1 on failure
97  */
98 static int lib_auto_instantiate(global_lib_autoinst_t * const *to_init)
99 {
100  global_lib_autoinst_t * const *p;
101 
102  for (p = to_init; *p != &global_lib_terminator; p++) {
103  global_lib_inst_t *lib = NULL;
104 
105  lib = fr_rb_find(&lib_list->libs, &(global_lib_inst_t){ .autoinit = *p });
106 
107  /*
108  * If the library is already initialised, just increase the reference count
109  */
110  if ((lib) && (lib->initialised)) {
111  lib->instance_count++;
112  return 0;
113  }
114 
115  if (!lib) {
116  MEM(lib = talloc_zero(lib_list, global_lib_inst_t));
117  lib->autoinit = *p;
118  fr_rb_insert(&lib_list->libs, lib);
119  }
120  lib->instance_count++;
121 
122  /*
123  * If the main config parsing is not complete we can't initialise the library yet
124  */
125  if (!main_config->root_cs) continue;
126 
127  DEBUG2("Instantiating %s", lib->autoinit->name);
128  if (lib_init_call(lib) < 0) return -1;
129  }
130 
131  return 0;
132 }
133 
134 /** Callback for creation of "lib" symbols
135  *
136  */
137 int global_lib_auto_instantiate(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
138 {
139  if (lib_auto_instantiate((global_lib_autoinst_t **)symbol) < 0) return -1;
140 
141  return 0;
142 }
143 
144 /** Run free callbacks for external libraries no-longer in use
145  *
146  * @param[in] to_free Array of autoinit structures detailing libraries to free
147  */
148 static void lib_autofree(global_lib_autoinst_t * const *to_free)
149 {
150  global_lib_autoinst_t * const *p;
151 
152  for (p = to_free; *p != &global_lib_terminator; p++) {
153  global_lib_inst_t *lib = NULL;
154 
155  lib = fr_rb_find(&lib_list->libs, &(global_lib_inst_t){ .autoinit = *p });
156 
157  fr_assert_msg(lib, "Library %s already freed", (*p)->name);
158 
159  if (--lib->instance_count > 0) return;
160 
161  /*
162  * Only run the free callback if the library was successfully initialised
163  */
164  if (lib->initialised && ((*p)->free)) (*p)->free();
165 
166  fr_rb_remove(&lib_list->libs, lib);
167  talloc_free(lib);
168  }
169 }
170 
171 /** Callback for freeing of "lib" symbols
172  *
173  */
174 void global_lib_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
175 {
177 }
178 
179 /** Compare two fr_lib_t
180  *
181  */
182 static int8_t _lib_cmp(void const *one, void const *two)
183 {
184  global_lib_inst_t const *a = one;
185  global_lib_inst_t const *b = two;
186 
187  return CMP(a->autoinit, b->autoinit);
188 }
189 
190 /** Free global list of libraries
191  *
192  * Called as an atexit function
193  */
195 {
196  if (talloc_free(lib_list) < 0) return -1;
197  lib_list = NULL;
198  return 0;
199 }
200 
201 /** Initialise the global list of external libraries
202  *
203  */
205 {
206  if (lib_list) return 0;
207 
208  MEM(lib_list = talloc_zero(NULL, global_lib_list_t));
210 
212  return 0;
213 }
214 
215 /** Walk the tree of libraries and instantiate any which are pending
216  *
217  */
219 {
220  /*
221  * Must be called after main config has been parsed
222  */
224 
225  DEBUG2("#### Instantiating libraries ####");
227  if (lib->initialised) continue;
228 
229  DEBUG2("Instantiating %s", lib->autoinit->name);
230  if (lib_init_call(lib) < 0) return -1;
231 
232  }
233  endforeach
234  return 0;
235 }
#define fr_atexit_global(_func, _uctx)
Add a free function to the global free list.
Definition: atexit.h:59
#define endforeach
Definition: build.h:491
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define UNUSED
Definition: build.h:313
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition: cf_parse.c:985
#define cf_section_rules_push(_cs, _rule)
Definition: cf_parse.h:659
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:1028
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:289
#define cf_root(_cf)
Definition: cf_util.h:98
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition: cf_util.h:140
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:210
Module handle.
Definition: dl.h:58
fr_rb_tree_t libs
Definition: global_lib.c:38
fr_rb_node_t entry
Entry in tree of libraries.
Definition: global_lib.c:47
static void lib_autofree(global_lib_autoinst_t *const *to_free)
Run free callbacks for external libraries no-longer in use.
Definition: global_lib.c:148
int global_lib_init(void)
Initialise the global list of external libraries.
Definition: global_lib.c:204
static int _lib_list_free_atexit(UNUSED void *uctx)
Free global list of libraries.
Definition: global_lib.c:194
bool initialised
Has the init callback been run for this library.
Definition: global_lib.c:50
static int lib_auto_instantiate(global_lib_autoinst_t *const *to_init)
Instantiate a list of libraries.
Definition: global_lib.c:98
uint32_t instance_count
Number of current uses of this library.
Definition: global_lib.c:49
static global_lib_list_t * lib_list
Definition: global_lib.c:41
void global_lib_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback for freeing of "lib" symbols.
Definition: global_lib.c:174
int global_lib_auto_instantiate(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback for creation of "lib" symbols.
Definition: global_lib.c:137
global_lib_autoinst_t const global_lib_terminator
Definition: global_lib.c:32
global_lib_autoinst_t const * autoinit
Autoinit structure used to manage this library.
Definition: global_lib.c:48
int global_lib_instantiate(void)
Walk the tree of libraries and instantiate any which are pending.
Definition: global_lib.c:218
static int lib_init_call(global_lib_inst_t *lib)
Parse the global config section for a library and call its init function.
Definition: global_lib.c:60
static int8_t _lib_cmp(void const *one, void const *two)
Compare two fr_lib_t.
Definition: global_lib.c:182
Structure to track use of libraries.
Definition: global_lib.c:46
conf_parser_t const * config
Config parser for this library's global options.
Definition: global_lib.h:40
char const * name
Name of library and section within global config.
Definition: global_lib.h:39
lib_init_t init
Callback to initialise library.
Definition: global_lib.h:42
void * inst
Module data to parse global config into.
Definition: global_lib.h:41
Structure to define how to initialise libraries with global configuration.
Definition: global_lib.h:38
talloc_free(reap)
main_config_t const * main_config
Main server configuration.
Definition: main_config.c:69
CONF_SECTION * root_cs
Root of the server config.
Definition: main_config.h:55
unsigned int uint32_t
Definition: merged_model.c:33
#define DEBUG2(fmt,...)
Definition: radclient.h:43
void * fr_rb_remove(fr_rb_tree_t *tree, void const *data)
#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free)
Initialises a red black tree.
Definition: rb.h:180
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
#define fr_rb_inorder_foreach(_tree, _type, _iter)
Definition: rb.h:333
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
The main red black tree structure.
Definition: rb.h:73
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)