The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
dependency.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: 2c9af55db2d575a91d8388066c875be03ab530a9 $
19  * @file src/lib/server/dependency.c
20  * @brief Check version numbers of dependencies.
21  *
22  * @copyright 1999-2014 The FreeRADIUS server project
23  * @copyright 2012 Alan DeKok (aland@freeradius.org)
24  * @copyright 2000 Chris Parker (cparker@starnetusa.com)
25  */
26 
27 RCSID("$Id: 2c9af55db2d575a91d8388066c875be03ab530a9 $")
28 
29 #include <freeradius-devel/server/base.h>
30 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
31 
32 static uint64_t libmagic = RADIUSD_MAGIC_NUMBER;
33 char const *radiusd_version_short = STRINGIFY(RADIUSD_VERSION_MAJOR) "." STRINGIFY(RADIUSD_VERSION_MINOR) "." STRINGIFY(RADIUSD_VERSION_INCRM);
34 
35 static CONF_SECTION *default_feature_cs; //!< Default configuration section to add features to.
36 static CONF_SECTION *default_version_cs; //!< Default configuration section to add features to.
37 
38 #include <freeradius-devel/tls/openssl_user_macros.h>
39 
40 #ifdef WITH_TLS
41 # include <freeradius-devel/tls/version.h>
42 # include <openssl/crypto.h>
43 # include <openssl/opensslv.h>
44 # include <openssl/engine.h>
45 #endif
46 
47 #ifdef HAVE_GPERFTOOLS_PROFILER_H
48 # include <gperftools/profiler.h>
49 #endif
50 
51 #ifdef HAVE_VALGRIND_H
52 # include <valgrind.h>
53 #endif
54 
55 /** Check if the application linking to the library has the correct magic number
56  *
57  * @param magic number as defined by RADIUSD_MAGIC_NUMBER
58  * @returns
59  * - 0 on success.
60  * - -1 on prefix mismatch.
61  * - -2 on version mismatch.
62  * - -3 on commit mismatch.
63  */
64 int rad_check_lib_magic(uint64_t magic)
65 {
66  if (MAGIC_PREFIX(magic) != MAGIC_PREFIX(libmagic)) {
67  ERROR("Application and libfreeradius-server magic number (prefix) mismatch."
68  " application: %x library: %x",
70  return -1;
71  }
72 
73  if (MAGIC_VERSION(magic) != MAGIC_VERSION(libmagic)) {
74  ERROR("Application and libfreeradius-server magic number (version) mismatch."
75  " application: %lx library: %lx",
76  (unsigned long) MAGIC_VERSION(magic), (unsigned long) MAGIC_VERSION(libmagic));
77  return -2;
78  }
79 
80  if (MAGIC_COMMIT(magic) != MAGIC_COMMIT(libmagic)) {
81  ERROR("Application and libfreeradius-server magic number (commit) mismatch."
82  " application: %lx library: %lx",
83  (unsigned long) MAGIC_COMMIT(magic), (unsigned long) MAGIC_COMMIT(libmagic));
84  return -3;
85  }
86 
87  return 0;
88 }
89 
90 /** Add a feature flag to the main configuration
91  *
92  * Add a feature flag (yes/no) to the 'feature' subsection
93  * off the main config.
94  *
95  * This allows the user to create configurations that work with
96  * across multiple environments.
97  *
98  * @param[in] cs to add feature pair to. May be NULL
99  * in which case the cs passed to
100  * dependency_feature_init() is used.
101  * @param[in] name of feature.
102  * @param[in] enabled Whether the feature is present/enabled.
103  * @return
104  * - 0 on success.
105  * - -1 on failure.
106  */
107 int dependency_feature_add(CONF_SECTION *cs, char const *name, bool enabled)
108 {
109  if (!cs) cs = default_feature_cs;
110  if (!fr_cond_assert_msg(cs, "dependency_features_init() must be called before calling %s", __FUNCTION__)) {
111  return -1;
112  }
113 
114  if (!cf_pair_find(cs, name)) {
115  CONF_PAIR *cp;
116 
117  cp = cf_pair_alloc(cs, name, enabled ? "yes" : "no",
119  if (!cp) return -1;
120  }
121 
122  return 0;
123 }
124 
125 /** Add a library/server version pair to the main configuration
126  *
127  * Add a version number to the 'version' subsection off the main
128  * config.
129  *
130  * Because of the optimisations in the configuration parser, these
131  * may be checked using regular expressions without a performance
132  * penalty.
133  *
134  * The version pairs are there primarily to work around defects
135  * in libraries or the server.
136  *
137  * @param[in] cs to add feature pair to. May be NULL
138  * in which case the cs passed to
139  * dependency_feature_init() is used.
140  * @param[in] name of library or feature.
141  * @param[in] version Humanly readable version text.
142  * @return
143  * - 0 on success.
144  * - -1 on failure.
145  */
146 int dependency_version_number_add(CONF_SECTION *cs, char const *name, char const *version)
147 {
148  CONF_PAIR *old;
149 
150  if (!cs) cs = default_version_cs;
151  if (!fr_cond_assert_msg(cs, "dependency_version_numbers_init() must be called before calling %s", __FUNCTION__)) {
152  return -1;
153  }
154 
155  old = cf_pair_find(cs, name);
156  if (!old) {
157  CONF_PAIR *cp;
158 
160  if (!cp) return -1;
161 
162  } else {
163  WARN("Replacing user version.%s (%s) with %s", name, cf_pair_value(old), version);
164 
165  cf_pair_replace(cs, old, version);
166  }
167 
168  return 0;
169 }
170 
171 
172 /** Initialise core feature flags
173  *
174  * @param cs Where to add the CONF_PAIRS, if null pairs will be added
175  * to the 'feature' section of the main config.
176  */
178 {
179  default_feature_cs = cs;
180 
181  dependency_feature_add(cs, "cap",
182 #ifdef HAVE_CAPABILITY_H
183  true
184 #else
185  false
186 #endif
187  );
188 
189  dependency_feature_add(cs, "regex-pcre",
190 #ifdef HAVE_REGEX_PCRE
191  true
192 #else
193  false
194 #endif
195  );
196 
197  dependency_feature_add(cs, "regex-pcre2",
198 #ifdef HAVE_REGEX_PCRE2
199  true
200 #else
201  false
202 #endif
203  );
204 
205 #ifdef HAVE_REGEX_POSIX
206  dependency_feature_add(cs, "regex-posix", true);
207  dependency_feature_add(cs, "regex-posix-extended",
208 # ifdef HAVE_REG_EXTENDED
209  true
210 # else
211  false
212 # endif
213  );
214 #else
215  dependency_feature_add(cs, "regex-posix", false);
216  dependency_feature_add(cs, "regex-posix-extended", false);
217 #endif
218 
219  dependency_feature_add(cs, "regex-binsafe",
220 #if defined(HAVE_REGNEXEC) || defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2)
221  true
222 #else
223  false
224 #endif
225  );
226 
227  dependency_feature_add(cs, "stats",
228 #ifdef WITH_STATS
229  true
230 #else
231  false
232 #endif
233  );
234 
235  dependency_feature_add(cs, "systemd",
236 #ifdef HAVE_SYSTEMD
237  true
238 #else
239  false
240 #endif
241  );
242 
243  dependency_feature_add(cs, "tls",
244 #ifdef WITH_TLS
245  true
246 #else
247  false
248 #endif
249  );
250 
251  dependency_feature_add(cs, "socket-timestamps",
252 #ifdef SO_TIMESTAMP
253  true
254 #else
255  false
256 #endif
257  );
258 
259  dependency_feature_add(cs, "developer",
260 #ifndef NDEBUG
261  true
262 #else
263  false
264 #endif
265  );
266 
267  dependency_feature_add(cs, "address-sanitizer",
268 #ifdef __SANITIZE_ADDRESS__
269  true
270 #else
271  false
272 #endif
273  );
274 
275 #ifdef HAVE_SANITIZER_COMMON_INTERFACE_DEFS_H
276  /*
277  * Are we running under Leak Sanitizer
278  */
279  dependency_feature_add(cs, "runtime-lsan", (fr_get_lsan_state() == 1));
280 #endif
281 
282 #ifdef HAVE_GPERFTOOLS_PROFILER_H
283  {
284  struct ProfilerState state;
285 
286  ProfilerGetCurrentState(&state);
287  /*
288  * Were we build with gperftools support,
289  * and is it currently enabled.
290  */
291  dependency_feature_add(cs, "runtime-gperftools", state.enabled);
292  }
293 #endif
294 
295 #ifdef HAVE_VALGRIND_H
296  /*
297  * Are we running under valgrind
298  */
299  dependency_feature_add(cs, "runtime-valgrind", RUNNING_ON_VALGRIND);
300 #endif
301 
302  /*
303  * Are we running under a debugger
304  */
305  dependency_feature_add(cs, "runtime-debugger", (fr_get_debug_state() == 1));
306 }
307 
308 #ifdef EVFILT_LIBKQUEUE
309 static void dependency_libqueue_version(CONF_SECTION *cs)
310 {
311  int kqfd, ret;
312  struct kevent kev, receipt;
313 
314  kqfd = kqueue();
315  if (kqfd < 0) {
316  kqueue_error:
317  dependency_version_number_add(cs, "libkqueue", fr_syserror(errno));
318  return;
319  }
320 
321  EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_VERSION_STR, 0, NULL);
322  ret = kevent(kqfd, &kev, 1, &receipt, 1, &(struct timespec){});
323  close(kqfd);
324  if (ret != 1) goto kqueue_error;
325 
326  dependency_version_number_add(cs, "libkqueue", (char *)receipt.udata);
327 }
328 #endif
329 
330 /** Initialise core version flags
331  *
332  * @param cs Where to add the CONF_PAIRS, if null pairs will be added
333  * to the 'version' section of the main config.
334  */
336 {
337  char buffer[128];
338 
339  default_version_cs = cs;
340 
341  dependency_version_number_add(cs, "freeradius-server", radiusd_version_short);
342 
343  snprintf(buffer, sizeof(buffer), "%i.%i.*", talloc_version_major(), talloc_version_minor());
344  dependency_version_number_add(cs, "talloc", buffer);
345 
346 #ifdef WITH_TLS
348 #endif
349 
350 #ifdef HAVE_REGEX
351 # ifdef HAVE_REGEX_PCRE2
352  snprintf(buffer, sizeof(buffer), "%i.%i (%s) - retrieved at build time", PCRE2_MAJOR, PCRE2_MINOR, STRINGIFY(PCRE2_DATE));
354 # elif defined(HAVE_REGEX_PCRE)
355  dependency_version_number_add(cs, "pcre", pcre_version());
356 # endif
357 #endif
358 
359 #ifdef EVFILT_LIBKQUEUE
360  dependency_libqueue_version(cs);
361 #endif
362 }
363 
364 static char const *spaces = " "; /* 40 */
365 
366 /*
367  * Display the revision number for this program
368  */
370 {
371  CONF_SECTION *features, *versions;
372  CONF_ITEM *ci;
373  CONF_PAIR *cp;
374 
375  if (DEBUG_ENABLED3) {
376 #if defined(WITH_TLS) && (OPENSSL_VERSION_NUMBER < 0x30000000L)
377  ENGINE *engine;
378  char const *engine_id;
379 #endif
380  int max = 0, len;
381 
382  MEM(features = cf_section_alloc(NULL, NULL, "feature", NULL));
383  dependency_features_init(features);
384 
385  MEM(versions = cf_section_alloc(NULL, NULL, "version", NULL));
387 
388  DEBUG2("Server was built with:");
389 
390  for (ci = cf_item_next(features, NULL);
391  ci;
392  ci = cf_item_next(features, ci)) {
393  len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
394  if (max < len) max = len;
395  }
396 
397  for (ci = cf_item_next(versions, NULL);
398  ci;
399  ci = cf_item_next(versions, ci)) {
400  len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
401  if (max < len) max = len;
402  }
403 
404 #if defined(WITH_TLS) && (OPENSSL_VERSION_NUMBER < 0x30000000L)
405  for (engine = ENGINE_get_first();
406  engine;
407  engine = ENGINE_get_next(engine)) {
408  len = strlen(ENGINE_get_id(engine) + 1);
409  if (max < len) max = len;
410  }
411 #endif
412 
413  for (ci = cf_item_next(features, NULL);
414  ci;
415  ci = cf_item_next(features, ci)) {
416  char const *attr;
417 
418  cp = cf_item_to_pair(ci);
419  attr = cf_pair_attr(cp);
420 
421  DEBUG2(" %s%.*s : %s", attr,
422  (int)(max - talloc_array_length(attr)), spaces, cf_pair_value(cp));
423  }
424 
425  DEBUG2("Server core libs:");
426 
427  for (ci = cf_item_next(versions, NULL);
428  ci;
429  ci = cf_item_next(versions, ci)) {
430  char const *attr;
431 
432  cp = cf_item_to_pair(ci);
433  attr = cf_pair_attr(cp);
434 
435  DEBUG2(" %s%.*s : %s", attr,
436  (int)(max - talloc_array_length(attr)), spaces, cf_pair_value(cp));
437  }
438 
439  talloc_free(features);
440  talloc_free(versions);
441 
442 #if defined(WITH_TLS) && (OPENSSL_VERSION_NUMBER < 0x30000000L)
443  DEBUG3("OpenSSL engines:");
444  for (engine = ENGINE_get_first();
445  engine;
446  engine = ENGINE_get_next(engine)) {
447  engine_id = ENGINE_get_id(engine);
448 
449  DEBUG3(" %s%.*s : %s", engine_id, (int)(max - (strlen(engine_id) + 1)), spaces,
450  ENGINE_get_name(engine));
451  }
452 #endif
453 
454  DEBUG2("Endianness:");
455 #ifdef WORDS_BIGENDIAN
456  DEBUG2(" big");
457 #else
458  DEBUG2(" little");
459 #endif
460 
461  DEBUG2("Compilation flags:");
462 #ifdef BUILT_WITH_CPPFLAGS
463  DEBUG2(" cppflags : " BUILT_WITH_CPPFLAGS);
464 #endif
465 #ifdef BUILT_WITH_CFLAGS
466  DEBUG2(" cflags : " BUILT_WITH_CFLAGS);
467 #endif
468 #ifdef BUILT_WITH_LDFLAGS
469  DEBUG2(" ldflags : " BUILT_WITH_LDFLAGS);
470 #endif
471 #ifdef BUILT_WITH_LIBS
472  DEBUG2(" libs : " BUILT_WITH_LIBS);
473 #endif
474  DEBUG2(" ");
475  }
476  INFO("Copyright 1999-2024 The FreeRADIUS server project and contributors");
477  INFO("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A");
478  INFO("PARTICULAR PURPOSE");
479  INFO("You may redistribute copies of FreeRADIUS under the terms of the");
480  INFO("GNU General Public License");
481  INFO("For more information about these matters, see the file named COPYRIGHT");
482 
483  fflush(NULL);
484 }
static int const char char buffer[256]
Definition: acutest.h:574
#define USES_APPLE_DEPRECATED_API
Definition: build.h:431
#define RCSID(id)
Definition: build.h:444
#define STRINGIFY(x)
Definition: build.h:195
Common header for all CONF_* types.
Definition: cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:629
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition: cf_util.c:1495
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition: cf_util.c:1356
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1511
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
Replace pair in a given section with a new pair, of the given value.
Definition: cf_util.c:1290
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition: cf_util.c:1220
#define cf_item_next(_ci, _prev)
Definition: cf_util.h:92
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition: cf_util.h:137
int fr_get_lsan_state(void)
Definition: debug.c:261
int fr_get_debug_state(void)
Definition: debug.c:492
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:154
void dependency_version_print(void)
Definition: dependency.c:369
void dependency_features_init(CONF_SECTION *cs)
Initialise core feature flags.
Definition: dependency.c:177
int rad_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition: dependency.c:64
static USES_APPLE_DEPRECATED_API uint64_t libmagic
Definition: dependency.c:32
char const * radiusd_version_short
Definition: dependency.c:33
void dependency_version_numbers_init(CONF_SECTION *cs)
Initialise core version flags.
Definition: dependency.c:335
int dependency_feature_add(CONF_SECTION *cs, char const *name, bool enabled)
Add a feature flag to the main configuration.
Definition: dependency.c:107
int dependency_version_number_add(CONF_SECTION *cs, char const *name, char const *version)
Add a library/server version pair to the main configuration.
Definition: dependency.c:146
static CONF_SECTION * default_feature_cs
Default configuration section to add features to.
Definition: dependency.c:35
static char const * spaces
Definition: dependency.c:364
static CONF_SECTION * default_version_cs
Default configuration section to add features to.
Definition: dependency.c:36
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define RUNNING_ON_VALGRIND
Definition: dl.c:40
#define DEBUG3(_fmt,...)
Definition: log.h:266
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition: log.h:259
talloc_free(reap)
#define DEBUG2(fmt,...)
Definition: radclient.h:43
#define WARN(fmt,...)
Definition: radclient.h:47
#define INFO(fmt,...)
Definition: radict.c:54
static char const * name
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:689
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
char const * fr_openssl_version_basic(void)
Definition: version.c:329
@ T_SINGLE_QUOTED_STRING
Definition: token.h:122
@ T_BARE_WORD
Definition: token.h:120
@ T_OP_EQ
Definition: token.h:83
close(uq->fd)
#define MAGIC_PREFIX(_x)
Definition: version.h:82
#define MAGIC_VERSION(_x)
Definition: version.h:83
#define MAGIC_COMMIT(_x)
Definition: version.h:84
#define RADIUSD_MAGIC_NUMBER
Definition: version.h:81