Expose core library versions and features in ${feature.*} and ${version.*}
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 5 Jan 2015 01:29:43 +0000 (20:29 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 5 Jan 2015 03:19:48 +0000 (22:19 -0500)
This is mainly needed so that the regex flavour is available for shipped policies, but can also be used for the canonical store of module dependency version numbers.

That in itself isn't useful for the server config, as we'd need some sort of 'pass2' for the config sections, but it is useful for querying via radmin.

src/include/radiusd.h
src/main/libfreeradius-server.mk
src/main/mainconfig.c
src/main/radiusd.c
src/main/radiusd.mk
src/main/unittest.c
src/main/version.c
src/main/xlat.c

index 8d3778d..a3970bd 100644 (file)
@@ -502,6 +502,7 @@ extern char const   *radlog_dir;
 extern char const      *radlib_dir;
 extern bool            log_stripped_names;
 extern char const      *radiusd_version;
+extern char const      *radiusd_version_short;
 void                   radius_signal_self(int flag);
 
 typedef enum {
@@ -624,9 +625,14 @@ void               pairlist_free(PAIR_LIST **);
 int            rad_check_lib_magic(uint64_t magic);
 int            ssl_check_consistency(void);
 char const     *ssl_version_by_num(uint32_t version);
+char const     *ssl_version_num(void);
 char const     *ssl_version_range(uint32_t low, uint32_t high);
 char const     *ssl_version(void);
-void           version(void);
+int            version_add_feature(CONF_SECTION *cs, char const *name, bool enabled);
+int            version_add_number(CONF_SECTION *cs, char const *name, char const *version);
+void           version_init_features(CONF_SECTION *cs);
+void           version_init_numbers(CONF_SECTION *cs);
+void           version_print(void);
 
 /* auth.c */
 char   *auth_name(char *buf, size_t buflen, REQUEST *request, bool do_cli);
index c40b1dd..7c43722 100644 (file)
@@ -10,5 +10,6 @@ SOURCES       :=      conffile.c \
                regex.c \
                tmpl.c \
                util.c \
+               version.c \
                pair.c \
                xlat.c
index 08a1eb8..5bd1a33 100644 (file)
@@ -702,7 +702,7 @@ char const *get_radius_dir(void)
 int main_config_init(void)
 {
        char const *p = NULL;
-       CONF_SECTION *cs;
+       CONF_SECTION *cs, *subcs;
        struct stat statbuf;
        cached_config_t *cc;
        char buffer[1024];
@@ -782,6 +782,38 @@ do {\
         */
        DICT_READ_OPTIONAL(radius_dir, RADIUS_DICTIONARY);
 
+       cs = cf_section_alloc(NULL, "main", NULL);
+       if (!cs) return -1;
+
+       /*
+        *      Add a 'feature' subsection off the main config
+        *      We check if it's defined first, as the user may
+        *      have defined their own feature flags, or want
+        *      to manually override the ones set by modules
+        *      or the server.
+        */
+       subcs = cf_section_sub_find(cs, "feature");
+       if (!subcs) {
+               subcs = cf_section_alloc(cs, "feature", NULL);
+               if (!subcs) return -1;
+
+               cf_section_add(cs, subcs);
+       }
+       version_init_features(subcs);
+
+       /*
+        *      Add a 'version' subsection off the main config
+        *      We check if it's defined first, this is for
+        *      backwards compatibility.
+        */
+       subcs = cf_section_sub_find(cs, "version");
+       if (!subcs) {
+               subcs = cf_section_alloc(cs, "version", NULL);
+               if (!subcs) return -1;
+               cf_section_add(cs, subcs);
+       }
+       version_init_numbers(subcs);
+
        /* Read the configuration file */
        snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
                 radius_dir, main_config.name);
index b8b0a55..1a2df8d 100644 (file)
@@ -311,11 +311,12 @@ int main(int argc, char *argv[])
                default_log.dst = L_DST_STDOUT;
                default_log.fd = STDOUT_FILENO;
 
-               version();
+               INFO("%s: %s", progname, radiusd_version);
+               version_print();
                exit(EXIT_SUCCESS);
        }
 
-       if (debug_flag) version();
+       if (debug_flag) version_print();
 
        /*
         *  Under linux CAP_SYS_PTRACE is usually only available before setuid/setguid,
index 1ff95a4..15f856c 100644 (file)
@@ -2,7 +2,7 @@ TARGET  := radiusd
 SOURCES := acct.c auth.c client.c crypt.c files.c \
                  listen.c  mainconfig.c modules.c modcall.c \
                  radiusd.c state.c stats.c soh.c connection.c \
-                 session.c threads.c version.c  \
+                 session.c threads.c \
                  process.c realms.c detail.c
 ifneq ($(OPENSSL_LIBS),)
 SOURCES        += cb.c tls.c tls_listen.c
index ffcf713..906ac6d 100644 (file)
@@ -612,9 +612,7 @@ int main(int argc, char *argv[])
                }
        }
 
-       if (debug_flag) {
-               version();
-       }
+       if (debug_flag) version_print();
        fr_debug_flag = debug_flag;
 
        /*
index d476443..21f06f1 100644 (file)
@@ -27,7 +27,8 @@ RCSID("$Id$")
 #include <freeradius-devel/radiusd.h>
 USES_APPLE_DEPRECATED_API      /* OpenSSL API has been deprecated by Apple */
 
-static uint64_t libmagic = RADIUSD_MAGIC_NUMBER;
+static uint64_t        libmagic = RADIUSD_MAGIC_NUMBER;
+char const     *radiusd_version_short = RADIUSD_VERSION_STRING;
 
 #ifdef HAVE_OPENSSL_CRYPTO_H
 #  include <openssl/crypto.h>
@@ -123,6 +124,18 @@ char const *ssl_version_by_num(uint32_t v)
        return buffer;
 }
 
+/** Return the linked SSL version number as a string
+ *
+ * @return pointer to a static buffer containing the version string.
+ */
+char const *ssl_version_num(void)
+{
+       long ssl_linked;
+
+       ssl_linked = SSLeay();
+       return ssl_version_by_num((uint32_t)ssl_linked);
+}
+
 /** Convert two openssl version numbers into a range string
  *
  * @note Not thread safe.
@@ -169,13 +182,17 @@ int ssl_check_consistency(void) {
        return 0;
 }
 
+char const *ssl_version_num(void)
+{
+       return "not linked";
+}
+
 char const *ssl_version()
 {
        return "not linked";
 }
 #endif /* ifdef HAVE_OPENSSL_CRYPTO_H */
 
-
 /** Check if the application linking to the library has the correct magic number
  *
  * @param magic number as defined by RADIUSD_MAGIC_NUMBER
@@ -207,113 +224,357 @@ int rad_check_lib_magic(uint64_t magic)
        return 0;
 }
 
-/*
- *     Display the revision number for this program
+/** Add a feature flag to the main configuration
+ *
+ * Add a feature flag (yes/no) to the 'feature' subsection
+ * off the main config.
+ *
+ * This allows the user to create configurations that work with
+ * across multiple environments.
+ *
+ * @param cs to add feature pair to.
+ * @param name of feature.
+ * @param enabled Whether the feature is present/enabled.
+ * @return 0 on success else -1.
+ */
+int version_add_feature(CONF_SECTION *cs, char const *name, bool enabled)
+{
+       if (!cs) return -1;
+
+       if (!cf_pair_find(cs, name)) {
+               CONF_PAIR *cp;
+
+               cp = cf_pair_alloc(cs, name, enabled ? "yes" : "no",
+                                  T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+               if (!cp) return -1;
+               cf_pair_add(cs, cp);
+       }
+
+       return 0;
+}
+
+/** Add a library/server version pair to the main configuration
+ *
+ * Add a version number to the 'version' subsection off the main
+ * config.
+ *
+ * Because of the optimisations in the configuration parser, these
+ * may be checked using regular expressions without a performance
+ * penalty.
+ *
+ * The version pairs are there primarily to work around defects
+ * in libraries or the server.
+ *
+ * @param cs to add feature pair to.
+ * @param name of library or feature.
+ * @param version Humanly readable version text.
+ * @return 0 on success else -1.
  */
-void version(void)
+int version_add_number(CONF_SECTION *cs, char const *name, char const *version)
 {
-       INFO("%s: %s", progname, radiusd_version);
+       CONF_PAIR *old;
+
+       if (!cs) return -1;
 
-       DEBUG3("Server was built with: ");
+       old = cf_pair_find(cs, name);
+       if (!old) {
+               CONF_PAIR *cp;
 
+               cp = cf_pair_alloc(cs, name, version, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+               if (!cp) return -1;
+
+               cf_pair_add(cs, cp);
+       } else {
+               WARN("Replacing user version.%s (%s) with %s", name, cf_pair_value(old), version);
+
+               cf_pair_replace(cs, old, version);
+       }
+
+       return 0;
+}
+
+
+/** Initialise core feature flags
+ *
+ * @param cs Where to add the CONF_PAIRS, if null pairs will be added
+ *     to the 'feature' section of the main config.
+ */
+void version_init_features(CONF_SECTION *cs)
+{
+       version_add_feature(cs, "accounting",
 #ifdef WITH_ACCOUNTING
-       DEBUG3("  accounting");
+                               true
+#else
+                               false
 #endif
-       DEBUG3("  authentication"); /* always enabled */
+                               );
 
+       version_add_feature(cs, "authentication", true);
+
+       version_add_feature(cs, "ascend-binary-attributes",
 #ifdef WITH_ASCEND_BINARY
-       DEBUG3("  ascend binary attributes");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "coa",
 #ifdef WITH_COA
-       DEBUG3("  coa");
+                               true
+#else
+                               false
 #endif
+                               );
+
+
+       version_add_feature(cs, "control-socket",
 #ifdef WITH_COMMAND_SOCKET
-       DEBUG3("  control-socket");
+                               true
+#else
+                               false
 #endif
+                               );
+
+
+       version_add_feature(cs, "detail",
 #ifdef WITH_DETAIL
-       DEBUG3("  detail");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "dhcp",
 #ifdef WITH_DHCP
-       DEBUG3("  dhcp");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "dynamic-clients",
 #ifdef WITH_DYNAMIC_CLIENTS
-       DEBUG3("  dynamic clients");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "osfc2",
 #ifdef OSFC2
-       DEBUG3("  OSFC2");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "proxy",
 #ifdef WITH_PROXY
-       DEBUG3("  proxy");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "regex-pcre",
 #ifdef HAVE_PCRE
-       DEBUG3("  regex-pcre");
+                               true
 #else
-#  ifdef HAVE_REGEX
-#    ifdef HAVE_REG_EXTENDED
-       DEBUG3("  regex-posix-extended");
-#    else
-       DEBUG3("  regex-posix");
-#    endif
+                               false
+#endif
+                               );
+
+#if !defined(HAVE_PCRE) && defined(HAVE_REGEX)
+       version_add_feature(cs, "regex-posix", true);
+       version_add_feature(cs, "regex-posix-extended",
+#  ifdef HAVE_REG_EXTENDED
+                               true
+#  else
+                               false
 #  endif
+                               );
+#else
+       version_add_feature(cs, "regex-posix", false);
+       version_add_feature(cs, "regex-posix-extended", false);
 #endif
 
+       version_add_feature(cs, "session-management",
 #ifdef WITH_SESSION_MGMT
-       DEBUG3("  session-management");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "stats",
 #ifdef WITH_STATS
-       DEBUG3("  stats");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "tcp",
 #ifdef WITH_TCP
-       DEBUG3("  tcp");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "threads",
 #ifdef WITH_THREADS
-       DEBUG3("  threads");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "tls",
 #ifdef WITH_TLS
-       DEBUG3("  tls");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "unlang",
 #ifdef WITH_UNLANG
-       DEBUG3("  unlang");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "vmps",
 #ifdef WITH_VMPS
-       DEBUG3("  vmps");
+                               true
+#else
+                               false
 #endif
+                               );
+
+       version_add_feature(cs, "developer",
 #ifndef NDEBUG
-       DEBUG3("  developer");
+                               true
+#else
+                               false
 #endif
+                               );
+}
 
-       DEBUG3("Server core libs:");
-       DEBUG3("  talloc : %i.%i.*", talloc_version_major(), talloc_version_minor());
-       DEBUG3("  ssl    : %s", ssl_version());
+/** Initialise core version flags
+ *
+ * @param cs Where to add the CONF_PAIRS, if null pairs will be added
+ *     to the 'version' section of the main config.
+ */
+void version_init_numbers(CONF_SECTION *cs)
+{
+       char buffer[128];
+
+       version_add_number(cs, "freeradius-server", radiusd_version_short);
+
+       snprintf(buffer, sizeof(buffer), "%i.%i.*", talloc_version_major(), talloc_version_minor());
+       version_add_number(cs, "talloc", buffer);
+
+       version_add_number(cs, "ssl", ssl_version_num());
 
 #if defined(HAVE_REGEX) && defined(HAVE_PCRE)
-       DEBUG3("  pcre   : %s", pcre_version());
+       version_add_number(cs, "pcre", pcre_version());
 #endif
-       DEBUG3("Library magic number:");
-       DEBUG3("  0x%llx", (unsigned long long) libmagic);
+}
+
+static char const *spaces = "                                    ";    /* 40 */
+
+/*
+ *     Display the revision number for this program
+ */
+void version_print(void)
+{
+       CONF_SECTION *features, *versions;
+       CONF_ITEM *ci;
+       CONF_PAIR *cp;
+
+       if (DEBUG_ENABLED2) {
+               int max = 0, len;
+
+               MEM(features = cf_section_alloc(NULL, "feature", NULL));
+               version_init_features(features);
+
+               MEM(versions = cf_section_alloc(NULL, "version", NULL));
+               version_init_numbers(versions);
 
-       DEBUG3("Endianess:");
+               DEBUG3("Server was built with: ");
+
+               for (ci = cf_item_find_next(features, NULL);
+                    ci;
+                    ci = cf_item_find_next(features, ci)) {
+                       len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
+                       if (max < len) max = len;
+               }
+
+               for (ci = cf_item_find_next(versions, NULL);
+                    ci;
+                    ci = cf_item_find_next(versions, ci)) {
+                       len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
+                       if (max < len) max = len;
+               }
+
+
+               for (ci = cf_item_find_next(features, NULL);
+                    ci;
+                    ci = cf_item_find_next(features, ci)) {
+                       char const *attr;
+
+                       cp = cf_item_to_pair(ci);
+                       attr = cf_pair_attr(cp);
+
+                       DEBUG3("  %s%.*s : %s", attr,
+                              (int)(max - talloc_array_length(attr)), spaces,  cf_pair_value(cp));
+               }
+
+               talloc_free(features);
+
+               DEBUG3("Server core libs:");
+
+               for (ci = cf_item_find_next(versions, NULL);
+                    ci;
+                    ci = cf_item_find_next(versions, ci)) {
+                       char const *attr;
+
+                       cp = cf_item_to_pair(ci);
+                       attr = cf_pair_attr(cp);
+
+                       DEBUG3("  %s%.*s : %s", attr,
+                              (int)(max - talloc_array_length(attr)), spaces,  cf_pair_value(cp));
+               }
+
+               talloc_free(versions);
+
+               DEBUG3("Endianess:");
 #if defined(RADIUS_LITTLE_ENDIAN)
-       DEBUG3("  little");
+               DEBUG3("  little");
 #elif defined(RADIUS_BIG_ENDIAN)
-       DEBUG3("  big");
+               DEBUG3("  big");
 #else
-       DEBUG3("  unknown");
+               DEBUG3("  unknown");
 #endif
 
-       DEBUG3("Compilation flags:");
+               DEBUG3("Compilation flags:");
 #ifdef BUILT_WITH_CPPFLAGS
-       DEBUG3("  cppflags : " BUILT_WITH_CPPFLAGS);
+               DEBUG3("  cppflags : " BUILT_WITH_CPPFLAGS);
 #endif
 #ifdef BUILT_WITH_CFLAGS
-       DEBUG3("  cflags   : " BUILT_WITH_CFLAGS);
+               DEBUG3("  cflags   : " BUILT_WITH_CFLAGS);
 #endif
 #ifdef BUILT_WITH_LDFLAGS
-       DEBUG3("  ldflags  : " BUILT_WITH_LDFLAGS);
+               DEBUG3("  ldflags  : " BUILT_WITH_LDFLAGS);
 #endif
 #ifdef BUILT_WITH_LIBS
-       DEBUG3("  libs     : " BUILT_WITH_LIBS);
+               DEBUG3("  libs     : " BUILT_WITH_LIBS);
 #endif
+       }
        INFO("Copyright (C) 1999-2015 The FreeRADIUS server project and contributors");
        INFO("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A");
        INFO("PARTICULAR PURPOSE");
index 30a7852..9a4b580 100644 (file)
@@ -92,8 +92,6 @@ static char const * const xlat_foreach_names[] = {"Foreach-Variable-0",
 
 static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };     /* up to 10 for foreach */
 
-static char const *radiusd_short_version = RADIUSD_VERSION_STRING;
-
 /** Print length of its RHS.
  *
  */
@@ -2151,7 +2149,8 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
                        break;
 
                case 'v': /* Version of code */
-                       snprintf(str, freespace, "%s", radiusd_short_version);
+                       RWDEBUG("%%v is deprecated and will be removed.  Use ${version.freeradius-server}");
+                       snprintf(str, freespace, "%s", radiusd_version_short);
                        break;
 
                default: