1 /*****
2 *
3 * Copyright (C) 2004-2015 CS-SI. All Rights Reserved.
4 * Author: Yoann Vandoorselaere <yoann.v@prelude-ids.com>
5 *
6 * This file is part of the Prelude library.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 *****/
23 
24 #include "config.h"
25 #include "libmissing.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <gnutls/gnutls.h>
31 #include <gcrypt.h>
32 
33 #include "glthread/thread.h"
34 #include "glthread/lock.h"
35 
36 #include "prelude.h"
37 #include "idmef-path.h"
38 #include "prelude-option.h"
39 #include "prelude-log.h"
40 #include "prelude-timer.h"
41 #include "variable.h"
42 #include "tls-auth.h"
43 
44 
45 int _prelude_internal_argc = 0;
46 char *_prelude_prefix = NULL;
47 char *_prelude_internal_argv[1024];
48 
49 char _prelude_init_cwd[PATH_MAX];
50 static int libprelude_refcount = 0;
51 extern prelude_option_t *_prelude_generic_optlist;
52 extern gl_lock_t _criteria_parse_mutex;
53 
54 
55 
tls_log_func(int level,const char * data)56 static void tls_log_func(int level, const char *data)
57 {
58         prelude_log(PRELUDE_LOG_INFO, "%s", data);
59 }
60 
gcry_prelude_mutex_init(void ** retval)61 static int gcry_prelude_mutex_init(void **retval)
62 {
63         int ret;
64         gl_lock_t *lock;
65 
66         *retval = lock = malloc(sizeof(*lock));
67         if ( ! lock )
68                 return ENOMEM;
69 
70         ret = glthread_lock_init(lock);
71         if ( ret < 0 )
72                 free(lock);
73 
74         return ret;
75 }
76 
77 
gcry_prelude_mutex_destroy(void ** lock)78 static int gcry_prelude_mutex_destroy(void **lock)
79 {
80         return glthread_lock_destroy(*lock);
81 }
82 
83 
84 
gcry_prelude_mutex_lock(void ** lock)85 static int gcry_prelude_mutex_lock(void **lock)
86 {
87         return glthread_lock_lock((gl_lock_t *) *lock);
88 }
89 
90 
gcry_prelude_mutex_unlock(void ** lock)91 static int gcry_prelude_mutex_unlock(void **lock)
92 {
93         return glthread_lock_unlock((gl_lock_t *) *lock);
94 }
95 
96 
97 static struct gcry_thread_cbs gcry_threads_prelude = {
98         GCRY_THREAD_OPTION_USER,
99         NULL,
100         gcry_prelude_mutex_init,
101         gcry_prelude_mutex_destroy,
102         gcry_prelude_mutex_lock,
103         gcry_prelude_mutex_unlock,
104         NULL,
105         NULL,
106         NULL,
107         NULL,
108         NULL,
109         NULL,
110         NULL,
111         NULL
112 };
113 
114 
slice_arguments(int * argc,char ** argv)115 static void slice_arguments(int *argc, char **argv)
116 {
117         int i;
118         char *ptr;
119         prelude_option_t *rootopt, *opt, *bkp = NULL;
120 
121         _prelude_client_register_options();
122 
123         _prelude_internal_argc = 0;
124         _prelude_internal_argv[0] = NULL;
125 
126         if ( ! argc || ! argv || *argc < 1 )
127                 return;
128 
129         rootopt = _prelude_generic_optlist;
130         _prelude_internal_argv[_prelude_internal_argc++] = argv[0];
131 
132         for ( i = 0; i < *argc && (size_t) _prelude_internal_argc + 1 < sizeof(_prelude_internal_argv) / sizeof(char *); i++ ) {
133 
134                 ptr = argv[i];
135                 if ( *ptr != '-' )
136                         continue;
137 
138                 while ( *ptr == '-' ) ptr++;
139 
140                 opt = prelude_option_search(rootopt, ptr, PRELUDE_OPTION_TYPE_CLI, FALSE);
141                 if ( ! opt ) {
142                         if ( bkp )
143                                 rootopt = bkp;
144                         continue;
145                 }
146 
147                 if ( prelude_option_has_optlist(opt) ) {
148                         rootopt = opt;
149                         bkp = _prelude_generic_optlist;
150                 }
151 
152                 _prelude_internal_argv[_prelude_internal_argc++] = argv[i];
153 
154                 if ( (i + 1) == *argc )
155                         break;
156 
157                 if ( prelude_option_get_has_arg(opt) == PRELUDE_OPTION_ARGUMENT_NONE )
158                         continue;
159 
160                 if ( *argv[i + 1] == '-' )
161                         continue;
162 
163                 _prelude_internal_argv[_prelude_internal_argc++] = argv[i + 1];
164         }
165 }
166 
167 
168 /**
169  * prelude_init:
170  * @argc: Address of the argc parameter of your main() function.
171  * @argv: Address of the argv parameter of your main() function.
172  *
173  * Call this function before using any other Prelude functions in your applications.
174  * It will initialize everything needed to operate the library and parses some standard
175  * command line options. @argc and @argv are adjusted accordingly so your own code will
176  * never see those standard arguments.
177  *
178  * Returns: 0 on success, a negative value if an error occured.
179  */
prelude_init(int * argc,char ** argv)180 int prelude_init(int *argc, char **argv)
181 {
182         int ret;
183         const char *env;
184 
185         if ( libprelude_refcount++ > 0 )
186                 return 0;
187 
188         env = getenv("LIBPRELUDE_DEBUG");
189         if ( env )
190                 prelude_log_set_debug_level(atoi(env));
191 
192         env = getenv("LIBPRELUDE_TLS_DEBUG");
193         if ( env ) {
194                 gnutls_global_set_log_level(atoi(env));
195                 gnutls_global_set_log_function(tls_log_func);
196         }
197 
198         env = getenv("LIBPRELUDE_LOGFILE");
199         if ( env )
200                 prelude_log_set_logfile(env);
201 
202         env = getenv("LIBPRELUDE_PREFIX");
203         if ( env )
204                 _prelude_prefix = strdup(env);
205 
206         env = getenv("LIBPRELUDE_ABORT");
207         if ( env ) {
208                 if ( *env )
209                         _prelude_log_set_abort_level_from_string(env);
210                 else
211                         _prelude_log_set_abort_level(PRELUDE_LOG_CRIT);
212         }
213 
214         prelude_thread_init(NULL);
215 
216         if ( ! getcwd(_prelude_init_cwd, sizeof(_prelude_init_cwd)) )
217                 _prelude_init_cwd[0] = 0;
218 
219         ret = _prelude_timer_init();
220         if ( ret < 0 )
221                 return ret;
222 
223         ret = glthread_atfork(prelude_fork_prepare, prelude_fork_parent, prelude_fork_child);
224         if ( ret != 0 )
225                 return prelude_error_from_errno(ret);
226 
227         slice_arguments(argc, argv);
228 
229         ret = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_prelude);
230         if ( ret < 0 )
231                 return prelude_error_verbose(PRELUDE_ERROR_TLS,
232                                              "gcrypt initialization failed: %s", gcry_strerror(ret));
233 
234         ret = gnutls_global_init();
235         if ( ret < 0 )
236                 return prelude_error_verbose(PRELUDE_ERROR_TLS,
237                                              "TLS initialization failed: %s", gnutls_strerror(ret));
238 
239         return 0;
240 }
241 
242 
243 
244 /**
245  * prelude_deinit:
246  *
247  * Call this function if you're done using the library and want to free global
248  * shared ressource allocated by libprelude.
249  */
prelude_deinit(void)250 void prelude_deinit(void)
251 {
252         prelude_list_t *iter = NULL;
253         prelude_plugin_generic_t *plugin;
254 
255         if ( --libprelude_refcount != 0 )
256                 return;
257 
258         while ( (plugin = prelude_plugin_get_next(NULL, &iter)) )
259                 prelude_plugin_unload(plugin);
260 
261         _idmef_path_cache_destroy();
262         prelude_option_destroy(NULL);
263         variable_unset_all();
264 
265         tls_auth_deinit();
266         gnutls_global_deinit();
267 
268         _prelude_thread_deinit();
269 }
270 
271 
272 
levelstr_to_int(const char * wanted)273 static int levelstr_to_int(const char *wanted)
274 {
275         int i;
276         struct {
277                 int level;
278                 const char *level_str;
279         } tbl[] = {
280                 { LIBPRELUDE_RELEASE_LEVEL_ALPHA, "alpha" },
281                 { LIBPRELUDE_RELEASE_LEVEL_BETA, "beta"   },
282                 { LIBPRELUDE_RELEASE_LEVEL_RC, "rc"       }
283         };
284 
285         for ( i = 0; i < sizeof(tbl) / sizeof(*tbl); i++ ) {
286                 if ( strcmp(wanted, tbl[i].level_str) == 0 )
287                         return tbl[i].level;
288         }
289 
290         return -1;
291 }
292 
293 
294 
295 /**
296  * prelude_parse_version:
297  * @version: A version string.
298  * @out: Where to store the parsed version
299  *
300  * Parse version to an integer, and return it in @out.
301  * Accepted format are:
302  *
303  * major.minor.micro.patchlevel
304  * the following special level string are supported : alpha, beta, rc
305  *
306  * For example: 1.1.1rc1
307  *
308  * Returns: The 0 on success, a negative value in case of error.
309  */
prelude_parse_version(const char * version,unsigned int * out)310 int prelude_parse_version(const char *version, unsigned int *out)
311 {
312         int ret;
313         char levels[6] = { 0 };
314         int major = 0, minor = 0, micro = 0, level = 0, patch = 0;
315 
316         ret = sscanf(version, "%d.%d.%d%5[^0-9]%d", &major, &minor, &micro, levels, &patch);
317         if ( ret <= 0 )
318                 return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "version formatting error with '%s'", version);
319 
320         if ( *levels == 0 || *levels == '.' )
321                 level = LIBPRELUDE_RELEASE_LEVEL_FINAL;
322         else {
323                 level = levelstr_to_int(levels);
324                 if ( level < 0 )
325                         return level;
326         }
327 
328         *out = (major << 24) | (minor << 16) | (micro << 8) | (level << 4) | (patch << 0);
329         return 0;
330 }
331 
332 
333 
334 /**
335  * prelude_check_version:
336  * @req_version: The minimum acceptable version number.
337  *
338  * If @req_version is NULL this function will return the version of the library.
339  * Otherwise, @req_version will be compared to the current library version. If
340  * the library version is higher or equal, this function will return the current
341  * library version. Otherwise, NULL is returned.
342  *
343  * Returns: The current library version, or NULL if @req_version doesn't match.
344  */
prelude_check_version(const char * req_version)345 const char *prelude_check_version(const char *req_version)
346 {
347         int ret;
348         unsigned int hexversion;
349 
350         if ( ! req_version )
351                 return VERSION;
352 
353         ret = prelude_parse_version(req_version, &hexversion);
354         if ( ret < 0 )
355                 return NULL;
356 
357         return (hexversion <= LIBPRELUDE_HEXVERSION) ? VERSION : NULL;
358 }
359 
360 
361 
prelude_fork_prepare(void)362 void prelude_fork_prepare(void)
363 {
364 #ifdef HAVE_PTHREAD_ATFORK
365         return;
366 #endif
367 
368         _prelude_async_fork_prepare();
369         _prelude_timer_fork_prepare();
370 
371         _idmef_path_cache_lock();
372         gl_lock_lock(_criteria_parse_mutex);
373 }
374 
375 
prelude_fork_parent(void)376 void prelude_fork_parent(void)
377 {
378 #ifdef HAVE_PTHREAD_ATFORK
379         return;
380 #endif
381 
382         _prelude_async_fork_parent();
383         _prelude_timer_fork_parent();
384 
385         _idmef_path_cache_unlock();
386         gl_lock_unlock(_criteria_parse_mutex);
387 }
388 
389 
prelude_fork_child(void)390 void prelude_fork_child(void)
391 {
392 #ifdef HAVE_PTHREAD_ATFORK
393         return;
394 #endif
395 
396         _prelude_async_fork_child();
397         _prelude_timer_fork_child();
398 
399         _idmef_path_cache_reinit();
400         gl_lock_init(_criteria_parse_mutex);
401 }
402