/* * version.c Print version number and exit. * * Version: $Id$ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 1999-2019 The FreeRADIUS server project * Copyright 2012 Alan DeKok * Copyright 2000 Chris Parker */ RCSID("$Id$") #include USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ static uint64_t libmagic = RADIUSD_MAGIC_NUMBER; char const *radiusd_version_short = RADIUSD_VERSION_STRING; #ifdef HAVE_OPENSSL_CRYPTO_H # include # include static long ssl_built = OPENSSL_VERSION_NUMBER; /** Check built and linked versions of OpenSSL match * * OpenSSL version number consists of: * MNNFFPPS: major minor fix patch status * * Where status >= 0 && < 10 means beta, and status 10 means release. * * https://wiki.openssl.org/index.php/Versioning * * Startup check for whether the linked version of OpenSSL matches the * version the server was built against. * * @return 0 if ok, else -1 */ int ssl_check_consistency(void) { long ssl_linked; ssl_linked = SSLeay(); /* * Major and minor versions mismatch, that's bad. */ if ((ssl_linked & 0xfff00000) != (ssl_built & 0xfff00000)) goto mismatch; /* * 1.1.0 and later export all of the APIs we need, so we * don't care about mismatches in fix / patch / status * fields. If the major && minor fields match, that's * good enough. */ if ((ssl_linked & 0xfff00000) >= 0x10100000) return 0; /* * Before 1.1.0, we need all kinds of stupid checks to * see if it might work. */ /* * Status mismatch always triggers error. */ if ((ssl_linked & 0x0000000f) != (ssl_built & 0x0000000f)) { mismatch: ERROR("libssl version mismatch. built: %lx linked: %lx", (unsigned long) ssl_built, (unsigned long) ssl_linked); return -1; } /* * Use the OpenSSH approach and relax fix checks after version * 1.0.0 and only allow moving backwards within a patch * series. */ if (ssl_built & 0xf0000000) { if ((ssl_built & 0xfffff000) != (ssl_linked & 0xfffff000) || (ssl_built & 0x00000ff0) > (ssl_linked & 0x00000ff0)) goto mismatch; /* * Before 1.0.0 we require the same major minor and fix version * and ignore the patch number. */ } else if ((ssl_built & 0xfffff000) != (ssl_linked & 0xfffff000)) goto mismatch; return 0; } /** Convert a version number to a text string * * @note Not thread safe. * * @param v version to convert. * @return pointer to a static buffer containing the version string. */ char const *ssl_version_by_num(uint32_t v) { /* 2 (%s) + 1 (.) + 2 (%i) + 1 (.) + 2 (%i) + 1 (c) + 8 (%s) + \0 */ static char buffer[18]; char *p = buffer; p += sprintf(p, "%u.%u.%u", (0xf0000000 & v) >> 28, (0x0ff00000 & v) >> 20, (0x000ff000 & v) >> 12); if ((0x00000ff0 & v) >> 4) { *p++ = (char) (0x60 + ((0x00000ff0 & v) >> 4)); } *p++ = ' '; /* * Development (0) */ if ((0x0000000f & v) == 0) { strcpy(p, "dev"); /* * Beta (1-14) */ } else if ((0x0000000f & v) <= 14) { sprintf(p, "beta %u", 0x0000000f & v); } else { strcpy(p, "release"); } 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. * * @param low version to convert. * @param high version to convert. * @return pointer to a static buffer containing the version range string. */ char const *ssl_version_range(uint32_t low, uint32_t high) { /* 12 (version) + 3 ( - ) + 12 (version) */ static char buffer[28]; char *p = buffer; p += strlcpy(p, ssl_version_by_num(low), sizeof(buffer)); p += strlcpy(p, " - ", sizeof(buffer) - (p - buffer)); strlcpy(p, ssl_version_by_num(high), sizeof(buffer) - (p - buffer)); return buffer; } /** Print the current linked version of Openssl * * Print the currently linked version of the OpenSSL library. * * @note Not thread safe. * @return pointer to a static buffer containing libssl version information. */ char const *ssl_version(void) { static char buffer[256]; uint32_t v = SSLeay(); snprintf(buffer, sizeof(buffer), "%s 0x%.8x (%s)", SSLeay_version(SSLEAY_VERSION), /* Not all builds include a useful version number */ v, ssl_version_by_num(v)); return buffer; } # else int ssl_check_consistency(void) { return 0; } char const *ssl_version_num(void) { return "not linked"; } char const *ssl_version(void) { 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 * @returns 0 on success, -1 on prefix mismatch, -2 on version mismatch -3 on commit mismatch. */ int rad_check_lib_magic(uint64_t magic) { if (MAGIC_PREFIX(magic) != MAGIC_PREFIX(libmagic)) { ERROR("Application and libfreeradius-server magic number (prefix) mismatch." " application: %x library: %x", MAGIC_PREFIX(magic), MAGIC_PREFIX(libmagic)); return -1; } if (MAGIC_VERSION(magic) != MAGIC_VERSION(libmagic)) { ERROR("Application and libfreeradius-server magic number (version) mismatch." " application: %lx library: %lx", (unsigned long) MAGIC_VERSION(magic), (unsigned long) MAGIC_VERSION(libmagic)); return -2; } if (MAGIC_COMMIT(magic) != MAGIC_COMMIT(libmagic)) { ERROR("Application and libfreeradius-server magic number (commit) mismatch." " application: %lx library: %lx", (unsigned long) MAGIC_COMMIT(magic), (unsigned long) MAGIC_COMMIT(libmagic)); return -3; } return 0; } /** 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. */ int version_add_number(CONF_SECTION *cs, char const *name, char const *version) { CONF_PAIR *old; if (!cs) return -1; 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 true #else false #endif ); version_add_feature(cs, "authentication", true); version_add_feature(cs, "ascend-binary-attributes", #ifdef WITH_ASCEND_BINARY true #else false #endif ); version_add_feature(cs, "coa", #ifdef WITH_COA true #else false #endif ); version_add_feature(cs, "recv-coa-from-home-server", #ifdef WITH_COA_TUNNEL true #else false #endif ); version_add_feature(cs, "control-socket", #ifdef WITH_COMMAND_SOCKET true #else false #endif ); version_add_feature(cs, "detail", #ifdef WITH_DETAIL true #else false #endif ); version_add_feature(cs, "dhcp", #ifdef WITH_DHCP true #else false #endif ); version_add_feature(cs, "dynamic-clients", #ifdef WITH_DYNAMIC_CLIENTS true #else false #endif ); version_add_feature(cs, "osfc2", #ifdef OSFC2 true #else false #endif ); version_add_feature(cs, "proxy", #ifdef WITH_PROXY true #else false #endif ); version_add_feature(cs, "regex-pcre", #ifdef HAVE_PCRE true #else 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 true #else false #endif ); version_add_feature(cs, "stats", #ifdef WITH_STATS true #else false #endif ); version_add_feature(cs, "systemd", #ifdef HAVE_SYSTEMD true #else false #endif ); version_add_feature(cs, "tcp", #ifdef WITH_TCP true #else false #endif ); version_add_feature(cs, "threads", #ifdef WITH_THREADS true #else false #endif ); version_add_feature(cs, "tls", #ifdef WITH_TLS true #else false #endif ); version_add_feature(cs, "unlang", #ifdef WITH_UNLANG true #else false #endif ); version_add_feature(cs, "vmps", #ifdef WITH_VMPS true #else false #endif ); version_add_feature(cs, "developer", #ifndef NDEBUG true #else false #endif ); } /** 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) version_add_number(cs, "pcre", pcre_version()); #endif } 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_ENABLED3) { 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); DEBUG2("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); DEBUG2(" %s%.*s : %s", attr, (int)(max - talloc_array_length(attr)), spaces, cf_pair_value(cp)); } talloc_free(features); DEBUG2("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); DEBUG2(" %s%.*s : %s", attr, (int)(max - talloc_array_length(attr)), spaces, cf_pair_value(cp)); } talloc_free(versions); DEBUG2("Endianness:"); #if defined(FR_LITTLE_ENDIAN) DEBUG2(" little"); #elif defined(FR_BIG_ENDIAN) DEBUG2(" big"); #else DEBUG2(" unknown"); #endif DEBUG2("Compilation flags:"); #ifdef BUILT_WITH_CPPFLAGS DEBUG2(" cppflags : " BUILT_WITH_CPPFLAGS); #endif #ifdef BUILT_WITH_CFLAGS DEBUG2(" cflags : " BUILT_WITH_CFLAGS); #endif #ifdef BUILT_WITH_LDFLAGS DEBUG2(" ldflags : " BUILT_WITH_LDFLAGS); #endif #ifdef BUILT_WITH_LIBS DEBUG2(" libs : " BUILT_WITH_LIBS); #endif DEBUG2(" "); } INFO("FreeRADIUS Version " RADIUSD_VERSION_STRING); INFO("Copyright (C) 1999-2022 The FreeRADIUS server project and contributors"); INFO("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A"); INFO("PARTICULAR PURPOSE"); INFO("You may redistribute copies of FreeRADIUS under the terms of the"); INFO("GNU General Public License"); INFO("For more information about these matters, see the file named COPYRIGHT"); fflush(NULL); }