Update copyright year
[freeradius.git] / src / main / version.c
1 /*
2  * version.c    Print version number and exit.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 1999-2014  The FreeRADIUS server project
21  * Copyright 2012  Alan DeKok <aland@ox.org>
22  * Copyright 2000  Chris Parker <cparker@starnetusa.com>
23  */
24
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 USES_APPLE_DEPRECATED_API       /* OpenSSL API has been deprecated by Apple */
29
30 static uint64_t libmagic = RADIUSD_MAGIC_NUMBER;
31 char const      *radiusd_version_short = RADIUSD_VERSION_STRING;
32
33 #ifdef HAVE_OPENSSL_CRYPTO_H
34 #  include <openssl/crypto.h>
35 #  include <openssl/opensslv.h>
36
37 static long ssl_built = OPENSSL_VERSION_NUMBER;
38
39 /** Check built and linked versions of OpenSSL match
40  *
41  * OpenSSL version number consists of:
42  * MNNFFPPS: major minor fix patch status
43  *
44  * Where status >= 0 && < 10 means beta, and status 10 means release.
45  *
46  * Startup check for whether the linked version of OpenSSL matches the
47  * version the server was built against.
48  *
49  * @return 0 if ok, else -1
50  */
51 int ssl_check_consistency(void)
52 {
53         long ssl_linked;
54
55         ssl_linked = SSLeay();
56
57         /*
58          *      Status mismatch always triggers error.
59          */
60         if ((ssl_linked & 0x0000000f) != (ssl_built & 0x0000000f)) {
61         mismatch:
62                 ERROR("libssl version mismatch.  built: %lx linked: %lx",
63                       (unsigned long) ssl_built,
64                       (unsigned long) ssl_linked);
65
66                 return -1;
67         }
68
69         /*
70          *      Use the OpenSSH approach and relax fix checks after version
71          *      1.0.0 and only allow moving backwards within a patch
72          *      series.
73          */
74         if (ssl_built & 0xf0000000) {
75                 if ((ssl_built & 0xfffff000) != (ssl_linked & 0xfffff000) ||
76                     (ssl_built & 0x00000ff0) > (ssl_linked & 0x00000ff0)) goto mismatch;
77         /*
78          *      Before 1.0.0 we require the same major minor and fix version
79          *      and ignore the patch number.
80          */
81         } else if ((ssl_built & 0xfffff000) != (ssl_linked & 0xfffff000)) goto mismatch;
82
83         return 0;
84 }
85
86 /** Convert a version number to a text string
87  *
88  * @note Not thread safe.
89  *
90  * @param v version to convert.
91  * @return pointer to a static buffer containing the version string.
92  */
93 char const *ssl_version_by_num(uint32_t v)
94 {
95         /* 2 (%s) + 1 (.) + 2 (%i) + 1 (.) + 2 (%i) + 1 (c) + 8 (%s) + \0 */
96         static char buffer[18];
97         char *p = buffer;
98
99         p += sprintf(p, "%u.%u.%u",
100                      (0xf0000000 & v) >> 28,
101                      (0x0ff00000 & v) >> 20,
102                      (0x000ff000 & v) >> 12);
103
104         if ((0x00000ff0 & v) >> 4) {
105                 *p++ =  (char) (0x60 + ((0x00000ff0 & v) >> 4));
106         }
107
108         *p++ = ' ';
109
110         /*
111          *      Development (0)
112          */
113         if ((0x0000000f & v) == 0) {
114                 strcpy(p, "dev");
115         /*
116          *      Beta (1-14)
117          */
118         } else if ((0x0000000f & v) <= 14) {
119                 sprintf(p, "beta %u", 0x0000000f & v);
120         } else {
121                 strcpy(p, "release");
122         }
123
124         return buffer;
125 }
126
127 /** Return the linked SSL version number as a string
128  *
129  * @return pointer to a static buffer containing the version string.
130  */
131 char const *ssl_version_num(void)
132 {
133         long ssl_linked;
134
135         ssl_linked = SSLeay();
136         return ssl_version_by_num((uint32_t)ssl_linked);
137 }
138
139 /** Convert two openssl version numbers into a range string
140  *
141  * @note Not thread safe.
142  *
143  * @param low version to convert.
144  * @param high version to convert.
145  * @return pointer to a static buffer containing the version range string.
146  */
147 char const *ssl_version_range(uint32_t low, uint32_t high)
148 {
149         /* 12 (version) + 3 ( - ) + 12 (version) */
150         static char buffer[28];
151         char *p = buffer;
152
153         p += strlcpy(p, ssl_version_by_num(low), sizeof(buffer));
154         p += strlcpy(p, " - ", sizeof(buffer) - (p - buffer));
155         strlcpy(p, ssl_version_by_num(high), sizeof(buffer) - (p - buffer));
156
157         return buffer;
158 }
159
160 /** Print the current linked version of Openssl
161  *
162  * Print the currently linked version of the OpenSSL library.
163  *
164  * @note Not thread safe.
165  * @return pointer to a static buffer containing libssl version information.
166  */
167 char const *ssl_version(void)
168 {
169         static char buffer[256];
170
171         uint32_t v = SSLeay();
172
173         snprintf(buffer, sizeof(buffer), "%s 0x%.8x (%s)",
174                  SSLeay_version(SSLEAY_VERSION),                /* Not all builds include a useful version number */
175                  v,
176                  ssl_version_by_num(v));
177
178         return buffer;
179 }
180 #  else
181 int ssl_check_consistency(void) {
182         return 0;
183 }
184
185 char const *ssl_version_num(void)
186 {
187         return "not linked";
188 }
189
190 char const *ssl_version()
191 {
192         return "not linked";
193 }
194 #endif /* ifdef HAVE_OPENSSL_CRYPTO_H */
195
196 /** Check if the application linking to the library has the correct magic number
197  *
198  * @param magic number as defined by RADIUSD_MAGIC_NUMBER
199  * @returns 0 on success, -1 on prefix mismatch, -2 on version mismatch -3 on commit mismatch.
200  */
201 int rad_check_lib_magic(uint64_t magic)
202 {
203         if (MAGIC_PREFIX(magic) != MAGIC_PREFIX(libmagic)) {
204                 ERROR("Application and libfreeradius-server magic number (prefix) mismatch."
205                       "  application: %x library: %x",
206                       MAGIC_PREFIX(magic), MAGIC_PREFIX(libmagic));
207                 return -1;
208         }
209
210         if (MAGIC_VERSION(magic) != MAGIC_VERSION(libmagic)) {
211                 ERROR("Application and libfreeradius-server magic number (version) mismatch."
212                       "  application: %lx library: %lx",
213                       (unsigned long) MAGIC_VERSION(magic), (unsigned long) MAGIC_VERSION(libmagic));
214                 return -2;
215         }
216
217         if (MAGIC_COMMIT(magic) != MAGIC_COMMIT(libmagic)) {
218                 ERROR("Application and libfreeradius-server magic number (commit) mismatch."
219                       "  application: %lx library: %lx",
220                       (unsigned long) MAGIC_COMMIT(magic), (unsigned long) MAGIC_COMMIT(libmagic));
221                 return -3;
222         }
223
224         return 0;
225 }
226
227 /** Add a feature flag to the main configuration
228  *
229  * Add a feature flag (yes/no) to the 'feature' subsection
230  * off the main config.
231  *
232  * This allows the user to create configurations that work with
233  * across multiple environments.
234  *
235  * @param cs to add feature pair to.
236  * @param name of feature.
237  * @param enabled Whether the feature is present/enabled.
238  * @return 0 on success else -1.
239  */
240 int version_add_feature(CONF_SECTION *cs, char const *name, bool enabled)
241 {
242         if (!cs) return -1;
243
244         if (!cf_pair_find(cs, name)) {
245                 CONF_PAIR *cp;
246
247                 cp = cf_pair_alloc(cs, name, enabled ? "yes" : "no",
248                                    T_OP_SET, T_BARE_WORD, T_BARE_WORD);
249                 if (!cp) return -1;
250                 cf_pair_add(cs, cp);
251         }
252
253         return 0;
254 }
255
256 /** Add a library/server version pair to the main configuration
257  *
258  * Add a version number to the 'version' subsection off the main
259  * config.
260  *
261  * Because of the optimisations in the configuration parser, these
262  * may be checked using regular expressions without a performance
263  * penalty.
264  *
265  * The version pairs are there primarily to work around defects
266  * in libraries or the server.
267  *
268  * @param cs to add feature pair to.
269  * @param name of library or feature.
270  * @param version Humanly readable version text.
271  * @return 0 on success else -1.
272  */
273 int version_add_number(CONF_SECTION *cs, char const *name, char const *version)
274 {
275         CONF_PAIR *old;
276
277         if (!cs) return -1;
278
279         old = cf_pair_find(cs, name);
280         if (!old) {
281                 CONF_PAIR *cp;
282
283                 cp = cf_pair_alloc(cs, name, version, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
284                 if (!cp) return -1;
285
286                 cf_pair_add(cs, cp);
287         } else {
288                 WARN("Replacing user version.%s (%s) with %s", name, cf_pair_value(old), version);
289
290                 cf_pair_replace(cs, old, version);
291         }
292
293         return 0;
294 }
295
296
297 /** Initialise core feature flags
298  *
299  * @param cs Where to add the CONF_PAIRS, if null pairs will be added
300  *      to the 'feature' section of the main config.
301  */
302 void version_init_features(CONF_SECTION *cs)
303 {
304         version_add_feature(cs, "accounting",
305 #ifdef WITH_ACCOUNTING
306                                 true
307 #else
308                                 false
309 #endif
310                                 );
311
312         version_add_feature(cs, "authentication", true);
313
314         version_add_feature(cs, "ascend-binary-attributes",
315 #ifdef WITH_ASCEND_BINARY
316                                 true
317 #else
318                                 false
319 #endif
320                                 );
321
322         version_add_feature(cs, "coa",
323 #ifdef WITH_COA
324                                 true
325 #else
326                                 false
327 #endif
328                                 );
329
330
331         version_add_feature(cs, "control-socket",
332 #ifdef WITH_COMMAND_SOCKET
333                                 true
334 #else
335                                 false
336 #endif
337                                 );
338
339
340         version_add_feature(cs, "detail",
341 #ifdef WITH_DETAIL
342                                 true
343 #else
344                                 false
345 #endif
346                                 );
347
348         version_add_feature(cs, "dhcp",
349 #ifdef WITH_DHCP
350                                 true
351 #else
352                                 false
353 #endif
354                                 );
355
356         version_add_feature(cs, "dynamic-clients",
357 #ifdef WITH_DYNAMIC_CLIENTS
358                                 true
359 #else
360                                 false
361 #endif
362                                 );
363
364         version_add_feature(cs, "osfc2",
365 #ifdef OSFC2
366                                 true
367 #else
368                                 false
369 #endif
370                                 );
371
372         version_add_feature(cs, "proxy",
373 #ifdef WITH_PROXY
374                                 true
375 #else
376                                 false
377 #endif
378                                 );
379
380         version_add_feature(cs, "regex-pcre",
381 #ifdef HAVE_PCRE
382                                 true
383 #else
384                                 false
385 #endif
386                                 );
387
388 #if !defined(HAVE_PCRE) && defined(HAVE_REGEX)
389         version_add_feature(cs, "regex-posix", true);
390         version_add_feature(cs, "regex-posix-extended",
391 #  ifdef HAVE_REG_EXTENDED
392                                 true
393 #  else
394                                 false
395 #  endif
396                                 );
397 #else
398         version_add_feature(cs, "regex-posix", false);
399         version_add_feature(cs, "regex-posix-extended", false);
400 #endif
401
402         version_add_feature(cs, "session-management",
403 #ifdef WITH_SESSION_MGMT
404                                 true
405 #else
406                                 false
407 #endif
408                                 );
409
410         version_add_feature(cs, "stats",
411 #ifdef WITH_STATS
412                                 true
413 #else
414                                 false
415 #endif
416                                 );
417
418         version_add_feature(cs, "tcp",
419 #ifdef WITH_TCP
420                                 true
421 #else
422                                 false
423 #endif
424                                 );
425
426         version_add_feature(cs, "threads",
427 #ifdef WITH_THREADS
428                                 true
429 #else
430                                 false
431 #endif
432                                 );
433
434         version_add_feature(cs, "tls",
435 #ifdef WITH_TLS
436                                 true
437 #else
438                                 false
439 #endif
440                                 );
441
442         version_add_feature(cs, "unlang",
443 #ifdef WITH_UNLANG
444                                 true
445 #else
446                                 false
447 #endif
448                                 );
449
450         version_add_feature(cs, "vmps",
451 #ifdef WITH_VMPS
452                                 true
453 #else
454                                 false
455 #endif
456                                 );
457
458         version_add_feature(cs, "developer",
459 #ifndef NDEBUG
460                                 true
461 #else
462                                 false
463 #endif
464                                 );
465 }
466
467 /** Initialise core version flags
468  *
469  * @param cs Where to add the CONF_PAIRS, if null pairs will be added
470  *      to the 'version' section of the main config.
471  */
472 void version_init_numbers(CONF_SECTION *cs)
473 {
474         char buffer[128];
475
476         version_add_number(cs, "freeradius-server", radiusd_version_short);
477
478         snprintf(buffer, sizeof(buffer), "%i.%i.*", talloc_version_major(), talloc_version_minor());
479         version_add_number(cs, "talloc", buffer);
480
481         version_add_number(cs, "ssl", ssl_version_num());
482
483 #if defined(HAVE_REGEX) && defined(HAVE_PCRE)
484         version_add_number(cs, "pcre", pcre_version());
485 #endif
486 }
487
488 static char const *spaces = "                                    ";     /* 40 */
489
490 /*
491  *      Display the revision number for this program
492  */
493 void version_print(void)
494 {
495         CONF_SECTION *features, *versions;
496         CONF_ITEM *ci;
497         CONF_PAIR *cp;
498
499         if (DEBUG_ENABLED3) {
500                 int max = 0, len;
501
502                 MEM(features = cf_section_alloc(NULL, "feature", NULL));
503                 version_init_features(features);
504
505                 MEM(versions = cf_section_alloc(NULL, "version", NULL));
506                 version_init_numbers(versions);
507
508                 DEBUG2("Server was built with: ");
509
510                 for (ci = cf_item_find_next(features, NULL);
511                      ci;
512                      ci = cf_item_find_next(features, ci)) {
513                         len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
514                         if (max < len) max = len;
515                 }
516
517                 for (ci = cf_item_find_next(versions, NULL);
518                      ci;
519                      ci = cf_item_find_next(versions, ci)) {
520                         len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
521                         if (max < len) max = len;
522                 }
523
524
525                 for (ci = cf_item_find_next(features, NULL);
526                      ci;
527                      ci = cf_item_find_next(features, ci)) {
528                         char const *attr;
529
530                         cp = cf_item_to_pair(ci);
531                         attr = cf_pair_attr(cp);
532
533                         DEBUG2("  %s%.*s : %s", attr,
534                                (int)(max - talloc_array_length(attr)), spaces,  cf_pair_value(cp));
535                 }
536
537                 talloc_free(features);
538
539                 DEBUG2("Server core libs:");
540
541                 for (ci = cf_item_find_next(versions, NULL);
542                      ci;
543                      ci = cf_item_find_next(versions, ci)) {
544                         char const *attr;
545
546                         cp = cf_item_to_pair(ci);
547                         attr = cf_pair_attr(cp);
548
549                         DEBUG2("  %s%.*s : %s", attr,
550                                (int)(max - talloc_array_length(attr)), spaces,  cf_pair_value(cp));
551                 }
552
553                 talloc_free(versions);
554
555                 DEBUG2("Endianness:");
556 #if defined(FR_LITTLE_ENDIAN)
557                 DEBUG2("  little");
558 #elif defined(FR_BIG_ENDIAN)
559                 DEBUG2("  big");
560 #else
561                 DEBUG2("  unknown");
562 #endif
563
564                 DEBUG2("Compilation flags:");
565 #ifdef BUILT_WITH_CPPFLAGS
566                 DEBUG2("  cppflags : " BUILT_WITH_CPPFLAGS);
567 #endif
568 #ifdef BUILT_WITH_CFLAGS
569                 DEBUG2("  cflags   : " BUILT_WITH_CFLAGS);
570 #endif
571 #ifdef BUILT_WITH_LDFLAGS
572                 DEBUG2("  ldflags  : " BUILT_WITH_LDFLAGS);
573 #endif
574 #ifdef BUILT_WITH_LIBS
575                 DEBUG2("  libs     : " BUILT_WITH_LIBS);
576 #endif
577                 DEBUG2("  ");
578         }
579         INFO("FreeRADIUS Version " RADIUSD_VERSION_STRING);
580         INFO("Copyright (C) 1999-2017 The FreeRADIUS server project and contributors");
581         INFO("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A");
582         INFO("PARTICULAR PURPOSE");
583         INFO("You may redistribute copies of FreeRADIUS under the terms of the");
584         INFO("GNU General Public License");
585         INFO("For more information about these matters, see the file named COPYRIGHT");
586
587         fflush(NULL);
588 }
589