1 // +------------------------------------------------------------------+
2 // | ____ _ _ __ __ _ __ |
3 // | / ___| |__ ___ ___| | __ | \/ | |/ / |
4 // | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
5 // | | |___| | | | __/ (__| < | | | | . \ |
6 // | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
7 // | |
8 // | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
9 // +------------------------------------------------------------------+
10 //
11 // This file is part of Check_MK.
12 // The official homepage is at http://mathias-kettner.de/check_mk.
13 //
14 // check_mk is free software; you can redistribute it and/or modify it
15 // under the terms of the GNU General Public License as published by
16 // the Free Software Foundation in version 2. check_mk is distributed
17 // in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
18 // out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
19 // PARTICULAR PURPOSE. See the GNU General Public License for more de-
20 // ails. You should have received a copy of the GNU General Public
21 // License along with GNU Make; see the file COPYING. If not, write
22 // to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 // Boston, MA 02110-1301 USA.
24
25 // IWYU pragma: no_include <bits/socket_type.h>
26 #include "config.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <pthread.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/select.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/types.h> // IWYU pragma: keep
38 #include <sys/un.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include "auth.h"
42 #include "data_encoding.h"
43 #include "global_counters.h"
44 #include "livestatus.h"
45 #include "logger.h"
46 #include "nagios.h"
47 #include "store_c.h"
48 #include "strutil.h"
49 #include "waittriggers.h"
50
51 #ifndef AF_LOCAL
52 #define AF_LOCAL AF_UNIX
53 #endif
54 #ifndef PF_LOCAL
55 #define PF_LOCAL PF_UNIX
56 #endif
57
58 // usually - but not always - in sys/un.h
59 #ifndef SUN_LEN
60 #define SUN_LEN(ptr) \
61 ((size_t)(((struct sockaddr_un *)0)->sun_path) + strlen((ptr)->sun_path))
62 #endif
63
64 NEB_API_VERSION(CURRENT_NEB_API_VERSION)
65 #ifndef NAGIOS4
66 extern int event_broker_options;
67 #else
68 extern unsigned long event_broker_options;
69 #endif // NAGIOS4
70 extern int enable_environment_macros;
71 extern char *log_file;
72
73 int g_idle_timeout_msec =
74 300 * 1000; /* maximum idle time for connection in keep alive state */
75 int g_query_timeout_msec = 10 * 1000; /* maximum time for reading a query */
76
77 int g_num_clientthreads = 10; /* allow 10 concurrent connections per default */
78 int g_num_queued_connections =
79 0; /* current number of queued connections (for statistics) */
80 int g_num_active_connections =
81 0; /* current number of active connections (for statistics) */
82 size_t g_thread_stack_size = 65536; /* stack size of threads */
83 extern int g_disable_statehist_filtering;
84
85 #define false 0
86 #define true 1
87
88 void *g_nagios_handle;
89 int g_unix_socket = -1;
90 int g_max_fd_ever = 0;
91 char g_socket_path[4096];
92 char pnp_path_storage[4096];
93 char *g_pnp_path = pnp_path_storage;
94 char g_mk_inventory_path[4096]; // base path of Check_MK inventor files
95 char g_logfile_path[4096];
96 int g_debug_level = 0;
97 int g_should_terminate = false;
98 pthread_t g_mainthread_id;
99 pthread_t *g_clientthread_id;
100 unsigned long g_max_cached_messages = 500000;
101 unsigned long g_max_lines_per_logfile =
102 1000000; // do never read more than that number of lines from a logfile
103 unsigned long g_max_response_size = 100 * 1024 * 1024; // limit answer to 10 MB
104 int g_thread_running = 0;
105 int g_thread_pid = 0;
106 int g_service_authorization = AUTH_LOOSE;
107 int g_group_authorization = AUTH_STRICT;
108 int g_data_encoding = ENCODING_UTF8;
109
110 /* simple statistics data for TableStatus */
111 extern struct host *host_list;
112 extern struct service *service_list;
113 extern scheduled_downtime *scheduled_downtime_list;
114 extern int log_initial_states;
115
116 int g_num_hosts;
117 int g_num_services;
118
count_hosts()119 void count_hosts() {
120 g_num_hosts = 0;
121 host *h = (host *)host_list;
122 while (h) {
123 g_num_hosts++;
124 h = h->next;
125 }
126 }
127
count_services()128 void count_services() {
129 g_num_services = 0;
130 service *s = (service *)service_list;
131 while (s) {
132 g_num_services++;
133 s = s->next;
134 }
135 }
136
137 void *voidp;
138
livestatus_count_fork()139 void livestatus_count_fork() { g_counters[COUNTER_FORKS]++; }
140
livestatus_cleanup_after_fork()141 void livestatus_cleanup_after_fork() {
142 // 4.2.2010: Deactivate the cleanup function. It might cause
143 // more trouble than it tries to avoid. It might lead to a deadlock
144 // with Nagios' fork()-mechanism...
145 // store_deinit();
146 struct stat st;
147
148 int i;
149 // We need to close our server and client sockets. Otherwise
150 // our connections are inherited to host and service checks.
151 // If we close our client connection in such a situation,
152 // the connection will still be open since and the client will
153 // hang while trying to read further data. And the CLOEXEC is
154 // not atomic :-(
155
156 // Eventuell sollte man hier anstelle von store_deinit() nicht
157 // darauf verlassen, dass die ClientQueue alle Verbindungen zumacht.
158 // Es sind ja auch Dateideskriptoren offen, die von Threads gehalten
159 // werden und nicht mehr in der Queue sind. Und in store_deinit()
160 // wird mit mutexes rumgemacht....
161 for (i = 3; i < g_max_fd_ever; i++) {
162 if (0 == fstat(i, &st) && S_ISSOCK(st.st_mode)) {
163 close(i);
164 }
165 }
166 }
167
main_thread(void * data)168 void *main_thread(void *data __attribute__((__unused__))) {
169 g_thread_pid = getpid();
170 while (!g_should_terminate) {
171 do_statistics();
172 if (g_thread_pid != getpid()) {
173 logger(LG_INFO, "I'm not the main process but %d!", getpid());
174 // return;
175 }
176 struct timeval tv;
177 tv.tv_sec = 2;
178 tv.tv_usec = 500 * 1000;
179
180 fd_set fds;
181 FD_ZERO(&fds);
182 FD_SET(g_unix_socket, &fds);
183 int retval = select(g_unix_socket + 1, &fds, NULL, NULL, &tv);
184 if (retval > 0 && FD_ISSET(g_unix_socket, &fds)) {
185 int cc = accept(g_unix_socket, NULL, NULL);
186 if (cc > g_max_fd_ever) {
187 g_max_fd_ever = cc;
188 }
189 if (fcntl(cc, F_SETFD, FD_CLOEXEC) < 0) {
190 logger(LG_INFO, "Cannot set FD_CLOEXEC on client socket: %s",
191 strerror(errno));
192 }
193 queue_add_connection(cc); // closes fd
194 g_num_queued_connections++;
195 g_counters[COUNTER_CONNECTIONS]++;
196 }
197 }
198 logger(LG_INFO, "Socket thread has terminated");
199 return voidp;
200 }
201
client_thread(void * data)202 void *client_thread(void *data __attribute__((__unused__))) {
203 void *output_buffer = create_outputbuffer();
204
205 while (!g_should_terminate) {
206 int cc = queue_pop_connection();
207 g_num_queued_connections--;
208 g_num_active_connections++;
209 if (cc >= 0) {
210 if (g_debug_level >= 2) {
211 logger(LG_INFO, "Accepted client connection on fd %d", cc);
212 }
213 void *input_buffer = create_inputbuffer(cc, &g_should_terminate);
214 int keepalive = 1;
215 unsigned requestnr = 1;
216 while (keepalive) {
217 if (g_debug_level >= 2 && requestnr > 1) {
218 logger(LG_INFO, "Handling request %d on same connection",
219 requestnr);
220 }
221 keepalive = store_answer_request(input_buffer, output_buffer);
222 flush_output_buffer(output_buffer, cc, &g_should_terminate);
223 g_counters[COUNTER_REQUESTS]++;
224 requestnr++;
225 }
226 delete_inputbuffer(input_buffer);
227 close(cc);
228 }
229 g_num_active_connections--;
230 }
231 delete_outputbuffer(output_buffer);
232 return voidp;
233 }
234
start_threads()235 void start_threads() {
236 count_hosts();
237 count_services();
238
239 if (!g_thread_running) {
240 /* start thread that listens on socket */
241 pthread_atfork(livestatus_count_fork, NULL,
242 livestatus_cleanup_after_fork);
243 pthread_create(&g_mainthread_id, 0, main_thread, (void *)0);
244 if (g_debug_level > 0) {
245 logger(LG_INFO, "Starting %d client threads", g_num_clientthreads);
246 }
247
248 int t;
249 g_clientthread_id =
250 (pthread_t *)malloc(sizeof(pthread_t) * g_num_clientthreads);
251 pthread_attr_t attr;
252 pthread_attr_init(&attr);
253 size_t defsize;
254 if (g_debug_level >= 2 &&
255 0 == pthread_attr_getstacksize(&attr, &defsize)) {
256 logger(LG_INFO, "Default stack size is %lu", defsize);
257 }
258 if (0 != pthread_attr_setstacksize(&attr, g_thread_stack_size)) {
259 logger(LG_INFO, "Error: Cannot set thread stack size to %lu",
260 g_thread_stack_size);
261 } else {
262 if (g_debug_level >= 2) {
263 logger(LG_INFO, "Setting thread stack size to %lu",
264 g_thread_stack_size);
265 }
266 }
267 for (t = 0; t < g_num_clientthreads; t++) {
268 pthread_create(&g_clientthread_id[t], &attr, client_thread,
269 (void *)0);
270 }
271
272 g_thread_running = 1;
273 pthread_attr_destroy(&attr);
274 }
275 }
276
terminate_threads()277 void terminate_threads() {
278 if (g_thread_running) {
279 g_should_terminate = true;
280 logger(LG_INFO, "Waiting for main to terminate...");
281 pthread_join(g_mainthread_id, NULL);
282 logger(LG_INFO, "Waiting for client threads to terminate...");
283 queue_terminate();
284 int t;
285 for (t = 0; t < g_num_clientthreads; t++) {
286 if (0 != pthread_join(g_clientthread_id[t], NULL)) {
287 logger(LG_INFO, "Warning: could not join thread no. %d", t);
288 }
289 }
290 if (g_debug_level > 0) {
291 logger(LG_INFO, "Main thread + %d client threads have finished",
292 g_num_clientthreads);
293 }
294 g_thread_running = 0;
295 g_should_terminate = false;
296 }
297 free(g_clientthread_id);
298 }
299
open_unix_socket()300 int open_unix_socket() {
301 struct stat st;
302 if (0 == stat(g_socket_path, &st)) {
303 if (0 == unlink(g_socket_path)) {
304 logger(LG_DEBUG, "Removed old left over socket file %s",
305 g_socket_path);
306 } else {
307 logger(LG_ALERT, "Cannot remove in the way file %s: %s",
308 g_socket_path, strerror(errno));
309 return false;
310 }
311 }
312
313 g_unix_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
314 g_max_fd_ever = g_unix_socket;
315 if (g_unix_socket < 0) {
316 logger(LG_CRIT, "Unable to create UNIX socket: %s", strerror(errno));
317 return false;
318 }
319
320 // Imortant: close on exec -> check plugins must not inherit it!
321 if (fcntl(g_unix_socket, F_SETFD, FD_CLOEXEC) < 0) {
322 logger(LG_INFO, "Cannot set FD_CLOEXEC on socket: %s", strerror(errno));
323 }
324
325 // Bind it to its address. This creates the file with the name g_socket_path
326 struct sockaddr_un sockaddr;
327 sockaddr.sun_family = AF_LOCAL;
328 strncpy(sockaddr.sun_path, g_socket_path, sizeof(sockaddr.sun_path));
329 if (bind(g_unix_socket, (struct sockaddr *)&sockaddr, SUN_LEN(&sockaddr)) <
330 0) {
331 logger(LG_ERR, "Unable to bind adress %s to UNIX socket: %s",
332 g_socket_path, strerror(errno));
333 close(g_unix_socket);
334 return false;
335 }
336
337 // Make writable group members (fchmod didn't do nothing for me. Don't know
338 // why!)
339 if (0 != chmod(g_socket_path, 0660)) {
340 logger(LG_ERR, "Cannot chown unix socket at %s to 0660: %s",
341 g_socket_path, strerror(errno));
342 close(g_unix_socket);
343 return false;
344 }
345
346 if (0 != listen(g_unix_socket, 3 /* backlog */)) {
347 logger(LG_ERR, "Cannot listen to unix socket at %s: %s", g_socket_path,
348 strerror(errno));
349 close(g_unix_socket);
350 return false;
351 }
352
353 if (g_debug_level > 0) {
354 logger(LG_INFO, "Opened UNIX socket %s\n", g_socket_path);
355 }
356 return true;
357 }
358
close_unix_socket()359 void close_unix_socket() {
360 unlink(g_socket_path);
361 if (g_unix_socket >= 0) {
362 close(g_unix_socket);
363 g_unix_socket = -1;
364 }
365 }
366
broker_host(int event_type,void * data)367 int broker_host(int event_type __attribute__((__unused__)),
368 void *data __attribute__((__unused__))) {
369 g_counters[COUNTER_NEB_CALLBACKS]++;
370 return 0;
371 }
372
broker_check(int event_type,void * data)373 int broker_check(int event_type, void *data) {
374 int result = NEB_OK;
375 if (event_type == NEBCALLBACK_SERVICE_CHECK_DATA) {
376 nebstruct_service_check_data *c = (nebstruct_service_check_data *)data;
377 if (c->type == NEBTYPE_SERVICECHECK_PROCESSED) {
378 g_counters[COUNTER_SERVICE_CHECKS]++;
379 }
380 } else if (event_type == NEBCALLBACK_HOST_CHECK_DATA) {
381 nebstruct_host_check_data *c = (nebstruct_host_check_data *)data;
382 if (c->type == NEBTYPE_HOSTCHECK_PROCESSED) {
383 g_counters[COUNTER_HOST_CHECKS]++;
384 }
385 }
386 trigger_notify_all(trigger_check());
387 return result;
388 }
389
broker_comment(int event_type,void * data)390 int broker_comment(int event_type __attribute__((__unused__)), void *data) {
391 nebstruct_comment_data *co = (nebstruct_comment_data *)data;
392 store_register_comment(co);
393 g_counters[COUNTER_NEB_CALLBACKS]++;
394 trigger_notify_all(trigger_comment());
395 return 0;
396 }
397
broker_downtime(int event_type,void * data)398 int broker_downtime(int event_type __attribute__((__unused__)), void *data) {
399 nebstruct_downtime_data *dt = (nebstruct_downtime_data *)data;
400 store_register_downtime(dt);
401 g_counters[COUNTER_NEB_CALLBACKS]++;
402 trigger_notify_all(trigger_downtime());
403 return 0;
404 }
405
broker_log(int event_type,void * data)406 int broker_log(int event_type __attribute__((__unused__)),
407 void *data __attribute__((__unused__))) {
408 g_counters[COUNTER_NEB_CALLBACKS]++;
409 g_counters[COUNTER_LOG_MESSAGES]++;
410 trigger_notify_all(trigger_log());
411 return 0;
412 }
413
broker_command(int event_type,void * data)414 int broker_command(int event_type __attribute__((__unused__)), void *data) {
415 nebstruct_external_command_data *sc =
416 (nebstruct_external_command_data *)data;
417 if (sc->type == NEBTYPE_EXTERNALCOMMAND_START) {
418 g_counters[COUNTER_COMMANDS]++;
419 }
420 g_counters[COUNTER_NEB_CALLBACKS]++;
421 trigger_notify_all(trigger_command());
422 return 0;
423 }
424
broker_state(int event_type,void * data)425 int broker_state(int event_type __attribute__((__unused__)),
426 void *data __attribute__((__unused__))) {
427 g_counters[COUNTER_NEB_CALLBACKS]++;
428 trigger_notify_all(trigger_state());
429 return 0;
430 }
431
broker_program(int event_type,void * data)432 int broker_program(int event_type __attribute__((__unused__)),
433 void *data __attribute__((__unused__))) {
434 g_counters[COUNTER_NEB_CALLBACKS]++;
435 trigger_notify_all(trigger_program());
436 return 0;
437 }
438
get_downtime_comment(char * host_name,char * svc_desc)439 char *get_downtime_comment(char *host_name, char *svc_desc) {
440 char *comment;
441 int matches = 0;
442 scheduled_downtime *dt_list = scheduled_downtime_list;
443 while (dt_list != NULL) {
444 if (dt_list->type == HOST_DOWNTIME) {
445 if (strcmp(dt_list->host_name, host_name) == 0) {
446 matches++;
447 comment = dt_list->comment;
448 }
449 }
450 if (svc_desc != NULL && dt_list->type == SERVICE_DOWNTIME) {
451 if (strcmp(dt_list->host_name, host_name) == 0 &&
452 strcmp(dt_list->service_description, svc_desc) == 0) {
453 matches++;
454 comment = dt_list->comment;
455 }
456 }
457 dt_list = dt_list->next;
458 }
459 return matches == 0 ? "No comment"
460 : matches > 1 ? "Multiple Downtime Comments" : comment;
461 }
462
livestatus_log_initial_states()463 void livestatus_log_initial_states() {
464 // Log DOWNTIME hosts
465 host *h = (host *)host_list;
466 char buffer[8192];
467
468 while (h) {
469 if (h->scheduled_downtime_depth > 0) {
470 snprintf(buffer, sizeof(buffer),
471 "HOST DOWNTIME ALERT: %s;STARTED;%s", h->name,
472 get_downtime_comment(h->name, NULL));
473 write_to_all_logs(buffer, LG_INFO);
474 }
475 h = h->next;
476 }
477 // Log DOWNTIME services
478 service *s = (service *)service_list;
479 while (s) {
480 if (s->scheduled_downtime_depth > 0) {
481 snprintf(buffer, sizeof(buffer),
482 "SERVICE DOWNTIME ALERT: %s;%s;STARTED;%s", s->host_name,
483 s->description,
484 get_downtime_comment(s->host_name, s->description));
485 write_to_all_logs(buffer, LG_INFO);
486 }
487 s = s->next;
488 }
489 // Log TIMERPERIODS
490 log_timeperiods_cache();
491 }
492
broker_event(int event_type,void * data)493 int broker_event(int event_type __attribute__((__unused__)), void *data) {
494 g_counters[COUNTER_NEB_CALLBACKS]++;
495 struct nebstruct_timed_event_struct *ts =
496 (struct nebstruct_timed_event_struct *)data;
497 if (ts->event_type == EVENT_LOG_ROTATION) {
498 if (g_thread_running == 1) {
499 livestatus_log_initial_states();
500 } else if (log_initial_states == 1) {
501 write_to_all_logs("logging initial states",
502 LG_INFO); // initial info during startup
503 }
504 }
505 update_timeperiods_cache(ts->timestamp.tv_sec);
506 return 0;
507 }
508
broker_process(int event_type,void * data)509 int broker_process(int event_type __attribute__((__unused__)), void *data) {
510 struct nebstruct_process_struct *ps =
511 (struct nebstruct_process_struct *)data;
512 if (ps->type == NEBTYPE_PROCESS_EVENTLOOPSTART) {
513 update_timeperiods_cache(time(0));
514 start_threads();
515 }
516 return 0;
517 }
518
verify_event_broker_options()519 int verify_event_broker_options() {
520 int errors = 0;
521 if (!(event_broker_options & BROKER_PROGRAM_STATE)) {
522 logger(LG_CRIT,
523 "need BROKER_PROGRAM_STATE (%i) event_broker_option enabled to "
524 "work.",
525 BROKER_PROGRAM_STATE);
526 errors++;
527 }
528 if (!(event_broker_options & BROKER_TIMED_EVENTS)) {
529 logger(LG_CRIT,
530 "need BROKER_TIMED_EVENTS (%i) event_broker_option enabled to "
531 "work.",
532 BROKER_TIMED_EVENTS);
533 errors++;
534 }
535 if (!(event_broker_options & BROKER_SERVICE_CHECKS)) {
536 logger(LG_CRIT,
537 "need BROKER_SERVICE_CHECKS (%i) event_broker_option enabled to "
538 "work.",
539 BROKER_SERVICE_CHECKS);
540 errors++;
541 }
542 if (!(event_broker_options & BROKER_HOST_CHECKS)) {
543 logger(
544 LG_CRIT,
545 "need BROKER_HOST_CHECKS (%i) event_broker_option enabled to work.",
546 BROKER_HOST_CHECKS);
547 errors++;
548 }
549 if (!(event_broker_options & BROKER_LOGGED_DATA)) {
550 logger(
551 LG_CRIT,
552 "need BROKER_LOGGED_DATA (%i) event_broker_option enabled to work.",
553 BROKER_LOGGED_DATA);
554 errors++;
555 }
556 if (!(event_broker_options & BROKER_COMMENT_DATA)) {
557 logger(LG_CRIT,
558 "need BROKER_COMMENT_DATA (%i) event_broker_option enabled to "
559 "work.",
560 BROKER_COMMENT_DATA);
561 errors++;
562 }
563 if (!(event_broker_options & BROKER_DOWNTIME_DATA)) {
564 logger(LG_CRIT,
565 "need BROKER_DOWNTIME_DATA (%i) event_broker_option enabled to "
566 "work.",
567 BROKER_DOWNTIME_DATA);
568 errors++;
569 }
570 if (!(event_broker_options & BROKER_STATUS_DATA)) {
571 logger(
572 LG_CRIT,
573 "need BROKER_STATUS_DATA (%i) event_broker_option enabled to work.",
574 BROKER_STATUS_DATA);
575 errors++;
576 }
577 if (!(event_broker_options & BROKER_ADAPTIVE_DATA)) {
578 logger(LG_CRIT,
579 "need BROKER_ADAPTIVE_DATA (%i) event_broker_option enabled to "
580 "work.",
581 BROKER_ADAPTIVE_DATA);
582 errors++;
583 }
584 if (!(event_broker_options & BROKER_EXTERNALCOMMAND_DATA)) {
585 logger(LG_CRIT,
586 "need BROKER_EXTERNALCOMMAND_DATA (%i) event_broker_option "
587 "enabled to work.",
588 BROKER_EXTERNALCOMMAND_DATA);
589 errors++;
590 }
591 if (!(event_broker_options & BROKER_STATECHANGE_DATA)) {
592 logger(LG_CRIT,
593 "need BROKER_STATECHANGE_DATA (%i) event_broker_option enabled "
594 "to work.",
595 BROKER_STATECHANGE_DATA);
596 errors++;
597 }
598
599 return errors == 0;
600 }
601
register_callbacks()602 void register_callbacks() {
603 neb_register_callback(NEBCALLBACK_HOST_STATUS_DATA, g_nagios_handle, 0,
604 broker_host); // Needed to start threads
605 neb_register_callback(NEBCALLBACK_COMMENT_DATA, g_nagios_handle, 0,
606 broker_comment); // dynamic data
607 neb_register_callback(NEBCALLBACK_DOWNTIME_DATA, g_nagios_handle, 0,
608 broker_downtime); // dynamic data
609 neb_register_callback(NEBCALLBACK_SERVICE_CHECK_DATA, g_nagios_handle, 0,
610 broker_check); // only for statistics
611 neb_register_callback(NEBCALLBACK_HOST_CHECK_DATA, g_nagios_handle, 0,
612 broker_check); // only for statistics
613 neb_register_callback(NEBCALLBACK_LOG_DATA, g_nagios_handle, 0,
614 broker_log); // only for trigger 'log'
615 neb_register_callback(NEBCALLBACK_EXTERNAL_COMMAND_DATA, g_nagios_handle, 0,
616 broker_command); // only for trigger 'command'
617 neb_register_callback(NEBCALLBACK_STATE_CHANGE_DATA, g_nagios_handle, 0,
618 broker_state); // only for trigger 'state'
619 neb_register_callback(NEBCALLBACK_ADAPTIVE_PROGRAM_DATA, g_nagios_handle, 0,
620 broker_program); // only for trigger 'program'
621 neb_register_callback(NEBCALLBACK_PROCESS_DATA, g_nagios_handle, 0,
622 broker_process); // used for starting threads
623 neb_register_callback(NEBCALLBACK_TIMED_EVENT_DATA, g_nagios_handle, 0,
624 broker_event); // used for timeperiods cache
625 }
626
deregister_callbacks()627 void deregister_callbacks() {
628 neb_deregister_callback(NEBCALLBACK_HOST_STATUS_DATA, broker_host);
629 neb_deregister_callback(NEBCALLBACK_COMMENT_DATA, broker_comment);
630 neb_deregister_callback(NEBCALLBACK_DOWNTIME_DATA, broker_downtime);
631 neb_deregister_callback(NEBCALLBACK_SERVICE_CHECK_DATA, broker_check);
632 neb_deregister_callback(NEBCALLBACK_HOST_CHECK_DATA, broker_check);
633 neb_deregister_callback(NEBCALLBACK_LOG_DATA, broker_log);
634 neb_deregister_callback(NEBCALLBACK_EXTERNAL_COMMAND_DATA, broker_command);
635 neb_deregister_callback(NEBCALLBACK_STATE_CHANGE_DATA, broker_state);
636 neb_deregister_callback(NEBCALLBACK_ADAPTIVE_PROGRAM_DATA, broker_program);
637 neb_deregister_callback(NEBCALLBACK_PROCESS_DATA, broker_program);
638 neb_deregister_callback(NEBCALLBACK_TIMED_EVENT_DATA, broker_event);
639 }
640
check_path(const char * name,char * path)641 void check_path(const char *name, char *path) {
642 struct stat st;
643 if (0 == stat(path, &st)) {
644 if (0 != access(path, R_OK)) {
645 logger(LG_ERR, "%s '%s' not readable. Please fix permissions.",
646 name, path);
647 path[0] = 0; // disable
648 }
649 } else {
650 logger(LG_ERR, "%s '%s' not existing!", name, path);
651 path[0] = 0; // disable
652 }
653 }
654
livestatus_parse_arguments(const char * args_orig)655 void livestatus_parse_arguments(const char *args_orig) {
656 /* set default socket path */
657 strncpy(g_socket_path, DEFAULT_SOCKET_PATH, sizeof(g_socket_path));
658
659 /* set default path to our logfile to be in the same path as nagios.log */
660 strncpy(g_logfile_path, log_file,
661 sizeof(g_logfile_path) - 16 /* len of "livestatus.log" */);
662 char *slash = strrchr(g_logfile_path, '/');
663 if (!slash) {
664 strncpy(g_logfile_path, "/tmp/livestatus.log", 20);
665 } else {
666 strncpy(slash + 1, "livestatus.log", 15);
667 }
668
669 /* there is no default PNP path */
670 g_pnp_path[0] = 0;
671
672 if (!args_orig) {
673 return; // no arguments, use default options
674 }
675
676 char *args = strdup(args_orig);
677 char *token;
678 while (0 != (token = next_field(&args))) {
679 /* find = */
680 char *part = token;
681 char *left = next_token(&part, '=');
682 char *right = next_token(&part, 0);
683 if (!right) {
684 strncpy(g_socket_path, left, sizeof(g_socket_path));
685 } else {
686 if (!strcmp(left, "debug")) {
687 g_debug_level = atoi(right);
688 logger(LG_INFO, "Setting debug level to %d", g_debug_level);
689 } else if (!strcmp(left, "log_file")) {
690 strncpy(g_logfile_path, right, sizeof(g_logfile_path));
691 } else if (!strcmp(left, "max_cached_messages")) {
692 g_max_cached_messages = strtoul(right, 0, 10);
693 logger(LG_INFO,
694 "Setting max number of cached log messages to %lu",
695 g_max_cached_messages);
696 } else if (!strcmp(left, "max_lines_per_logfile")) {
697 g_max_lines_per_logfile = strtoul(right, 0, 10);
698 logger(LG_INFO, "Setting max number lines per logfile to %lu",
699 g_max_lines_per_logfile);
700 } else if (!strcmp(left, "thread_stack_size")) {
701 g_thread_stack_size = strtoul(right, 0, 10);
702 logger(LG_INFO, "Setting size of thread stacks to %lu",
703 g_thread_stack_size);
704 } else if (!strcmp(left, "max_response_size")) {
705 g_max_response_size = strtoul(right, 0, 10);
706 logger(LG_INFO,
707 "Setting maximum response size to %lu bytes (%.1f MB)",
708 g_max_response_size,
709 g_max_response_size / (1024.0 * 1024.0));
710 } else if (!strcmp(left, "num_client_threads")) {
711 int c = atoi(right);
712 if (c <= 0 || c > 1000) {
713 logger(LG_INFO,
714 "Error: Cannot set num_client_threads to %d. Must "
715 "be > 0 and <= 1000",
716 c);
717 } else {
718 logger(LG_INFO, "Setting number of client threads to %d",
719 c);
720 g_num_clientthreads = c;
721 }
722 } else if (!strcmp(left, "query_timeout")) {
723 int c = atoi(right);
724 if (c < 0) {
725 logger(LG_INFO, "Error: query_timeout must be >= 0");
726 } else {
727 g_query_timeout_msec = c;
728 if (c == 0) {
729 logger(LG_INFO, "Disabled query timeout!");
730 } else {
731 logger(LG_INFO,
732 "Setting timeout for reading a query to %d ms",
733 c);
734 }
735 }
736 } else if (!strcmp(left, "idle_timeout")) {
737 int c = atoi(right);
738 if (c < 0) {
739 logger(LG_INFO, "Error: idle_timeout must be >= 0");
740 } else {
741 g_idle_timeout_msec = c;
742 if (c == 0) {
743 logger(LG_INFO, "Disabled idle timeout!");
744 } else {
745 logger(LG_INFO, "Setting idle timeout to %d ms", c);
746 }
747 }
748 } else if (!strcmp(left, "service_authorization")) {
749 if (!strcmp(right, "strict")) {
750 g_service_authorization = AUTH_STRICT;
751 } else if (!strcmp(right, "loose")) {
752 g_service_authorization = AUTH_LOOSE;
753 } else {
754 logger(LG_INFO,
755 "Invalid service authorization mode. Allowed are "
756 "strict and loose.");
757 }
758 } else if (!strcmp(left, "group_authorization")) {
759 if (!strcmp(right, "strict")) {
760 g_group_authorization = AUTH_STRICT;
761 } else if (!strcmp(right, "loose")) {
762 g_group_authorization = AUTH_LOOSE;
763 } else {
764 logger(LG_INFO,
765 "Invalid group authorization mode. Allowed are "
766 "strict and loose.");
767 }
768 } else if (!strcmp(left, "pnp_path")) {
769 strncpy(g_pnp_path, right, sizeof(pnp_path_storage) - 1);
770 // make sure, that trailing slash is always there
771 if (right[strlen(right) - 1] != '/') {
772 strncat(g_pnp_path, "/",
773 sizeof(pnp_path_storage) - strlen(g_pnp_path) - 1);
774 }
775 check_path("PNP perfdata directory", g_pnp_path);
776 } else if (!strcmp(left, "mk_inventory_path")) {
777 strncpy(g_mk_inventory_path, right,
778 sizeof(g_mk_inventory_path) - 1);
779 if (right[strlen(right) - 1] != '/') {
780 strncat(g_mk_inventory_path, "/",
781 sizeof(g_mk_inventory_path) -
782 strlen(g_mk_inventory_path) -
783 1); // make sure, that trailing slash is always
784 }
785 // there
786 check_path("Check_MK Inventory directory", g_mk_inventory_path);
787 } else if (!strcmp(left, "data_encoding")) {
788 if (!strcmp(right, "utf8")) {
789 g_data_encoding = ENCODING_UTF8;
790 } else if (!strcmp(right, "latin1")) {
791 g_data_encoding = ENCODING_LATIN1;
792 } else if (!strcmp(right, "mixed")) {
793 g_data_encoding = ENCODING_MIXED;
794 } else {
795 logger(LG_INFO,
796 "Invalid data_encoding %s. Allowed are utf8, latin1 "
797 "and mixed.",
798 right);
799 }
800 } else if (!strcmp(left, "livecheck")) {
801 logger(LG_INFO,
802 "Livecheck has been removed from Livestatus. Sorry.");
803 } else if (!strcmp(left, "disable_statehist_filtering")) {
804 g_disable_statehist_filtering = atoi(right);
805 } else {
806 logger(LG_INFO, "Ignoring invalid option %s=%s", left, right);
807 }
808 }
809 }
810 // free(args); won't free, since we use pointers?
811 }
812
omd_advertize()813 void omd_advertize() {
814 char *omd_site = getenv("OMD_SITE");
815 if (omd_site) {
816 if (g_debug_level > 0) {
817 logger(LG_INFO, "Running on OMD site %s. Cool.", omd_site);
818 }
819 } else {
820 logger(LG_INFO,
821 "Hint: please try out OMD - the Open Monitoring Distribution");
822 logger(LG_INFO, "Please visit OMD at http://omdistro.org");
823 }
824 }
825
826 /* this function gets called when the module is loaded by the event broker */
827 /* cppcheck-suppress unusedFunction */
nebmodule_init(int flags,char * args,void * handle)828 int nebmodule_init(int flags __attribute__((__unused__)), char *args,
829 void *handle) {
830 g_nagios_handle = handle;
831 livestatus_parse_arguments(args);
832 open_logfile();
833
834 logger(LG_INFO, "Livestatus %s by Mathias Kettner. Socket: '%s'", VERSION,
835 g_socket_path);
836 logger(LG_INFO, "Please visit us at http://mathias-kettner.de/");
837
838 omd_advertize();
839
840 if (!open_unix_socket()) {
841 return 1;
842 }
843
844 if (!verify_event_broker_options()) {
845 logger(LG_CRIT, "Fatal: bailing out. Please fix event_broker_options.");
846 logger(LG_CRIT,
847 "Hint: your event_broker_options are set to %d. Try setting it "
848 "to -1.",
849 event_broker_options);
850 return 1;
851 }
852 if (g_debug_level > 0) {
853 logger(LG_INFO,
854 "Your event_broker_options are sufficient for livestatus..");
855 }
856
857 if (enable_environment_macros == 1) {
858 logger(LG_INFO,
859 "Warning: environment_macros are enabled. This might decrease "
860 "the overall nagios performance");
861 }
862
863 store_init();
864 register_callbacks();
865
866 /* Unfortunately, we cannot start our socket thread right now.
867 Nagios demonizes *after* having loaded the NEB modules. When
868 demonizing we are losing our thread. Therefore, we create the
869 thread the first time one of our callbacks is called. Before
870 that happens, we haven't got any data anyway... */
871
872 logger(LG_INFO, "Finished initialization. Further log messages go to %s",
873 g_logfile_path);
874 return 0;
875 }
876
877 /* cppcheck-suppress unusedFunction */
nebmodule_deinit(int flags,int reason)878 int nebmodule_deinit(int flags __attribute__((__unused__)),
879 int reason __attribute__((__unused__))) {
880 logger(LG_INFO, "deinitializing");
881 terminate_threads();
882 close_unix_socket();
883 store_deinit();
884 deregister_callbacks();
885 close_logfile();
886 return 0;
887 }
888