check_snmp: Close potential for using uninitialized memory
[monitoring-plugins.git] / plugins / check_snmp.c
blobc73562bab011a9f59e2c62ba5e8a827a0e22d54e
1 /*****************************************************************************
2 *
3 * Nagios check_snmp plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2007 Nagios Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_snmp plugin
12 * Check status of remote machines and obtain system information via SNMP
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 *****************************************************************************/
31 const char *progname = "check_snmp";
32 const char *copyright = "1999-2007";
33 const char *email = "nagiosplug-devel@lists.sourceforge.net";
35 #include "common.h"
36 #include "utils.h"
37 #include "utils_cmd.h"
39 #define DEFAULT_COMMUNITY "public"
40 #define DEFAULT_PORT "161"
41 #define DEFAULT_MIBLIST "ALL"
42 #define DEFAULT_PROTOCOL "1"
43 #define DEFAULT_TIMEOUT 1
44 #define DEFAULT_RETRIES 5
45 #define DEFAULT_AUTH_PROTOCOL "MD5"
46 #define DEFAULT_PRIV_PROTOCOL "DES"
47 #define DEFAULT_DELIMITER "="
48 #define DEFAULT_OUTPUT_DELIMITER " "
50 #define mark(a) ((a)!=0?"*":"")
52 #define CHECK_UNDEF 0
53 #define CRIT_PRESENT 1
54 #define CRIT_STRING 2
55 #define CRIT_REGEX 4
56 #define WARN_PRESENT 8
57 #define WARN_STRING 16
58 #define WARN_REGEX 32
60 #define OID_COUNT_STEP 8
62 /* Longopts only arguments */
63 #define L_CALCULATE_RATE CHAR_MAX+1
64 #define L_RATE_MULTIPLIER CHAR_MAX+2
65 #define L_INVERT_SEARCH CHAR_MAX+3
67 /* Gobble to string - stop incrementing c when c[0] match one of the
68 * characters in s */
69 #define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; }
70 /* Given c, keep track of backslashes (bk) and double-quotes (dq)
71 * from c[0] */
72 #define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
73 case '\\': \
74 if (bk) bk--; \
75 else bk++; \
76 break; \
77 case '"': \
78 if (!dq) { dq++; } \
79 else if(!bk) { dq--; } \
80 else { bk--; } \
81 break; \
86 int process_arguments (int, char **);
87 int validate_arguments (void);
88 char *thisarg (char *str);
89 char *nextarg (char *str);
90 void print_usage (void);
91 void print_help (void);
93 #include "regex.h"
94 char regex_expect[MAX_INPUT_BUFFER] = "";
95 regex_t preg;
96 regmatch_t pmatch[10];
97 char errbuf[MAX_INPUT_BUFFER] = "";
98 char perfstr[MAX_INPUT_BUFFER] = "| ";
99 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
100 int eflags = 0;
101 int errcode, excode;
103 char *server_address = NULL;
104 char *community = NULL;
105 char **authpriv = NULL;
106 char *proto = NULL;
107 char *seclevel = NULL;
108 char *secname = NULL;
109 char *authproto = NULL;
110 char *privproto = NULL;
111 char *authpasswd = NULL;
112 char *privpasswd = NULL;
113 char **oids = NULL;
114 size_t oids_size = NULL;
115 char *label;
116 char *units;
117 char *port;
118 char *snmpcmd;
119 char string_value[MAX_INPUT_BUFFER] = "";
120 int invert_search=0;
121 char **labels = NULL;
122 char **unitv = NULL;
123 size_t nlabels = 0;
124 size_t labels_size = OID_COUNT_STEP;
125 size_t nunits = 0;
126 size_t unitv_size = OID_COUNT_STEP;
127 int numoids = 0;
128 int numauthpriv = 0;
129 int verbose = 0;
130 int usesnmpgetnext = FALSE;
131 char *warning_thresholds = NULL;
132 char *critical_thresholds = NULL;
133 thresholds **thlds;
134 size_t thlds_size = OID_COUNT_STEP;
135 double *response_value;
136 size_t response_size = OID_COUNT_STEP;
137 int retries = 0;
138 int *eval_method;
139 size_t eval_size = OID_COUNT_STEP;
140 char *delimiter;
141 char *output_delim;
142 char *miblist = NULL;
143 int needmibs = FALSE;
144 int calculate_rate = 0;
145 int rate_multiplier = 1;
146 state_data *previous_state;
147 double *previous_value;
148 size_t previous_size = OID_COUNT_STEP;
149 int perf_labels = 1;
152 static char *fix_snmp_range(char *th)
154 double left, right;
155 char *colon, *ret;
156 if (!(colon = strchr(th, ':')))
157 return th;
158 *colon = 0;
160 left = strtod(th, NULL);
161 right = strtod(colon + 1, NULL);
162 if (right >= left) {
163 return th;
165 ret = malloc(strlen(th) + strlen(colon + 1) + 2);
166 sprintf(ret, "@%s:%s", colon + 1, th);
167 free(th);
168 return ret;
172 main (int argc, char **argv)
174 int i, len, line, total_oids;
175 unsigned int bk_count = 0, dq_count = 0;
176 int iresult = STATE_UNKNOWN;
177 int result = STATE_UNKNOWN;
178 int return_code = 0;
179 int external_error = 0;
180 char **command_line = NULL;
181 char *cl_hidden_auth = NULL;
182 char *oidname = NULL;
183 char *response = NULL;
184 char *mult_resp = NULL;
185 char *outbuff;
186 char *ptr = NULL;
187 char *show = NULL;
188 char *th_warn=NULL;
189 char *th_crit=NULL;
190 char type[8] = "";
191 output chld_out, chld_err;
192 char *previous_string=NULL;
193 char *ap=NULL;
194 char *state_string=NULL;
195 size_t response_length, current_length, string_length;
196 char *temp_string=NULL;
197 char *quote_string=NULL;
198 time_t current_time;
199 double temp_double;
200 time_t duration;
201 char *conv = "12345678";
202 int is_counter=0;
204 setlocale (LC_ALL, "");
205 bindtextdomain (PACKAGE, LOCALEDIR);
206 textdomain (PACKAGE);
208 labels = malloc (labels_size * sizeof(*labels));
209 unitv = malloc (unitv_size * sizeof(*unitv));
210 thlds = malloc (thlds_size * sizeof(*thlds));
211 response_value = malloc (response_size * sizeof(*response_value));
212 previous_value = malloc (previous_size * sizeof(*previous_value));
213 eval_method = calloc (eval_size, sizeof(*eval_method));
214 oids = calloc(oids_size, sizeof (char *));
216 label = strdup ("SNMP");
217 units = strdup ("");
218 port = strdup (DEFAULT_PORT);
219 outbuff = strdup ("");
220 delimiter = strdup (" = ");
221 output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
222 timeout_interval = DEFAULT_TIMEOUT;
223 retries = DEFAULT_RETRIES;
225 np_init( (char *) progname, argc, argv );
227 /* Parse extra opts if any */
228 argv=np_extra_opts (&argc, argv, progname);
230 np_set_args(argc, argv);
232 time(&current_time);
234 if (process_arguments (argc, argv) == ERROR)
235 usage4 (_("Could not parse arguments"));
237 if(calculate_rate) {
238 if (!strcmp(label, "SNMP"))
239 label = strdup("SNMP RATE");
240 i=0;
241 previous_state = np_state_read();
242 if(previous_state!=NULL) {
243 /* Split colon separated values */
244 previous_string = strdup((char *) previous_state->data);
245 while((ap = strsep(&previous_string, ":")) != NULL) {
246 if(verbose>2)
247 printf("State for %d=%s\n", i, ap);
248 while (i >= previous_size) {
249 previous_size += OID_COUNT_STEP;
250 previous_value = realloc(previous_value, previous_size * sizeof(*previous_value));
252 previous_value[i++]=strtod(ap,NULL);
257 /* Populate the thresholds */
258 th_warn=warning_thresholds;
259 th_crit=critical_thresholds;
260 for (i=0; i<numoids; i++) {
261 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
262 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
263 /* translate "2:1" to "@1:2" for backwards compatibility */
264 w = w ? fix_snmp_range(w) : NULL;
265 c = c ? fix_snmp_range(c) : NULL;
267 while (i >= thlds_size) {
268 thlds_size += OID_COUNT_STEP;
269 thlds = realloc(thlds, thlds_size * sizeof(*thlds));
272 /* Skip empty thresholds, while avoiding segfault */
273 set_thresholds(&thlds[i],
274 w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL,
275 c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
276 if (w) {
277 th_warn=strchr(th_warn, ',');
278 if (th_warn) th_warn++;
279 free(w);
281 if (c) {
282 th_crit=strchr(th_crit, ',');
283 if (th_crit) th_crit++;
284 free(c);
288 /* Create the command array to execute */
289 if(usesnmpgetnext == TRUE) {
290 snmpcmd = strdup (PATH_TO_SNMPGETNEXT);
291 }else{
292 snmpcmd = strdup (PATH_TO_SNMPGET);
295 /* 9 arguments to pass before authpriv options + 1 for host and numoids. Add one for terminating NULL */
296 command_line = calloc (9 + numauthpriv + 1 + numoids + 1, sizeof (char *));
297 command_line[0] = snmpcmd;
298 command_line[1] = strdup ("-t");
299 xasprintf (&command_line[2], "%d", timeout_interval);
300 command_line[3] = strdup ("-r");
301 xasprintf (&command_line[4], "%d", retries);
302 command_line[5] = strdup ("-m");
303 command_line[6] = strdup (miblist);
304 command_line[7] = "-v";
305 command_line[8] = strdup (proto);
307 for (i = 0; i < numauthpriv; i++) {
308 command_line[9 + i] = authpriv[i];
311 xasprintf (&command_line[9 + numauthpriv], "%s:%s", server_address, port);
313 /* This is just for display purposes, so it can remain a string */
314 xasprintf(&cl_hidden_auth, "%s -t %d -r %d -m %s -v %s %s %s:%s",
315 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto, "[authpriv]",
316 server_address, port);
318 for (i = 0; i < numoids; i++) {
319 command_line[9 + numauthpriv + 1 + i] = oids[i];
320 xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
323 command_line[9 + numauthpriv + 1 + numoids] = NULL;
325 if (verbose)
326 printf ("%s\n", cl_hidden_auth);
328 /* Run the command */
329 return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0);
331 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
332 only return state unknown if return code is non zero or there is no stdout.
333 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
335 if (return_code != 0)
336 external_error=1;
337 if (chld_out.lines == 0)
338 external_error=1;
339 if (external_error) {
340 if (chld_err.lines > 0) {
341 printf (_("External command error: %s\n"), chld_err.line[0]);
342 for (i = 1; i < chld_err.lines; i++) {
343 printf ("%s\n", chld_err.line[i]);
345 } else {
346 printf(_("External command error with no output (return code: %d)\n"), return_code);
348 exit (STATE_UNKNOWN);
351 if (verbose) {
352 for (i = 0; i < chld_out.lines; i++) {
353 printf ("%s\n", chld_out.line[i]);
357 for (line=0, i=0; line < chld_out.lines; line++, i++) {
358 if(calculate_rate)
359 conv = "%.10g";
360 else
361 conv = "%.0f";
363 ptr = chld_out.line[line];
364 oidname = strpcpy (oidname, ptr, delimiter);
365 response = strstr (ptr, delimiter);
366 if (response == NULL)
367 break;
369 if (verbose > 2) {
370 printf("Processing oid %i (line %i)\n oidname: %s\n response: %s\n", i+1, line+1, oidname, response);
373 /* Clean up type array - Sol10 does not necessarily zero it out */
374 bzero(type, sizeof(type));
376 is_counter=0;
377 /* We strip out the datatype indicator for PHBs */
378 if (strstr (response, "Gauge: ")) {
379 show = strstr (response, "Gauge: ") + 7;
381 else if (strstr (response, "Gauge32: ")) {
382 show = strstr (response, "Gauge32: ") + 9;
384 else if (strstr (response, "Counter32: ")) {
385 show = strstr (response, "Counter32: ") + 11;
386 is_counter=1;
387 if(!calculate_rate)
388 strcpy(type, "c");
390 else if (strstr (response, "Counter64: ")) {
391 show = strstr (response, "Counter64: ") + 11;
392 is_counter=1;
393 if(!calculate_rate)
394 strcpy(type, "c");
396 else if (strstr (response, "INTEGER: ")) {
397 show = strstr (response, "INTEGER: ") + 9;
399 else if (strstr (response, "STRING: ")) {
400 show = strstr (response, "STRING: ") + 8;
401 conv = "%.10g";
403 /* Get the rest of the string on multi-line strings */
404 ptr = show;
405 COUNT_SEQ(ptr, bk_count, dq_count)
406 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
407 ptr++;
408 GOBBLE_TOS(ptr, "\n\"\\")
409 COUNT_SEQ(ptr, bk_count, dq_count)
412 if (dq_count) { /* unfinished line */
413 /* copy show verbatim first */
414 if (!mult_resp) mult_resp = strdup("");
415 xasprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
416 /* then strip out unmatched double-quote from single-line output */
417 if (show[0] == '"') show++;
419 /* Keep reading until we match end of double-quoted string */
420 for (line++; line < chld_out.lines; line++) {
421 ptr = chld_out.line[line];
422 xasprintf (&mult_resp, "%s%s\n", mult_resp, ptr);
424 COUNT_SEQ(ptr, bk_count, dq_count)
425 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
426 ptr++;
427 GOBBLE_TOS(ptr, "\n\"\\")
428 COUNT_SEQ(ptr, bk_count, dq_count)
430 /* Break for loop before next line increment when done */
431 if (!dq_count) break;
436 else if (strstr (response, "Timeticks: ")) {
437 show = strstr (response, "Timeticks: ");
439 else
440 show = response + 3;
442 iresult = STATE_DEPENDENT;
444 /* Process this block for numeric comparisons */
445 /* Make some special values,like Timeticks numeric only if a threshold is defined */
446 if (thlds[i]->warning || thlds[i]->critical || calculate_rate) {
447 ptr = strpbrk (show, "0123456789");
448 if (ptr == NULL)
449 die (STATE_UNKNOWN,_("No valid data returned (%s)\n"), show);
450 while (i >= response_size) {
451 response_size += OID_COUNT_STEP;
452 response_value = realloc(response_value, response_size * sizeof(*response_value));
454 response_value[i] = strtod (ptr, NULL);
456 if(calculate_rate) {
457 if (previous_state!=NULL) {
458 duration = current_time-previous_state->time;
459 if(duration<=0)
460 die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid"));
461 temp_double = response_value[i]-previous_value[i];
462 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
463 if(is_counter) {
464 if(temp_double<(double)0.0)
465 temp_double+=(double)4294967296.0; /* 2^32 */
466 if(temp_double<(double)0.0)
467 temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */;
469 /* Convert to per second, then use multiplier */
470 temp_double = temp_double/duration*rate_multiplier;
471 iresult = get_status(temp_double, thlds[i]);
472 xasprintf (&show, conv, temp_double);
474 } else {
475 iresult = get_status(response_value[i], thlds[i]);
476 xasprintf (&show, conv, response_value[i]);
480 /* Process this block for string matching */
481 else if (eval_size > i && eval_method[i] & CRIT_STRING) {
482 if (strcmp (show, string_value))
483 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
484 else
485 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
488 /* Process this block for regex matching */
489 else if (eval_size > i && eval_method[i] & CRIT_REGEX) {
490 excode = regexec (&preg, response, 10, pmatch, eflags);
491 if (excode == 0) {
492 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
494 else if (excode != REG_NOMATCH) {
495 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
496 printf (_("Execute Error: %s\n"), errbuf);
497 exit (STATE_CRITICAL);
499 else {
500 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
504 /* Process this block for existence-nonexistence checks */
505 /* TV: Should this be outside of this else block? */
506 else {
507 if (eval_size > i && eval_method[i] & CRIT_PRESENT)
508 iresult = STATE_CRITICAL;
509 else if (eval_size > i && eval_method[i] & WARN_PRESENT)
510 iresult = STATE_WARNING;
511 else if (response && iresult == STATE_DEPENDENT)
512 iresult = STATE_OK;
515 /* Result is the worst outcome of all the OIDs tested */
516 result = max_state (result, iresult);
518 /* Prepend a label for this OID if there is one */
519 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
520 xasprintf (&outbuff, "%s%s%s %s%s%s", outbuff,
521 (i == 0) ? " " : output_delim,
522 labels[i], mark (iresult), show, mark (iresult));
523 else
524 xasprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
525 mark (iresult), show, mark (iresult));
527 /* Append a unit string for this OID if there is one */
528 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
529 xasprintf (&outbuff, "%s %s", outbuff, unitv[i]);
531 /* Write perfdata with whatever can be parsed by strtod, if possible */
532 ptr = NULL;
533 strtod(show, &ptr);
534 if (ptr > show) {
535 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
536 temp_string=labels[i];
537 else
538 temp_string=oidname;
539 if (strpbrk (temp_string, " ='\"") == NULL) {
540 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
541 } else {
542 if (strpbrk (temp_string, "'") == NULL) {
543 quote_string="'";
544 } else {
545 quote_string="\"";
547 strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1);
548 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
549 strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1);
551 strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
552 len = sizeof(perfstr)-strlen(perfstr)-1;
553 strncat(perfstr, show, len>ptr-show ? ptr-show : len);
555 if (type)
556 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
557 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
560 total_oids=i;
562 /* Save state data, as all data collected now */
563 if(calculate_rate) {
564 string_length=1024;
565 state_string=malloc(string_length);
566 if(state_string==NULL)
567 die(STATE_UNKNOWN, _("Cannot malloc"));
569 current_length=0;
570 for(i=0; i<total_oids; i++) {
571 xasprintf(&temp_string,"%.0f",response_value[i]);
572 if(temp_string==NULL)
573 die(STATE_UNKNOWN,_("Cannot asprintf()"));
574 response_length = strlen(temp_string);
575 if(current_length+response_length>string_length) {
576 string_length=current_length+1024;
577 state_string=realloc(state_string,string_length);
578 if(state_string==NULL)
579 die(STATE_UNKNOWN, _("Cannot realloc()"));
581 strcpy(&state_string[current_length],temp_string);
582 current_length=current_length+response_length;
583 state_string[current_length]=':';
584 current_length++;
585 free(temp_string);
587 state_string[--current_length]='\0';
588 if (verbose > 2)
589 printf("State string=%s\n",state_string);
591 /* This is not strictly the same as time now, but any subtle variations will cancel out */
592 np_state_write_string(current_time, state_string );
593 if(previous_state==NULL) {
594 /* Or should this be highest state? */
595 die( STATE_OK, _("No previous data to calculate rate - assume okay" ) );
599 printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr);
600 if (mult_resp) printf ("%s", mult_resp);
602 return result;
607 /* process command-line arguments */
609 process_arguments (int argc, char **argv)
611 char *ptr;
612 int c = 1;
613 int j = 0, jj = 0, ii = 0;
615 int option = 0;
616 static struct option longopts[] = {
617 STD_LONG_OPTS,
618 {"community", required_argument, 0, 'C'},
619 {"oid", required_argument, 0, 'o'},
620 {"object", required_argument, 0, 'o'},
621 {"delimiter", required_argument, 0, 'd'},
622 {"output-delimiter", required_argument, 0, 'D'},
623 {"string", required_argument, 0, 's'},
624 {"timeout", required_argument, 0, 't'},
625 {"regex", required_argument, 0, 'r'},
626 {"ereg", required_argument, 0, 'r'},
627 {"eregi", required_argument, 0, 'R'},
628 {"label", required_argument, 0, 'l'},
629 {"units", required_argument, 0, 'u'},
630 {"port", required_argument, 0, 'p'},
631 {"retries", required_argument, 0, 'e'},
632 {"miblist", required_argument, 0, 'm'},
633 {"protocol", required_argument, 0, 'P'},
634 {"seclevel", required_argument, 0, 'L'},
635 {"secname", required_argument, 0, 'U'},
636 {"authproto", required_argument, 0, 'a'},
637 {"privproto", required_argument, 0, 'x'},
638 {"authpasswd", required_argument, 0, 'A'},
639 {"privpasswd", required_argument, 0, 'X'},
640 {"next", no_argument, 0, 'n'},
641 {"rate", no_argument, 0, L_CALCULATE_RATE},
642 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
643 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
644 {"perf-oids", no_argument, 0, 'O'},
645 {0, 0, 0, 0}
648 if (argc < 2)
649 return ERROR;
651 /* reverse compatibility for very old non-POSIX usage forms */
652 for (c = 1; c < argc; c++) {
653 if (strcmp ("-to", argv[c]) == 0)
654 strcpy (argv[c], "-t");
655 if (strcmp ("-wv", argv[c]) == 0)
656 strcpy (argv[c], "-w");
657 if (strcmp ("-cv", argv[c]) == 0)
658 strcpy (argv[c], "-c");
661 while (1) {
662 c = getopt_long (argc, argv, "nhvVOt:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:L:U:a:x:A:X:",
663 longopts, &option);
665 if (c == -1 || c == EOF)
666 break;
668 switch (c) {
669 case '?': /* usage */
670 usage5 ();
671 case 'h': /* help */
672 print_help ();
673 exit (STATE_OK);
674 case 'V': /* version */
675 print_revision (progname, NP_VERSION);
676 exit (STATE_OK);
677 case 'v': /* verbose */
678 verbose++;
679 break;
681 /* Connection info */
682 case 'C': /* group or community */
683 community = optarg;
684 break;
685 case 'H': /* Host or server */
686 server_address = optarg;
687 break;
688 case 'p': /* TCP port number */
689 port = optarg;
690 break;
691 case 'm': /* List of MIBS */
692 miblist = optarg;
693 break;
694 case 'n': /* usesnmpgetnext */
695 usesnmpgetnext = TRUE;
696 break;
697 case 'P': /* SNMP protocol version */
698 proto = optarg;
699 break;
700 case 'L': /* security level */
701 seclevel = optarg;
702 break;
703 case 'U': /* security username */
704 secname = optarg;
705 break;
706 case 'a': /* auth protocol */
707 authproto = optarg;
708 break;
709 case 'x': /* priv protocol */
710 privproto = optarg;
711 break;
712 case 'A': /* auth passwd */
713 authpasswd = optarg;
714 break;
715 case 'X': /* priv passwd */
716 privpasswd = optarg;
717 break;
718 case 't': /* timeout period */
719 if (!is_integer (optarg))
720 usage2 (_("Timeout interval must be a positive integer"), optarg);
721 else
722 timeout_interval = atoi (optarg);
723 break;
725 /* Test parameters */
726 case 'c': /* critical threshold */
727 critical_thresholds = optarg;
728 break;
729 case 'w': /* warning threshold */
730 warning_thresholds = optarg;
731 break;
732 case 'e': /* PRELIMINARY - may change */
733 case 'E': /* PRELIMINARY - may change */
734 if (!is_integer (optarg))
735 usage2 (_("Retries interval must be a positive integer"), optarg);
736 else
737 retries = atoi(optarg);
738 break;
739 case 'o': /* object identifier */
740 if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) {
742 * we have something other than digits, periods and comas,
743 * so we have a mib variable, rather than just an SNMP OID,
744 * so we have to actually read the mib files
746 needmibs = TRUE;
748 for (ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) {
749 while (j >= oids_size) {
750 oids_size += OID_COUNT_STEP;
751 oids = realloc(oids, oids_size * sizeof (*oids));
753 oids[j] = strdup(ptr);
755 numoids = j;
756 if (c == 'E' || c == 'e') {
757 jj++;
758 ii++;
759 while (j+1 >= eval_size) {
760 eval_size += OID_COUNT_STEP;
761 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
762 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
764 if (c == 'E')
765 eval_method[j+1] |= WARN_PRESENT;
766 else if (c == 'e')
767 eval_method[j+1] |= CRIT_PRESENT;
769 break;
770 case 's': /* string or substring */
771 strncpy (string_value, optarg, sizeof (string_value) - 1);
772 string_value[sizeof (string_value) - 1] = 0;
773 while (jj >= eval_size) {
774 eval_size += OID_COUNT_STEP;
775 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
776 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
778 eval_method[jj++] = CRIT_STRING;
779 ii++;
780 break;
781 case 'R': /* regex */
782 cflags = REG_ICASE;
783 case 'r': /* regex */
784 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
785 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
786 regex_expect[sizeof (regex_expect) - 1] = 0;
787 errcode = regcomp (&preg, regex_expect, cflags);
788 if (errcode != 0) {
789 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
790 printf (_("Could Not Compile Regular Expression"));
791 return ERROR;
793 while (jj >= eval_size) {
794 eval_size += OID_COUNT_STEP;
795 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
796 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
798 eval_method[jj++] = CRIT_REGEX;
799 ii++;
800 break;
802 /* Format */
803 case 'd': /* delimiter */
804 delimiter = strscpy (delimiter, optarg);
805 break;
806 case 'D': /* output-delimiter */
807 output_delim = strscpy (output_delim, optarg);
808 break;
809 case 'l': /* label */
810 nlabels++;
811 if (nlabels > labels_size) {
812 labels_size += 8;
813 labels = realloc (labels, labels_size * sizeof(*labels));
814 if (labels == NULL)
815 die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
817 labels[nlabels - 1] = optarg;
818 ptr = thisarg (optarg);
819 labels[nlabels - 1] = ptr;
820 if (ptr[0] == '\'')
821 labels[nlabels - 1] = ptr + 1;
822 while (ptr && (ptr = nextarg (ptr))) {
823 nlabels++;
824 if (nlabels > labels_size) {
825 labels_size += 8;
826 labels = realloc (labels, labels_size * sizeof(*labels));
827 if (labels == NULL)
828 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
830 ptr = thisarg (ptr);
831 if (ptr[0] == '\'')
832 labels[nlabels - 1] = ptr + 1;
833 else
834 labels[nlabels - 1] = ptr;
836 break;
837 case 'u': /* units */
838 units = optarg;
839 nunits++;
840 if (nunits > unitv_size) {
841 unitv_size += 8;
842 unitv = realloc (unitv, unitv_size * sizeof(*unitv));
843 if (unitv == NULL)
844 die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
846 unitv[nunits - 1] = optarg;
847 ptr = thisarg (optarg);
848 unitv[nunits - 1] = ptr;
849 if (ptr[0] == '\'')
850 unitv[nunits - 1] = ptr + 1;
851 while (ptr && (ptr = nextarg (ptr))) {
852 if (nunits > unitv_size) {
853 unitv_size += 8;
854 unitv = realloc (unitv, unitv_size * sizeof(*unitv));
855 if (units == NULL)
856 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
858 nunits++;
859 ptr = thisarg (ptr);
860 if (ptr[0] == '\'')
861 unitv[nunits - 1] = ptr + 1;
862 else
863 unitv[nunits - 1] = ptr;
865 break;
866 case L_CALCULATE_RATE:
867 if(calculate_rate==0)
868 np_enable_state(NULL, 1);
869 calculate_rate = 1;
870 break;
871 case L_RATE_MULTIPLIER:
872 if(!is_integer(optarg)||((rate_multiplier=atoi(optarg))<=0))
873 usage2(_("Rate multiplier must be a positive integer"),optarg);
874 break;
875 case L_INVERT_SEARCH:
876 invert_search=1;
877 break;
878 case 'O':
879 perf_labels=0;
880 break;
884 if (server_address == NULL)
885 server_address = argv[optind];
887 if (community == NULL)
888 community = strdup (DEFAULT_COMMUNITY);
890 return validate_arguments ();
894 /******************************************************************************
897 <sect3>
898 <title>validate_arguments</title>
900 <para>&PROTO_validate_arguments;</para>
902 <para>Checks to see if the default miblist needs to be loaded. Also verifies
903 the authentication and authorization combinations based on protocol version
904 selected.</para>
906 <para></para>
908 </sect3>
910 ******************************************************************************/
915 validate_arguments ()
917 /* check whether to load locally installed MIBS (CPU/disk intensive) */
918 if (miblist == NULL) {
919 if ( needmibs == TRUE ) {
920 miblist = strdup (DEFAULT_MIBLIST);
921 }else{
922 miblist = ""; /* don't read any mib files for numeric oids */
926 /* Check server_address is given */
927 if (server_address == NULL)
928 die(STATE_UNKNOWN, _("No host specified\n"));
930 /* Check oid is given */
931 if (numoids == 0)
932 die(STATE_UNKNOWN, _("No OIDs specified\n"));
934 if (proto == NULL)
935 xasprintf(&proto, DEFAULT_PROTOCOL);
937 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */
938 numauthpriv = 2;
939 authpriv = calloc (numauthpriv, sizeof (char *));
940 authpriv[0] = strdup ("-c");
941 authpriv[1] = strdup (community);
943 else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */
944 if (seclevel == NULL)
945 xasprintf(&seclevel, "noAuthNoPriv");
947 if (strcmp(seclevel, "noAuthNoPriv") == 0) {
948 numauthpriv = 2;
949 authpriv = calloc (numauthpriv, sizeof (char *));
950 authpriv[0] = strdup ("-l");
951 authpriv[1] = strdup ("noAuthNoPriv");
952 } else {
953 if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
954 usage2 (_("Invalid seclevel"), seclevel);
957 if (authproto == NULL )
958 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
960 if (secname == NULL)
961 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
963 if (authpasswd == NULL)
964 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
966 if ( strcmp(seclevel, "authNoPriv") == 0 ) {
967 numauthpriv = 8;
968 authpriv = calloc (numauthpriv, sizeof (char *));
969 authpriv[0] = strdup ("-l");
970 authpriv[1] = strdup ("authNoPriv");
971 authpriv[2] = strdup ("-a");
972 authpriv[3] = strdup (authproto);
973 authpriv[4] = strdup ("-u");
974 authpriv[5] = strdup (secname);
975 authpriv[6] = strdup ("-A");
976 authpriv[7] = strdup (authpasswd);
977 } else if ( strcmp(seclevel, "authPriv") == 0 ) {
978 if (privproto == NULL )
979 xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
981 if (privpasswd == NULL)
982 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
984 numauthpriv = 12;
985 authpriv = calloc (numauthpriv, sizeof (char *));
986 authpriv[0] = strdup ("-l");
987 authpriv[1] = strdup ("authPriv");
988 authpriv[2] = strdup ("-a");
989 authpriv[3] = strdup (authproto);
990 authpriv[4] = strdup ("-u");
991 authpriv[5] = strdup (secname);
992 authpriv[6] = strdup ("-A");
993 authpriv[7] = strdup (authpasswd);
994 authpriv[8] = strdup ("-x");
995 authpriv[9] = strdup (privproto);
996 authpriv[10] = strdup ("-X");
997 authpriv[11] = strdup (privpasswd);
1002 else {
1003 usage2 (_("Invalid SNMP version"), proto);
1006 return OK;
1011 /* trim leading whitespace
1012 if there is a leading quote, make sure it balances */
1014 char *
1015 thisarg (char *str)
1017 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
1018 if (str[0] == '\'') { /* handle SIMPLE quoted strings */
1019 if (strlen (str) == 1 || !strstr (str + 1, "'"))
1020 die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
1022 return str;
1027 /* if there's a leading quote, advance to the trailing quote
1028 set the trailing quote to '\x0'
1029 if the string continues, advance beyond the comma */
1031 char *
1032 nextarg (char *str)
1034 if (str[0] == '\'') {
1035 str[0] = 0;
1036 if (strlen (str) > 1) {
1037 str = strstr (str + 1, "'");
1038 return (++str);
1040 else {
1041 return NULL;
1044 if (str[0] == ',') {
1045 str[0] = 0;
1046 if (strlen (str) > 1) {
1047 return (++str);
1049 else {
1050 return NULL;
1053 if ((str = strstr (str, ",")) && strlen (str) > 1) {
1054 str[0] = 0;
1055 return (++str);
1057 return NULL;
1062 void
1063 print_help (void)
1065 print_revision (progname, NP_VERSION);
1067 printf (COPYRIGHT, copyright, email);
1069 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1071 printf ("\n\n");
1073 print_usage ();
1075 printf (UT_HELP_VRSN);
1076 printf (UT_EXTRA_OPTS);
1078 printf (UT_HOST_PORT, 'p', DEFAULT_PORT);
1080 /* SNMP and Authentication Protocol */
1081 printf (" %s\n", "-n, --next");
1082 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1083 printf (" %s\n", "-P, --protocol=[1|2c|3]");
1084 printf (" %s\n", _("SNMP protocol version"));
1085 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1086 printf (" %s\n", _("SNMPv3 securityLevel"));
1087 printf (" %s\n", "-a, --authproto=[MD5|SHA]");
1088 printf (" %s\n", _("SNMPv3 auth proto"));
1089 printf (" %s\n", "-x, --privproto=[DES|AES]");
1090 printf (" %s\n", _("SNMPv3 priv proto (default DES)"));
1092 /* Authentication Tokens*/
1093 printf (" %s\n", "-C, --community=STRING");
1094 printf (" %s ", _("Optional community string for SNMP communication"));
1095 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
1096 printf (" %s\n", "-U, --secname=USERNAME");
1097 printf (" %s\n", _("SNMPv3 username"));
1098 printf (" %s\n", "-A, --authpassword=PASSWORD");
1099 printf (" %s\n", _("SNMPv3 authentication password"));
1100 printf (" %s\n", "-X, --privpasswd=PASSWORD");
1101 printf (" %s\n", _("SNMPv3 privacy password"));
1103 /* OID Stuff */
1104 printf (" %s\n", "-o, --oid=OID(s)");
1105 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1106 printf (" %s\n", "-m, --miblist=STRING");
1107 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1108 printf (" %s\n", _("for symbolic OIDs.)"));
1109 printf (" %s\n", "-d, --delimiter=STRING");
1110 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
1111 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1112 printf (" %s\n", _("to be the data that should be used in the evaluation."));
1114 /* Tests Against Integers */
1115 printf (" %s\n", "-w, --warning=THRESHOLD(s)");
1116 printf (" %s\n", _("Warning threshold range(s)"));
1117 printf (" %s\n", "-c, --critical=THRESHOLD(s)");
1118 printf (" %s\n", _("Critical threshold range(s)"));
1119 printf (" %s\n", "--rate");
1120 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1121 printf (" %s\n", "--rate-multiplier");
1122 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1124 /* Tests Against Strings */
1125 printf (" %s\n", "-s, --string=STRING");
1126 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1127 printf (" %s\n", "-r, --ereg=REGEX");
1128 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1129 printf (" %s\n", "-R, --eregi=REGEX");
1130 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1131 printf (" %s\n", "--invert-search");
1132 printf (" %s\n", _("Invert search result (CRITICAL if found)"));
1134 /* Output Formatting */
1135 printf (" %s\n", "-l, --label=STRING");
1136 printf (" %s\n", _("Prefix label for output from plugin"));
1137 printf (" %s\n", "-u, --units=STRING");
1138 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1139 printf (" %s\n", "-D, --output-delimiter=STRING");
1140 printf (" %s\n", _("Separates output on multiple OID requests"));
1142 printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1143 printf (" %s\n", "-e, --retries=INTEGER");
1144 printf (" %s\n", _("Number of retries to be used in the requests"));
1146 printf (" %s\n", "-O, --perf-oids");
1147 printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
1149 printf (UT_VERBOSE);
1151 printf ("\n");
1152 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1153 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1154 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1156 printf ("\n");
1157 printf ("%s\n", _("Notes:"));
1158 printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1159 printf (" %s %i %s\n", _("list (lists with internal spaces must be quoted)."));
1161 printf(" -%s", UT_THRESHOLDS_NOTES);
1163 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1164 printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1165 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1166 printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
1168 printf("\n");
1169 printf("%s\n", _("Rate Calculation:"));
1170 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1171 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1172 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1173 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1174 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1175 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1176 printf(" %s\n", _("changing the arguments will create a new state file."));
1178 printf (UT_SUPPORT);
1183 void
1184 print_usage (void)
1186 printf ("%s\n", _("Usage:"));
1187 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname);
1188 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1189 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1190 printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
1191 printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");