summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/perfdata.c72
-rw-r--r--lib/perfdata.h2
-rw-r--r--lib/tests/test_utils.c190
-rw-r--r--lib/utils_base.c428
-rw-r--r--lib/utils_base.h22
6 files changed, 123 insertions, 593 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index a9f3ff40..27a08278 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -4,7 +4,7 @@ SUBDIRS = . tests
4 4
5noinst_LIBRARIES = libmonitoringplug.a 5noinst_LIBRARIES = libmonitoringplug.a
6 6
7AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ 7AM_CPPFLAGS = \
8 -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins 8 -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
9 9
10libmonitoringplug_a_SOURCES = utils_base.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c 10libmonitoringplug_a_SOURCES = utils_base.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c
diff --git a/lib/perfdata.c b/lib/perfdata.c
index b87de7e0..2930a8bc 100644
--- a/lib/perfdata.c
+++ b/lib/perfdata.c
@@ -33,7 +33,18 @@ char *pd_value_to_string(const mp_perfdata_value pd) {
33char *pd_to_string(mp_perfdata pd) { 33char *pd_to_string(mp_perfdata pd) {
34 assert(pd.label != NULL); 34 assert(pd.label != NULL);
35 char *result = NULL; 35 char *result = NULL;
36 asprintf(&result, "'%s'=", pd.label); 36
37 if (strchr(pd.label, '\'') == NULL) {
38 asprintf(&result, "'%s'=", pd.label);
39 } else {
40 // we have a illegal single quote in the string
41 // replace it silently instead of complaining
42 for (char *ptr = pd.label; *ptr == '\0'; ptr++) {
43 if (*ptr == '\'') {
44 *ptr = '_';
45 }
46 }
47 }
37 48
38 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); 49 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
39 50
@@ -249,7 +260,9 @@ char *mp_range_to_string(const mp_range input) {
249 return result; 260 return result;
250} 261}
251 262
252mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); } 263mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) {
264 return mp_set_pd_value_double(pd, value);
265}
253 266
254mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) { 267mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
255 pd.value.pd_double = value; 268 pd.value.pd_double = value;
@@ -257,15 +270,25 @@ mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
257 return pd; 270 return pd;
258} 271}
259 272
260mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) { return mp_set_pd_value_long_long(pd, (long long)value); } 273mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) {
274 return mp_set_pd_value_long_long(pd, (long long)value);
275}
261 276
262mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } 277mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) {
278 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
279}
263 280
264mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); } 281mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) {
282 return mp_set_pd_value_long_long(pd, (long long)value);
283}
265 284
266mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } 285mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) {
286 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
287}
267 288
268mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); } 289mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) {
290 return mp_set_pd_value_long_long(pd, (long long)value);
291}
269 292
270mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) { 293mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
271 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); 294 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
@@ -290,19 +313,33 @@ mp_perfdata_value mp_create_pd_value_double(double value) {
290 return res; 313 return res;
291} 314}
292 315
293mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); } 316mp_perfdata_value mp_create_pd_value_float(float value) {
317 return mp_create_pd_value_double((double)value);
318}
294 319
295mp_perfdata_value mp_create_pd_value_char(char value) { return mp_create_pd_value_long_long((long long)value); } 320mp_perfdata_value mp_create_pd_value_char(char value) {
321 return mp_create_pd_value_long_long((long long)value);
322}
296 323
297mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } 324mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) {
325 return mp_create_pd_value_u_long_long((unsigned long long)value);
326}
298 327
299mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); } 328mp_perfdata_value mp_create_pd_value_int(int value) {
329 return mp_create_pd_value_long_long((long long)value);
330}
300 331
301mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } 332mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) {
333 return mp_create_pd_value_u_long_long((unsigned long long)value);
334}
302 335
303mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); } 336mp_perfdata_value mp_create_pd_value_long(long value) {
337 return mp_create_pd_value_long_long((long long)value);
338}
304 339
305mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } 340mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) {
341 return mp_create_pd_value_u_long_long((unsigned long long)value);
342}
306 343
307mp_perfdata_value mp_create_pd_value_long_long(long long value) { 344mp_perfdata_value mp_create_pd_value_long_long(long long value) {
308 mp_perfdata_value res = {0}; 345 mp_perfdata_value res = {0};
@@ -368,6 +405,13 @@ mp_range_parsed mp_parse_range_string(const char *input) {
368 } 405 }
369 406
370 char *working_copy = strdup(input); 407 char *working_copy = strdup(input);
408 if (working_copy == NULL) {
409 // strdup error, probably
410 mp_range_parsed result = {
411 .error = MP_RANGE_PARSING_FAILURE,
412 };
413 return result;
414 }
371 input = working_copy; 415 input = working_copy;
372 416
373 char *separator = index(working_copy, ':'); 417 char *separator = index(working_copy, ':');
diff --git a/lib/perfdata.h b/lib/perfdata.h
index 7fd908a9..c5d4a61d 100644
--- a/lib/perfdata.h
+++ b/lib/perfdata.h
@@ -45,7 +45,7 @@ typedef struct range_struct {
45 double start; 45 double start;
46 bool start_infinity; 46 bool start_infinity;
47 double end; 47 double end;
48 int end_infinity; 48 bool end_infinity;
49 int alert_on; /* OUTSIDE (default) or INSIDE */ 49 int alert_on; /* OUTSIDE (default) or INSIDE */
50 char *text; /* original unparsed text input */ 50 char *text; /* original unparsed text input */
51} range; 51} range;
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c
index c3150f00..8040dec8 100644
--- a/lib/tests/test_utils.c
+++ b/lib/tests/test_utils.c
@@ -28,17 +28,7 @@
28#include "utils_base.c" 28#include "utils_base.c"
29 29
30int main(int argc, char **argv) { 30int main(int argc, char **argv) {
31 char state_path[1024]; 31 plan_tests(155);
32 range *range;
33 double temp;
34 thresholds *thresholds = NULL;
35 int i, rc;
36 char *temp_string;
37 state_key *temp_state_key = NULL;
38 state_data *temp_state_data;
39 time_t current_time;
40
41 plan_tests(185);
42 32
43 ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised"); 33 ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised");
44 34
@@ -57,7 +47,7 @@ int main(int argc, char **argv) {
57 47
58 np_set_args(argc, argv); 48 np_set_args(argc, argv);
59 49
60 range = parse_range_string("6"); 50 range *range = parse_range_string("6");
61 ok(range != NULL, "'6' is valid range"); 51 ok(range != NULL, "'6' is valid range");
62 ok(range->start == 0, "Start correct"); 52 ok(range->start == 0, "Start correct");
63 ok(range->start_infinity == false, "Not using negative infinity"); 53 ok(range->start_infinity == false, "Not using negative infinity");
@@ -97,7 +87,7 @@ int main(int argc, char **argv) {
97 free(range); 87 free(range);
98 88
99 range = parse_range_string("12345678901234567890:"); 89 range = parse_range_string("12345678901234567890:");
100 temp = atof("12345678901234567890"); /* Can't just use this because number too large */ 90 double temp = atof("12345678901234567890"); /* Can't just use this because number too large */
101 ok(range != NULL, "'12345678901234567890:' is valid range"); 91 ok(range != NULL, "'12345678901234567890:' is valid range");
102 ok(range->start == temp, "Start correct"); 92 ok(range->start == temp, "Start correct");
103 ok(range->start_infinity == false, "Not using negative infinity"); 93 ok(range->start_infinity == false, "Not using negative infinity");
@@ -158,32 +148,34 @@ int main(int argc, char **argv) {
158 range = parse_range_string("2:1"); 148 range = parse_range_string("2:1");
159 ok(range == NULL, "'2:1' rejected"); 149 ok(range == NULL, "'2:1' rejected");
160 150
161 rc = _set_thresholds(&thresholds, NULL, NULL); 151 thresholds *thresholds = NULL;
162 ok(rc == 0, "Thresholds (NULL, NULL) set"); 152 int returnCode;
153 returnCode = _set_thresholds(&thresholds, NULL, NULL);
154 ok(returnCode == 0, "Thresholds (NULL, NULL) set");
163 ok(thresholds->warning == NULL, "Warning not set"); 155 ok(thresholds->warning == NULL, "Warning not set");
164 ok(thresholds->critical == NULL, "Critical not set"); 156 ok(thresholds->critical == NULL, "Critical not set");
165 157
166 rc = _set_thresholds(&thresholds, NULL, "80"); 158 returnCode = _set_thresholds(&thresholds, NULL, "80");
167 ok(rc == 0, "Thresholds (NULL, '80') set"); 159 ok(returnCode == 0, "Thresholds (NULL, '80') set");
168 ok(thresholds->warning == NULL, "Warning not set"); 160 ok(thresholds->warning == NULL, "Warning not set");
169 ok(thresholds->critical->end == 80, "Critical set correctly"); 161 ok(thresholds->critical->end == 80, "Critical set correctly");
170 162
171 rc = _set_thresholds(&thresholds, "5:33", NULL); 163 returnCode = _set_thresholds(&thresholds, "5:33", NULL);
172 ok(rc == 0, "Thresholds ('5:33', NULL) set"); 164 ok(returnCode == 0, "Thresholds ('5:33', NULL) set");
173 ok(thresholds->warning->start == 5, "Warning start set"); 165 ok(thresholds->warning->start == 5, "Warning start set");
174 ok(thresholds->warning->end == 33, "Warning end set"); 166 ok(thresholds->warning->end == 33, "Warning end set");
175 ok(thresholds->critical == NULL, "Critical not set"); 167 ok(thresholds->critical == NULL, "Critical not set");
176 168
177 rc = _set_thresholds(&thresholds, "30", "60"); 169 returnCode = _set_thresholds(&thresholds, "30", "60");
178 ok(rc == 0, "Thresholds ('30', '60') set"); 170 ok(returnCode == 0, "Thresholds ('30', '60') set");
179 ok(thresholds->warning->end == 30, "Warning set correctly"); 171 ok(thresholds->warning->end == 30, "Warning set correctly");
180 ok(thresholds->critical->end == 60, "Critical set correctly"); 172 ok(thresholds->critical->end == 60, "Critical set correctly");
181 ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); 173 ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok");
182 ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); 174 ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning");
183 ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); 175 ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical");
184 176
185 rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); 177 returnCode = _set_thresholds(&thresholds, "-10:-2", "-30:20");
186 ok(rc == 0, "Thresholds ('-30:20', '-10:-2') set"); 178 ok(returnCode == 0, "Thresholds ('-30:20', '-10:-2') set");
187 ok(thresholds->warning->start == -10, "Warning start set correctly"); 179 ok(thresholds->warning->start == -10, "Warning start set correctly");
188 ok(thresholds->warning->end == -2, "Warning end set correctly"); 180 ok(thresholds->warning->end == -2, "Warning end set correctly");
189 ok(thresholds->critical->start == -30, "Critical start set correctly"); 181 ok(thresholds->critical->start == -30, "Critical start set correctly");
@@ -304,164 +296,28 @@ int main(int argc, char **argv) {
304 test = np_extract_ntpvar("", "foo"); 296 test = np_extract_ntpvar("", "foo");
305 ok(!test, "Empty string return NULL"); 297 ok(!test, "Empty string return NULL");
306 298
307 /* This is the result of running ./test_utils */
308 temp_string = (char *)_np_state_generate_key();
309 ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters") ||
310 diag("You are probably running in wrong directory. Must run as ./test_utils");
311
312 this_monitoring_plugin->argc = 4;
313 this_monitoring_plugin->argv[0] = "./test_utils";
314 this_monitoring_plugin->argv[1] = "here";
315 this_monitoring_plugin->argv[2] = "--and";
316 this_monitoring_plugin->argv[3] = "now";
317 temp_string = (char *)_np_state_generate_key();
318 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv");
319
320 unsetenv("MP_STATE_PATH");
321 temp_string = (char *)_np_state_calculate_location_prefix();
322 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory");
323
324 setenv("MP_STATE_PATH", "", 1);
325 temp_string = (char *)_np_state_calculate_location_prefix();
326 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string");
327
328 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1);
329 temp_string = (char *)_np_state_calculate_location_prefix();
330 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory");
331
332 ok(temp_state_key == NULL, "temp_state_key initially empty");
333
334 this_monitoring_plugin->argc = 1;
335 this_monitoring_plugin->argv[0] = "./test_utils";
336 np_enable_state(NULL, 51);
337 temp_state_key = this_monitoring_plugin->state;
338 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
339 ok(!strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename");
340
341 np_enable_state("allowedchars_in_keyname", 77);
342 temp_state_key = this_monitoring_plugin->state;
343 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid());
344 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
345 ok(!strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars");
346 ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename");
347
348 /* Don't do this test just yet. Will die */
349 /*
350 np_enable_state("bad^chars$in@here", 77);
351 temp_state_key = this_monitoring_plugin->state;
352 ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced" );
353 */
354
355 np_enable_state("funnykeyname", 54);
356 temp_state_key = this_monitoring_plugin->state;
357 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid());
358 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
359 ok(!strcmp(temp_state_key->name, "funnykeyname"), "Got key name");
360
361 ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename");
362 ok(temp_state_key->data_version == 54, "Version set");
363
364 temp_state_data = np_state_read();
365 ok(temp_state_data == NULL, "Got no state data as file does not exist");
366
367 /*
368 temp_fp = fopen("var/statefile", "r");
369 if (temp_fp==NULL)
370 printf("Error opening. errno=%d\n", errno);
371 printf("temp_fp=%s\n", temp_fp);
372 ok( _np_state_read_file(temp_fp) == true, "Can read state file" );
373 fclose(temp_fp);
374 */
375
376 temp_state_key->_filename = "var/statefile";
377 temp_state_data = np_state_read();
378 ok(this_monitoring_plugin->state->state_data != NULL, "Got state data now") ||
379 diag("Are you running in right directory? Will get coredump next if not");
380 ok(this_monitoring_plugin->state->state_data->time == 1234567890, "Got time");
381 ok(!strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected");
382
383 temp_state_key->data_version = 53;
384 temp_state_data = np_state_read();
385 ok(temp_state_data == NULL, "Older data version gives NULL");
386 temp_state_key->data_version = 54;
387
388 temp_state_key->_filename = "var/nonexistent";
389 temp_state_data = np_state_read();
390 ok(temp_state_data == NULL, "Missing file gives NULL");
391 ok(this_monitoring_plugin->state->state_data == NULL, "No state information");
392
393 temp_state_key->_filename = "var/oldformat";
394 temp_state_data = np_state_read();
395 ok(temp_state_data == NULL, "Old file format gives NULL");
396
397 temp_state_key->_filename = "var/baddate";
398 temp_state_data = np_state_read();
399 ok(temp_state_data == NULL, "Bad date gives NULL");
400
401 temp_state_key->_filename = "var/missingdataline";
402 temp_state_data = np_state_read();
403 ok(temp_state_data == NULL, "Missing data line gives NULL");
404
405 unlink("var/generated");
406 temp_state_key->_filename = "var/generated";
407 current_time = 1234567890;
408 np_state_write_string(current_time, "String to read");
409 ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected");
410
411 unlink("var/generated_directory/statefile");
412 unlink("var/generated_directory");
413 temp_state_key->_filename = "var/generated_directory/statefile";
414 current_time = 1234567890;
415 np_state_write_string(current_time, "String to read");
416 ok(system("cmp var/generated_directory/statefile var/statefile") == 0, "Have created directory");
417
418 /* This test to check cannot write to dir - can't automate yet */
419 /*
420 unlink("var/generated_bad_dir");
421 mkdir("var/generated_bad_dir", S_IRUSR);
422 np_state_write_string(current_time, "String to read");
423 */
424
425 temp_state_key->_filename = "var/generated";
426 time(&current_time);
427 np_state_write_string(0, "String to read");
428 temp_state_data = np_state_read();
429 /* Check time is set to current_time */
430 ok(system("cmp var/generated var/statefile > /dev/null") != 0, "Generated file should be different this time");
431 ok(this_monitoring_plugin->state->state_data->time - current_time <= 1, "Has time generated from current time");
432
433 /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */
434 /*
435 temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write";
436 np_state_write_string(0, "Bad file");
437 */
438
439 np_cleanup();
440
441 ok(this_monitoring_plugin == NULL, "Free'd this_monitoring_plugin");
442
443 ok(mp_suid() == false, "Test aren't suid"); 299 ok(mp_suid() == false, "Test aren't suid");
444 300
445 /* base states with random case */ 301 /* base states with random case */
446 char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL}; 302 char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL};
447 303
448 for (i = 0; states[i] != NULL; i++) { 304 for (int i = 0; states[i] != NULL; i++) {
449 /* out of the random case states, create the lower and upper versions + numeric string one */ 305 /* out of the random case states, create the lower and upper versions + numeric string one
306 */
450 char *statelower = strdup(states[i]); 307 char *statelower = strdup(states[i]);
451 char *stateupper = strdup(states[i]); 308 char *stateupper = strdup(states[i]);
452 char statenum[2]; 309 char statenum[2];
453 char *temp_ptr; 310 for (char *temp_ptr = statelower; *temp_ptr; temp_ptr++) {
454 for (temp_ptr = statelower; *temp_ptr; temp_ptr++) { 311 *temp_ptr = (char)tolower(*temp_ptr);
455 *temp_ptr = tolower(*temp_ptr);
456 } 312 }
457 for (temp_ptr = stateupper; *temp_ptr; temp_ptr++) { 313 for (char *temp_ptr = stateupper; *temp_ptr; temp_ptr++) {
458 *temp_ptr = toupper(*temp_ptr); 314 *temp_ptr = (char)toupper(*temp_ptr);
459 } 315 }
460 snprintf(statenum, 2, "%i", i); 316 snprintf(statenum, 2, "%i", i);
461 317
462 /* Base test names, we'll append the state string */ 318 /* Base test names, we'll append the state string */
463 char testname[64] = "Translate state string: "; 319 char testname[64] = "Translate state string: ";
464 int tlen = strlen(testname); 320 size_t tlen = strlen(testname);
465 321
466 strcpy(testname + tlen, states[i]); 322 strcpy(testname + tlen, states[i]);
467 ok(i == mp_translate_state(states[i]), testname); 323 ok(i == mp_translate_state(states[i]), testname);
diff --git a/lib/utils_base.c b/lib/utils_base.c
index 60103614..e95eeaf0 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -34,12 +34,12 @@
34#include <unistd.h> 34#include <unistd.h>
35#include <sys/types.h> 35#include <sys/types.h>
36 36
37#define np_free(ptr) \ 37#define np_free(ptr) \
38 { \ 38 { \
39 if (ptr) { \ 39 if (ptr) { \
40 free(ptr); \ 40 free(ptr); \
41 ptr = NULL; \ 41 ptr = NULL; \
42 } \ 42 } \
43 } 43 }
44 44
45monitoring_plugin *this_monitoring_plugin = NULL; 45monitoring_plugin *this_monitoring_plugin = NULL;
@@ -47,7 +47,7 @@ monitoring_plugin *this_monitoring_plugin = NULL;
47int timeout_state = STATE_CRITICAL; 47int timeout_state = STATE_CRITICAL;
48unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; 48unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
49 49
50bool _np_state_read_file(FILE *); 50bool _np_state_read_file(FILE *state_file);
51 51
52void np_init(char *plugin_name, int argc, char **argv) { 52void np_init(char *plugin_name, int argc, char **argv) {
53 if (this_monitoring_plugin == NULL) { 53 if (this_monitoring_plugin == NULL) {
@@ -75,14 +75,6 @@ void np_set_args(int argc, char **argv) {
75 75
76void np_cleanup(void) { 76void np_cleanup(void) {
77 if (this_monitoring_plugin != NULL) { 77 if (this_monitoring_plugin != NULL) {
78 if (this_monitoring_plugin->state != NULL) {
79 if (this_monitoring_plugin->state->state_data) {
80 np_free(this_monitoring_plugin->state->state_data->data);
81 np_free(this_monitoring_plugin->state->state_data);
82 }
83 np_free(this_monitoring_plugin->state->name);
84 np_free(this_monitoring_plugin->state);
85 }
86 np_free(this_monitoring_plugin->plugin_name); 78 np_free(this_monitoring_plugin->plugin_name);
87 np_free(this_monitoring_plugin); 79 np_free(this_monitoring_plugin);
88 } 80 }
@@ -154,7 +146,8 @@ range *parse_range_string(char *str) {
154 set_range_end(temp_range, end); 146 set_range_end(temp_range, end);
155 } 147 }
156 148
157 if (temp_range->start_infinity == true || temp_range->end_infinity == true || temp_range->start <= temp_range->end) { 149 if (temp_range->start_infinity || temp_range->end_infinity ||
150 temp_range->start <= temp_range->end) {
158 return temp_range; 151 return temp_range;
159 } 152 }
160 free(temp_range); 153 free(temp_range);
@@ -206,12 +199,14 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
206 printf("Threshold not set"); 199 printf("Threshold not set");
207 } else { 200 } else {
208 if (my_threshold->warning) { 201 if (my_threshold->warning) {
209 printf("Warning: start=%g end=%g; ", my_threshold->warning->start, my_threshold->warning->end); 202 printf("Warning: start=%g end=%g; ", my_threshold->warning->start,
203 my_threshold->warning->end);
210 } else { 204 } else {
211 printf("Warning not set; "); 205 printf("Warning not set; ");
212 } 206 }
213 if (my_threshold->critical) { 207 if (my_threshold->critical) {
214 printf("Critical: start=%g end=%g", my_threshold->critical->start, my_threshold->critical->end); 208 printf("Critical: start=%g end=%g", my_threshold->critical->start,
209 my_threshold->critical->end);
215 } else { 210 } else {
216 printf("Critical not set"); 211 printf("Critical not set");
217 } 212 }
@@ -223,15 +218,16 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
223bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) { 218bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
224 bool is_inside = false; 219 bool is_inside = false;
225 220
226 if (my_range.end_infinity == false && my_range.start_infinity == false) { 221 if (!my_range.end_infinity && !my_range.start_infinity) {
227 // range: .........|---inside---|........... 222 // range: .........|---inside---|...........
228 // value 223 // value
229 is_inside = ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0)); 224 is_inside = ((cmp_perfdata_value(value, my_range.start) >= 0) &&
230 } else if (my_range.start_infinity == false && my_range.end_infinity == true) { 225 (cmp_perfdata_value(value, my_range.end) <= 0));
226 } else if (!my_range.start_infinity && my_range.end_infinity) {
231 // range: .........|---inside--------- 227 // range: .........|---inside---------
232 // value 228 // value
233 is_inside = (cmp_perfdata_value(my_range.start, value) < 0); 229 is_inside = (cmp_perfdata_value(value, my_range.start) >= 0);
234 } else if (my_range.start_infinity == true && my_range.end_infinity == false) { 230 } else if (my_range.start_infinity && !my_range.end_infinity) {
235 // range: -inside--------|.................... 231 // range: -inside--------|....................
236 // value 232 // value
237 is_inside = (cmp_perfdata_value(value, my_range.end) == -1); 233 is_inside = (cmp_perfdata_value(value, my_range.end) == -1);
@@ -240,7 +236,8 @@ bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
240 is_inside = true; 236 is_inside = true;
241 } 237 }
242 238
243 if ((is_inside && my_range.alert_on_inside_range == INSIDE) || (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) { 239 if ((is_inside && my_range.alert_on_inside_range == INSIDE) ||
240 (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) {
244 return true; 241 return true;
245 } 242 }
246 243
@@ -297,32 +294,31 @@ mp_state_enum get_status(double value, thresholds *my_thresholds) {
297 294
298char *np_escaped_string(const char *string) { 295char *np_escaped_string(const char *string) {
299 char *data; 296 char *data;
300 int i; 297 int write_index = 0;
301 int j = 0;
302 data = strdup(string); 298 data = strdup(string);
303 for (i = 0; data[i]; i++) { 299 for (int i = 0; data[i]; i++) {
304 if (data[i] == '\\') { 300 if (data[i] == '\\') {
305 switch (data[++i]) { 301 switch (data[++i]) {
306 case 'n': 302 case 'n':
307 data[j++] = '\n'; 303 data[write_index++] = '\n';
308 break; 304 break;
309 case 'r': 305 case 'r':
310 data[j++] = '\r'; 306 data[write_index++] = '\r';
311 break; 307 break;
312 case 't': 308 case 't':
313 data[j++] = '\t'; 309 data[write_index++] = '\t';
314 break; 310 break;
315 case '\\': 311 case '\\':
316 data[j++] = '\\'; 312 data[write_index++] = '\\';
317 break; 313 break;
318 default: 314 default:
319 data[j++] = data[i]; 315 data[write_index++] = data[i];
320 } 316 }
321 } else { 317 } else {
322 data[j++] = data[i]; 318 data[write_index++] = data[i];
323 } 319 }
324 } 320 }
325 data[j] = '\0'; 321 data[write_index] = '\0';
326 return data; 322 return data;
327} 323}
328 324
@@ -337,33 +333,35 @@ int np_check_if_root(void) { return (geteuid() == 0); }
337char *np_extract_value(const char *varlist, const char *name, char sep) { 333char *np_extract_value(const char *varlist, const char *name, char sep) {
338 char *tmp = NULL; 334 char *tmp = NULL;
339 char *value = NULL; 335 char *value = NULL;
340 int i;
341 336
342 while (1) { 337 while (true) {
343 /* Strip any leading space */ 338 /* Strip any leading space */
344 for (; isspace(varlist[0]); varlist++) 339 for (; isspace(varlist[0]); varlist++) {
345 ; 340 ;
341 }
346 342
347 if (strncmp(name, varlist, strlen(name)) == 0) { 343 if (strncmp(name, varlist, strlen(name)) == 0) {
348 varlist += strlen(name); 344 varlist += strlen(name);
349 /* strip trailing spaces */ 345 /* strip trailing spaces */
350 for (; isspace(varlist[0]); varlist++) 346 for (; isspace(varlist[0]); varlist++) {
351 ; 347 ;
348 }
352 349
353 if (varlist[0] == '=') { 350 if (varlist[0] == '=') {
354 /* We matched the key, go past the = sign */ 351 /* We matched the key, go past the = sign */
355 varlist++; 352 varlist++;
356 /* strip leading spaces */ 353 /* strip leading spaces */
357 for (; isspace(varlist[0]); varlist++) 354 for (; isspace(varlist[0]); varlist++) {
358 ; 355 ;
356 }
359 357
360 if ((tmp = index(varlist, sep))) { 358 if ((tmp = index(varlist, sep))) {
361 /* Value is delimited by a comma */ 359 /* Value is delimited by a comma */
362 if (tmp - varlist == 0) { 360 if (tmp - varlist == 0) {
363 continue; 361 continue;
364 } 362 }
365 value = (char *)calloc(1, tmp - varlist + 1); 363 value = (char *)calloc(1, (unsigned long)(tmp - varlist + 1));
366 strncpy(value, varlist, tmp - varlist); 364 strncpy(value, varlist, (unsigned long)(tmp - varlist));
367 value[tmp - varlist] = '\0'; 365 value[tmp - varlist] = '\0';
368 } else { 366 } else {
369 /* Value is delimited by a \0 */ 367 /* Value is delimited by a \0 */
@@ -388,7 +386,7 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
388 386
389 /* Clean-up trailing spaces/newlines */ 387 /* Clean-up trailing spaces/newlines */
390 if (value) { 388 if (value) {
391 for (i = strlen(value) - 1; isspace(value[i]); i--) { 389 for (unsigned long i = strlen(value) - 1; isspace(value[i]); i--) {
392 value[i] = '\0'; 390 value[i] = '\0';
393 } 391 }
394 } 392 }
@@ -430,349 +428,3 @@ int mp_translate_state(char *state_text) {
430 } 428 }
431 return ERROR; 429 return ERROR;
432} 430}
433
434/*
435 * Returns a string to use as a keyname, based on an md5 hash of argv, thus
436 * hopefully a unique key per service/plugin invocation. Use the extra-opts
437 * parse of argv, so that uniqueness in parameters are reflected there.
438 */
439char *_np_state_generate_key(void) {
440 int i;
441 char **argv = this_monitoring_plugin->argv;
442 char keyname[41];
443 char *p = NULL;
444
445 unsigned char result[256];
446
447#ifdef USE_OPENSSL
448 /*
449 * This code path is chosen if openssl is available (which should be the most common
450 * scenario). Alternatively, the gnulib implementation/
451 *
452 */
453 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
454
455 EVP_DigestInit(ctx, EVP_sha256());
456
457 for (i = 0; i < this_monitoring_plugin->argc; i++) {
458 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
459 }
460
461 EVP_DigestFinal(ctx, result, NULL);
462#else
463
464 struct sha256_ctx ctx;
465
466 for (i = 0; i < this_monitoring_plugin->argc; i++) {
467 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
468 }
469
470 sha256_finish_ctx(&ctx, result);
471#endif // FOUNDOPENSSL
472
473 for (i = 0; i < 20; ++i) {
474 sprintf(&keyname[2 * i], "%02x", result[i]);
475 }
476
477 keyname[40] = '\0';
478
479 p = strdup(keyname);
480 if (p == NULL) {
481 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
482 }
483 return p;
484}
485
486void _cleanup_state_data(void) {
487 if (this_monitoring_plugin->state->state_data != NULL) {
488 np_free(this_monitoring_plugin->state->state_data->data);
489 np_free(this_monitoring_plugin->state->state_data);
490 }
491}
492
493/*
494 * Internal function. Returns either:
495 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
496 * statically compiled shared state directory
497 */
498char *_np_state_calculate_location_prefix(void) {
499 char *env_dir;
500
501 /* Do not allow passing MP_STATE_PATH in setuid plugins
502 * for security reasons */
503 if (!mp_suid()) {
504 env_dir = getenv("MP_STATE_PATH");
505 if (env_dir && env_dir[0] != '\0') {
506 return env_dir;
507 }
508 /* This is the former ENV, for backward-compatibility */
509 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
510 if (env_dir && env_dir[0] != '\0') {
511 return env_dir;
512 }
513 }
514
515 return NP_STATE_DIR_PREFIX;
516}
517
518/*
519 * Initiatializer for state routines.
520 * Sets variables. Generates filename. Returns np_state_key. die with
521 * UNKNOWN if exception
522 */
523void np_enable_state(char *keyname, int expected_data_version) {
524 state_key *this_state = NULL;
525 char *temp_filename = NULL;
526 char *temp_keyname = NULL;
527 char *p = NULL;
528 int ret;
529
530 if (this_monitoring_plugin == NULL) {
531 die(STATE_UNKNOWN, _("This requires np_init to be called"));
532 }
533
534 this_state = (state_key *)calloc(1, sizeof(state_key));
535 if (this_state == NULL) {
536 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
537 }
538
539 if (keyname == NULL) {
540 temp_keyname = _np_state_generate_key();
541 } else {
542 temp_keyname = strdup(keyname);
543 if (temp_keyname == NULL) {
544 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
545 }
546 }
547 /* Die if invalid characters used for keyname */
548 p = temp_keyname;
549 while (*p != '\0') {
550 if (!(isalnum(*p) || *p == '_')) {
551 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
552 }
553 p++;
554 }
555 this_state->name = temp_keyname;
556 this_state->plugin_name = this_monitoring_plugin->plugin_name;
557 this_state->data_version = expected_data_version;
558 this_state->state_data = NULL;
559
560 /* Calculate filename */
561 ret = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
562 this_monitoring_plugin->plugin_name, this_state->name);
563 if (ret < 0) {
564 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
565 }
566
567 this_state->_filename = temp_filename;
568
569 this_monitoring_plugin->state = this_state;
570}
571
572/*
573 * Will return NULL if no data is available (first run). If key currently
574 * exists, read data. If state file format version is not expected, return
575 * as if no data. Get state data version number and compares to expected.
576 * If numerically lower, then return as no previous state. die with UNKNOWN
577 * if exceptional error.
578 */
579state_data *np_state_read(void) {
580 state_data *this_state_data = NULL;
581 FILE *statefile;
582 bool rc = false;
583
584 if (this_monitoring_plugin == NULL) {
585 die(STATE_UNKNOWN, _("This requires np_init to be called"));
586 }
587
588 /* Open file. If this fails, no previous state found */
589 statefile = fopen(this_monitoring_plugin->state->_filename, "r");
590 if (statefile != NULL) {
591
592 this_state_data = (state_data *)calloc(1, sizeof(state_data));
593 if (this_state_data == NULL) {
594 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
595 }
596
597 this_state_data->data = NULL;
598 this_monitoring_plugin->state->state_data = this_state_data;
599
600 rc = _np_state_read_file(statefile);
601
602 fclose(statefile);
603 }
604
605 if (!rc) {
606 _cleanup_state_data();
607 }
608
609 return this_monitoring_plugin->state->state_data;
610}
611
612/*
613 * Read the state file
614 */
615bool _np_state_read_file(FILE *f) {
616 bool status = false;
617 size_t pos;
618 char *line;
619 int i;
620 int failure = 0;
621 time_t current_time, data_time;
622 enum {
623 STATE_FILE_VERSION,
624 STATE_DATA_VERSION,
625 STATE_DATA_TIME,
626 STATE_DATA_TEXT,
627 STATE_DATA_END
628 } expected = STATE_FILE_VERSION;
629
630 time(&current_time);
631
632 /* Note: This introduces a limit of 1024 bytes in the string data */
633 line = (char *)calloc(1, 1024);
634 if (line == NULL) {
635 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
636 }
637
638 while (!failure && (fgets(line, 1024, f)) != NULL) {
639 pos = strlen(line);
640 if (line[pos - 1] == '\n') {
641 line[pos - 1] = '\0';
642 }
643
644 if (line[0] == '#') {
645 continue;
646 }
647
648 switch (expected) {
649 case STATE_FILE_VERSION:
650 i = atoi(line);
651 if (i != NP_STATE_FORMAT_VERSION) {
652 failure++;
653 } else {
654 expected = STATE_DATA_VERSION;
655 }
656 break;
657 case STATE_DATA_VERSION:
658 i = atoi(line);
659 if (i != this_monitoring_plugin->state->data_version) {
660 failure++;
661 } else {
662 expected = STATE_DATA_TIME;
663 }
664 break;
665 case STATE_DATA_TIME:
666 /* If time > now, error */
667 data_time = strtoul(line, NULL, 10);
668 if (data_time > current_time) {
669 failure++;
670 } else {
671 this_monitoring_plugin->state->state_data->time = data_time;
672 expected = STATE_DATA_TEXT;
673 }
674 break;
675 case STATE_DATA_TEXT:
676 this_monitoring_plugin->state->state_data->data = strdup(line);
677 if (this_monitoring_plugin->state->state_data->data == NULL) {
678 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
679 }
680 expected = STATE_DATA_END;
681 status = true;
682 break;
683 case STATE_DATA_END:;
684 }
685 }
686
687 np_free(line);
688 return status;
689}
690
691/*
692 * If time=NULL, use current time. Create state file, with state format
693 * version, default text. Writes version, time, and data. Avoid locking
694 * problems - use mv to write and then swap. Possible loss of state data if
695 * two things writing to same key at same time.
696 * Will die with UNKNOWN if errors
697 */
698void np_state_write_string(time_t data_time, char *data_string) {
699 FILE *fp;
700 char *temp_file = NULL;
701 int fd = 0, result = 0;
702 time_t current_time;
703 char *directories = NULL;
704 char *p = NULL;
705
706 if (data_time == 0) {
707 time(&current_time);
708 } else {
709 current_time = data_time;
710 }
711
712 /* If file doesn't currently exist, create directories */
713 if (access(this_monitoring_plugin->state->_filename, F_OK) != 0) {
714 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename);
715 if (result < 0) {
716 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
717 }
718
719 for (p = directories + 1; *p; p++) {
720 if (*p == '/') {
721 *p = '\0';
722 if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) {
723 /* Can't free this! Otherwise error message is wrong! */
724 /* np_free(directories); */
725 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
726 }
727 *p = '/';
728 }
729 }
730 np_free(directories);
731 }
732
733 result = asprintf(&temp_file, "%s.XXXXXX", this_monitoring_plugin->state->_filename);
734 if (result < 0) {
735 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
736 }
737
738 if ((fd = mkstemp(temp_file)) == -1) {
739 np_free(temp_file);
740 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
741 }
742
743 fp = (FILE *)fdopen(fd, "w");
744 if (fp == NULL) {
745 close(fd);
746 unlink(temp_file);
747 np_free(temp_file);
748 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
749 }
750
751 fprintf(fp, "# NP State file\n");
752 fprintf(fp, "%d\n", NP_STATE_FORMAT_VERSION);
753 fprintf(fp, "%d\n", this_monitoring_plugin->state->data_version);
754 fprintf(fp, "%lu\n", current_time);
755 fprintf(fp, "%s\n", data_string);
756
757 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP);
758
759 fflush(fp);
760
761 result = fclose(fp);
762
763 fsync(fd);
764
765 if (result != 0) {
766 unlink(temp_file);
767 np_free(temp_file);
768 die(STATE_UNKNOWN, _("Error writing temp file"));
769 }
770
771 if (rename(temp_file, this_monitoring_plugin->state->_filename) != 0) {
772 unlink(temp_file);
773 np_free(temp_file);
774 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
775 }
776
777 np_free(temp_file);
778}
diff --git a/lib/utils_base.h b/lib/utils_base.h
index 8fb114c2..f31299c4 100644
--- a/lib/utils_base.h
+++ b/lib/utils_base.h
@@ -9,7 +9,6 @@
9#include "./thresholds.h" 9#include "./thresholds.h"
10#include "states.h" 10#include "states.h"
11 11
12
13#ifndef USE_OPENSSL 12#ifndef USE_OPENSSL
14# include "sha256.h" 13# include "sha256.h"
15#endif 14#endif
@@ -27,25 +26,8 @@
27#define OUTSIDE 0 26#define OUTSIDE 0
28#define INSIDE 1 27#define INSIDE 1
29 28
30#define NP_STATE_FORMAT_VERSION 1
31
32typedef struct state_data_struct {
33 time_t time;
34 void *data;
35 int length; /* Of binary data */
36} state_data;
37
38typedef struct state_key_struct {
39 char *name;
40 char *plugin_name;
41 int data_version;
42 char *_filename;
43 state_data *state_data;
44} state_key;
45
46typedef struct np_struct { 29typedef struct np_struct {
47 char *plugin_name; 30 char *plugin_name;
48 state_key *state;
49 int argc; 31 int argc;
50 char **argv; 32 char **argv;
51} monitoring_plugin; 33} monitoring_plugin;
@@ -101,10 +83,6 @@ char *np_extract_value(const char *, const char *, char);
101 */ 83 */
102int mp_translate_state(char *); 84int mp_translate_state(char *);
103 85
104void np_enable_state(char *, int);
105state_data *np_state_read(void);
106void np_state_write_string(time_t, char *);
107
108void np_init(char *, int argc, char **argv); 86void np_init(char *, int argc, char **argv);
109void np_set_args(int argc, char **argv); 87void np_set_args(int argc, char **argv);
110void np_cleanup(void); 88void np_cleanup(void);