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