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, µ, 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