9d9194225b4ee8d5f9facffc3e022e7ff198e741
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
11 *
12 * Check status of remote machines and obtain system information via SNMP
13 *
14 *
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.
19 *
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.
24 *
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/>.
27 *
28 *
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 MAX_OIDS 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; \
82 }
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 char *label;
115 char *units;
116 char *port;
117 char *snmpcmd;
118 char string_value[MAX_INPUT_BUFFER] = "";
119 int invert_search=0;
120 char **labels = NULL;
121 char **unitv = NULL;
122 size_t nlabels = 0;
123 size_t labels_size = 8;
124 size_t nunits = 0;
125 size_t unitv_size = 8;
126 int numoids = 0;
127 int numauthpriv = 0;
128 int verbose = 0;
129 int usesnmpgetnext = FALSE;
130 char *warning_thresholds = NULL;
131 char *critical_thresholds = NULL;
132 thresholds *thlds[MAX_OIDS];
133 double response_value[MAX_OIDS];
134 int retries = 0;
135 int eval_method[MAX_OIDS];
136 char *delimiter;
137 char *output_delim;
138 char *miblist = NULL;
139 int needmibs = FALSE;
140 int calculate_rate = 0;
141 int rate_multiplier = 1;
142 state_data *previous_state;
143 double previous_value[MAX_OIDS];
146 int
147 main (int argc, char **argv)
148 {
149 int i, len, line, total_oids;
150 unsigned int bk_count = 0, dq_count = 0;
151 int iresult = STATE_UNKNOWN;
152 int result = STATE_UNKNOWN;
153 int return_code = 0;
154 int external_error = 0;
155 char **command_line = NULL;
156 char *cl_hidden_auth = NULL;
157 char *oidname = NULL;
158 char *response = NULL;
159 char *mult_resp = NULL;
160 char *outbuff;
161 char *ptr = NULL;
162 char *show = NULL;
163 char *endptr = NULL;
164 char *th_warn=NULL;
165 char *th_crit=NULL;
166 char type[8] = "";
167 output chld_out, chld_err;
168 char *previous_string=NULL;
169 char *ap=NULL;
170 char *state_string=NULL;
171 size_t response_length, current_length, string_length;
172 char *temp_string=NULL;
173 int is_numeric=0;
174 time_t current_time;
175 double temp_double;
176 time_t duration;
177 char *conv = "12345678";
178 int is_counter=0;
180 setlocale (LC_ALL, "");
181 bindtextdomain (PACKAGE, LOCALEDIR);
182 textdomain (PACKAGE);
184 labels = malloc (labels_size);
185 unitv = malloc (unitv_size);
186 for (i = 0; i < MAX_OIDS; i++)
187 eval_method[i] = CHECK_UNDEF;
189 label = strdup ("SNMP");
190 units = strdup ("");
191 port = strdup (DEFAULT_PORT);
192 outbuff = strdup ("");
193 delimiter = strdup (" = ");
194 output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
195 timeout_interval = DEFAULT_TIMEOUT;
196 retries = DEFAULT_RETRIES;
198 np_init( (char *) progname, argc, argv );
200 /* Parse extra opts if any */
201 argv=np_extra_opts (&argc, argv, progname);
203 np_set_args(argc, argv);
205 if (process_arguments (argc, argv) == ERROR)
206 usage4 (_("Could not parse arguments"));
208 if(calculate_rate) {
209 if (!strcmp(label, "SNMP"))
210 label = strdup("SNMP RATE");
211 time(¤t_time);
212 i=0;
213 previous_state = np_state_read();
214 if(previous_state!=NULL) {
215 /* Split colon separated values */
216 previous_string = strdup((char *) previous_state->data);
217 while((ap = strsep(&previous_string, ":")) != NULL) {
218 if(verbose>2)
219 printf("State for %d=%s\n", i, ap);
220 previous_value[i++]=strtod(ap,NULL);
221 }
222 }
223 }
225 /* Populate the thresholds */
226 th_warn=warning_thresholds;
227 th_crit=critical_thresholds;
228 for (i=0; i<numoids; i++) {
229 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
230 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
231 /* Skip empty thresholds, while avoiding segfault */
232 set_thresholds(&thlds[i],
233 w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL,
234 c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
235 if (w) {
236 th_warn=strchr(th_warn, ',');
237 if (th_warn) th_warn++;
238 free(w);
239 }
240 if (c) {
241 th_crit=strchr(th_crit, ',');
242 if (th_crit) th_crit++;
243 free(c);
244 }
245 }
247 /* Create the command array to execute */
248 if(usesnmpgetnext == TRUE) {
249 snmpcmd = strdup (PATH_TO_SNMPGETNEXT);
250 }else{
251 snmpcmd = strdup (PATH_TO_SNMPGET);
252 }
254 /* 9 arguments to pass before authpriv options + 1 for host and numoids. Add one for terminating NULL */
255 command_line = calloc (9 + numauthpriv + 1 + numoids + 1, sizeof (char *));
256 command_line[0] = snmpcmd;
257 command_line[1] = strdup ("-t");
258 asprintf (&command_line[2], "%d", timeout_interval);
259 command_line[3] = strdup ("-r");
260 asprintf (&command_line[4], "%d", retries);
261 command_line[5] = strdup ("-m");
262 command_line[6] = strdup (miblist);
263 command_line[7] = "-v";
264 command_line[8] = strdup (proto);
266 for (i = 0; i < numauthpriv; i++) {
267 command_line[9 + i] = authpriv[i];
268 }
270 asprintf (&command_line[9 + numauthpriv], "%s:%s", server_address, port);
272 /* This is just for display purposes, so it can remain a string */
273 asprintf(&cl_hidden_auth, "%s -t %d -r %d -m %s -v %s %s %s:%s",
274 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto, "[authpriv]",
275 server_address, port);
277 for (i = 0; i < numoids; i++) {
278 command_line[9 + numauthpriv + 1 + i] = oids[i];
279 asprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
280 }
282 command_line[9 + numauthpriv + 1 + numoids] = NULL;
284 if (verbose)
285 printf ("%s\n", cl_hidden_auth);
287 /* Run the command */
288 return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0);
290 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
291 only return state unknown if return code is non zero or there is no stdout.
292 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
293 */
294 if (return_code != 0)
295 external_error=1;
296 if (chld_out.lines == 0)
297 external_error=1;
298 if (external_error) {
299 if (chld_err.lines > 0) {
300 printf (_("External command error: %s\n"), chld_err.line[0]);
301 for (i = 1; i < chld_err.lines; i++) {
302 printf ("%s\n", chld_err.line[i]);
303 }
304 } else {
305 printf(_("External command error with no output (return code: %d)\n"), return_code);
306 }
307 exit (STATE_UNKNOWN);
308 }
310 if (verbose) {
311 for (i = 0; i < chld_out.lines; i++) {
312 printf ("%s\n", chld_out.line[i]);
313 }
314 }
316 for (line=0, i=0; line < chld_out.lines; line++, i++) {
317 if(calculate_rate)
318 conv = "%.10g";
319 else
320 conv = "%.0f";
322 ptr = chld_out.line[line];
323 oidname = strpcpy (oidname, ptr, delimiter);
324 response = strstr (ptr, delimiter);
325 if (response == NULL)
326 break;
328 if (verbose > 2) {
329 printf("Processing oid %i (line %i)\n oidname: %s\n response: %s\n", i+1, line+1, oidname, response);
330 }
332 /* Clean up type array - Sol10 does not necessarily zero it out */
333 bzero(type, sizeof(type));
335 is_counter=0;
336 /* We strip out the datatype indicator for PHBs */
337 if (strstr (response, "Gauge: ")) {
338 show = strstr (response, "Gauge: ") + 7;
339 is_numeric++;
340 }
341 else if (strstr (response, "Gauge32: ")) {
342 show = strstr (response, "Gauge32: ") + 9;
343 is_numeric++;
344 }
345 else if (strstr (response, "Counter32: ")) {
346 show = strstr (response, "Counter32: ") + 11;
347 is_numeric++;
348 is_counter=1;
349 if(!calculate_rate)
350 strcpy(type, "c");
351 }
352 else if (strstr (response, "Counter64: ")) {
353 show = strstr (response, "Counter64: ") + 11;
354 is_numeric++;
355 is_counter=1;
356 if(!calculate_rate)
357 strcpy(type, "c");
358 }
359 else if (strstr (response, "INTEGER: ")) {
360 show = strstr (response, "INTEGER: ") + 9;
361 is_numeric++;
362 }
363 else if (strstr (response, "STRING: ")) {
364 show = strstr (response, "STRING: ") + 8;
365 conv = "%.10g";
367 /* Get the rest of the string on multi-line strings */
368 ptr = show;
369 COUNT_SEQ(ptr, bk_count, dq_count)
370 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
371 ptr++;
372 GOBBLE_TOS(ptr, "\n\"\\")
373 COUNT_SEQ(ptr, bk_count, dq_count)
374 }
376 if (dq_count) { /* unfinished line */
377 /* copy show verbatim first */
378 if (!mult_resp) mult_resp = strdup("");
379 asprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
380 /* then strip out unmatched double-quote from single-line output */
381 if (show[0] == '"') show++;
383 /* Keep reading until we match end of double-quoted string */
384 for (line++; line < chld_out.lines; line++) {
385 ptr = chld_out.line[line];
386 asprintf (&mult_resp, "%s%s\n", mult_resp, ptr);
388 COUNT_SEQ(ptr, bk_count, dq_count)
389 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
390 ptr++;
391 GOBBLE_TOS(ptr, "\n\"\\")
392 COUNT_SEQ(ptr, bk_count, dq_count)
393 }
394 /* Break for loop before next line increment when done */
395 if (!dq_count) break;
396 }
397 }
399 /* Allow numeric conversion if whole string is a number. Make concession for strings with " at beginning or end */
400 /* This duplicates the conversion a bit later, but is cleaner to separate out the checking against the conversion */
401 ptr = show;
402 if (*ptr == '"')
403 ptr++;
404 if (*ptr != '\0' ) {
405 strtod( ptr, &endptr );
406 if (*endptr == '"')
407 endptr++;
408 if (*endptr == '\0')
409 is_numeric=1;
410 }
412 }
413 else if (strstr (response, "Timeticks: "))
414 show = strstr (response, "Timeticks: ");
415 else
416 show = response;
418 iresult = STATE_DEPENDENT;
420 /* Process this block for numeric comparisons */
421 if (is_numeric) {
422 ptr = strpbrk (show, "0123456789");
423 if (ptr == NULL)
424 die (STATE_UNKNOWN,_("No valid data returned"));
425 response_value[i] = strtod (ptr, NULL);
427 if(calculate_rate) {
428 if (previous_state!=NULL) {
429 duration = current_time-previous_state->time;
430 if(duration<=0)
431 die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid"));
432 temp_double = response_value[i]-previous_value[i];
433 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
434 if(is_counter) {
435 if(temp_double<(double)0.0)
436 temp_double+=(double)4294967296.0; /* 2^32 */
437 if(temp_double<(double)0.0)
438 temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */;
439 }
440 /* Convert to per second, then use multiplier */
441 temp_double = temp_double/duration*rate_multiplier;
442 iresult = get_status(temp_double, thlds[i]);
443 asprintf (&show, conv, temp_double);
444 }
445 } else {
446 iresult = get_status(response_value[i], thlds[i]);
447 asprintf (&show, conv, response_value[i]);
448 }
449 }
451 /* Process this block for string matching */
452 else if (eval_method[i] & CRIT_STRING) {
453 if (strcmp (show, string_value))
454 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
455 else
456 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
457 }
459 /* Process this block for regex matching */
460 else if (eval_method[i] & CRIT_REGEX) {
461 excode = regexec (&preg, response, 10, pmatch, eflags);
462 if (excode == 0) {
463 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
464 }
465 else if (excode != REG_NOMATCH) {
466 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
467 printf (_("Execute Error: %s\n"), errbuf);
468 exit (STATE_CRITICAL);
469 }
470 else {
471 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
472 }
473 }
475 /* Process this block for existence-nonexistence checks */
476 /* TV: Should this be outside of this else block? */
477 else {
478 if (eval_method[i] & CRIT_PRESENT)
479 iresult = STATE_CRITICAL;
480 else if (eval_method[i] & WARN_PRESENT)
481 iresult = STATE_WARNING;
482 else if (response && iresult == STATE_DEPENDENT)
483 iresult = STATE_OK;
484 }
486 /* Result is the worst outcome of all the OIDs tested */
487 result = max_state (result, iresult);
489 /* Prepend a label for this OID if there is one */
490 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
491 asprintf (&outbuff, "%s%s%s %s%s%s", outbuff,
492 (i == 0) ? " " : output_delim,
493 labels[i], mark (iresult), show, mark (iresult));
494 else
495 asprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
496 mark (iresult), show, mark (iresult));
498 /* Append a unit string for this OID if there is one */
499 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
500 asprintf (&outbuff, "%s %s", outbuff, unitv[i]);
502 /* Write perfdata with whatever can be parsed by strtod, if possible */
503 ptr = NULL;
504 strtod(show, &ptr);
505 if (ptr > show) {
506 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
507 temp_string=labels[i];
508 else
509 temp_string=oidname;
510 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
511 strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
512 len = sizeof(perfstr)-strlen(perfstr)-1;
513 strncat(perfstr, show, len>ptr-show ? ptr-show : len);
515 if (type)
516 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
517 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
518 }
519 }
520 total_oids=i;
522 /* Save state data, as all data collected now */
523 if(calculate_rate) {
524 string_length=1024;
525 state_string=malloc(string_length);
526 if(state_string==NULL)
527 die(STATE_UNKNOWN, _("Cannot malloc"));
529 current_length=0;
530 for(i=0; i<total_oids; i++) {
531 asprintf(&temp_string,"%.0f",response_value[i]);
532 if(temp_string==NULL)
533 die(STATE_UNKNOWN,_("Cannot asprintf()"));
534 response_length = strlen(temp_string);
535 if(current_length+response_length>string_length) {
536 string_length=current_length+1024;
537 state_string=realloc(state_string,string_length);
538 if(state_string==NULL)
539 die(STATE_UNKNOWN, _("Cannot realloc()"));
540 }
541 strcpy(&state_string[current_length],temp_string);
542 current_length=current_length+response_length;
543 state_string[current_length]=':';
544 current_length++;
545 free(temp_string);
546 }
547 state_string[--current_length]='\0';
548 if (verbose > 2)
549 printf("State string=%s\n",state_string);
551 /* This is not strictly the same as time now, but any subtle variations will cancel out */
552 np_state_write_string(current_time, state_string );
553 if(previous_state==NULL) {
554 /* Or should this be highest state? */
555 die( STATE_OK, _("No previous data to calculate rate - assume okay" ) );
556 }
557 }
559 printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr);
560 if (mult_resp) printf ("%s", mult_resp);
562 return result;
563 }
567 /* process command-line arguments */
568 int
569 process_arguments (int argc, char **argv)
570 {
571 char *ptr;
572 int c = 1;
573 int j = 0, jj = 0, ii = 0;
575 int option = 0;
576 static struct option longopts[] = {
577 STD_LONG_OPTS,
578 {"community", required_argument, 0, 'C'},
579 {"oid", required_argument, 0, 'o'},
580 {"object", required_argument, 0, 'o'},
581 {"delimiter", required_argument, 0, 'd'},
582 {"output-delimiter", required_argument, 0, 'D'},
583 {"string", required_argument, 0, 's'},
584 {"timeout", required_argument, 0, 't'},
585 {"regex", required_argument, 0, 'r'},
586 {"ereg", required_argument, 0, 'r'},
587 {"eregi", required_argument, 0, 'R'},
588 {"label", required_argument, 0, 'l'},
589 {"units", required_argument, 0, 'u'},
590 {"port", required_argument, 0, 'p'},
591 {"retries", required_argument, 0, 'e'},
592 {"miblist", required_argument, 0, 'm'},
593 {"protocol", required_argument, 0, 'P'},
594 {"seclevel", required_argument, 0, 'L'},
595 {"secname", required_argument, 0, 'U'},
596 {"authproto", required_argument, 0, 'a'},
597 {"privproto", required_argument, 0, 'x'},
598 {"authpasswd", required_argument, 0, 'A'},
599 {"privpasswd", required_argument, 0, 'X'},
600 {"next", no_argument, 0, 'n'},
601 {"rate", no_argument, 0, L_CALCULATE_RATE},
602 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
603 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
604 {0, 0, 0, 0}
605 };
607 if (argc < 2)
608 return ERROR;
610 /* reverse compatibility for very old non-POSIX usage forms */
611 for (c = 1; c < argc; c++) {
612 if (strcmp ("-to", argv[c]) == 0)
613 strcpy (argv[c], "-t");
614 if (strcmp ("-wv", argv[c]) == 0)
615 strcpy (argv[c], "-w");
616 if (strcmp ("-cv", argv[c]) == 0)
617 strcpy (argv[c], "-c");
618 }
620 while (1) {
621 c = getopt_long (argc, argv, "nhvVt:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:L:U:a:x:A:X:",
622 longopts, &option);
624 if (c == -1 || c == EOF)
625 break;
627 switch (c) {
628 case '?': /* usage */
629 usage5 ();
630 case 'h': /* help */
631 print_help ();
632 exit (STATE_OK);
633 case 'V': /* version */
634 print_revision (progname, NP_VERSION);
635 exit (STATE_OK);
636 case 'v': /* verbose */
637 verbose++;
638 break;
640 /* Connection info */
641 case 'C': /* group or community */
642 community = optarg;
643 break;
644 case 'H': /* Host or server */
645 server_address = optarg;
646 break;
647 case 'p': /* TCP port number */
648 port = optarg;
649 break;
650 case 'm': /* List of MIBS */
651 miblist = optarg;
652 break;
653 case 'n': /* usesnmpgetnext */
654 usesnmpgetnext = TRUE;
655 break;
656 case 'P': /* SNMP protocol version */
657 proto = optarg;
658 break;
659 case 'L': /* security level */
660 seclevel = optarg;
661 break;
662 case 'U': /* security username */
663 secname = optarg;
664 break;
665 case 'a': /* auth protocol */
666 authproto = optarg;
667 break;
668 case 'x': /* priv protocol */
669 privproto = optarg;
670 break;
671 case 'A': /* auth passwd */
672 authpasswd = optarg;
673 break;
674 case 'X': /* priv passwd */
675 privpasswd = optarg;
676 break;
677 case 't': /* timeout period */
678 if (!is_integer (optarg))
679 usage2 (_("Timeout interval must be a positive integer"), optarg);
680 else
681 timeout_interval = atoi (optarg);
682 break;
684 /* Test parameters */
685 case 'c': /* critical threshold */
686 critical_thresholds = optarg;
687 break;
688 case 'w': /* warning threshold */
689 warning_thresholds = optarg;
690 break;
691 case 'e': /* PRELIMINARY - may change */
692 case 'E': /* PRELIMINARY - may change */
693 if (!is_integer (optarg))
694 usage2 (_("Retries interval must be a positive integer"), optarg);
695 else
696 retries = atoi(optarg);
697 break;
698 case 'o': /* object identifier */
699 if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) {
700 /*
701 * we have something other than digits, periods and comas,
702 * so we have a mib variable, rather than just an SNMP OID,
703 * so we have to actually read the mib files
704 */
705 needmibs = TRUE;
706 }
707 if (!oids) oids = calloc(MAX_OIDS, sizeof (char *));
708 for (ptr = strtok(optarg, ", "); ptr != NULL && j < MAX_OIDS; ptr = strtok(NULL, ", "), j++) {
709 oids[j] = strdup(ptr);
710 }
711 numoids = j;
712 if (c == 'E' || c == 'e') {
713 jj++;
714 ii++;
715 }
716 if (c == 'E')
717 eval_method[j+1] |= WARN_PRESENT;
718 else if (c == 'e')
719 eval_method[j+1] |= CRIT_PRESENT;
720 break;
721 case 's': /* string or substring */
722 strncpy (string_value, optarg, sizeof (string_value) - 1);
723 string_value[sizeof (string_value) - 1] = 0;
724 eval_method[jj++] = CRIT_STRING;
725 ii++;
726 break;
727 case 'R': /* regex */
728 cflags = REG_ICASE;
729 case 'r': /* regex */
730 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
731 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
732 regex_expect[sizeof (regex_expect) - 1] = 0;
733 errcode = regcomp (&preg, regex_expect, cflags);
734 if (errcode != 0) {
735 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
736 printf (_("Could Not Compile Regular Expression"));
737 return ERROR;
738 }
739 eval_method[jj++] = CRIT_REGEX;
740 ii++;
741 break;
743 /* Format */
744 case 'd': /* delimiter */
745 delimiter = strscpy (delimiter, optarg);
746 break;
747 case 'D': /* output-delimiter */
748 output_delim = strscpy (output_delim, optarg);
749 break;
750 case 'l': /* label */
751 nlabels++;
752 if (nlabels >= labels_size) {
753 labels_size += 8;
754 labels = realloc (labels, labels_size);
755 if (labels == NULL)
756 die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
757 }
758 labels[nlabels - 1] = optarg;
759 ptr = thisarg (optarg);
760 labels[nlabels - 1] = ptr;
761 if (strstr (ptr, "'") == ptr)
762 labels[nlabels - 1] = ptr + 1;
763 while (ptr && (ptr = nextarg (ptr))) {
764 if (nlabels >= labels_size) {
765 labels_size += 8;
766 labels = realloc (labels, labels_size);
767 if (labels == NULL)
768 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
769 }
770 labels++;
771 ptr = thisarg (ptr);
772 if (strstr (ptr, "'") == ptr)
773 labels[nlabels - 1] = ptr + 1;
774 else
775 labels[nlabels - 1] = ptr;
776 }
777 break;
778 case 'u': /* units */
779 units = optarg;
780 nunits++;
781 if (nunits >= unitv_size) {
782 unitv_size += 8;
783 unitv = realloc (unitv, unitv_size);
784 if (unitv == NULL)
785 die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
786 }
787 unitv[nunits - 1] = optarg;
788 ptr = thisarg (optarg);
789 unitv[nunits - 1] = ptr;
790 if (strstr (ptr, "'") == ptr)
791 unitv[nunits - 1] = ptr + 1;
792 while (ptr && (ptr = nextarg (ptr))) {
793 if (nunits >= unitv_size) {
794 unitv_size += 8;
795 unitv = realloc (unitv, unitv_size);
796 if (units == NULL)
797 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
798 }
799 nunits++;
800 ptr = thisarg (ptr);
801 if (strstr (ptr, "'") == ptr)
802 unitv[nunits - 1] = ptr + 1;
803 else
804 unitv[nunits - 1] = ptr;
805 }
806 break;
807 case L_CALCULATE_RATE:
808 if(calculate_rate==0)
809 np_enable_state(NULL, 1);
810 calculate_rate = 1;
811 break;
812 case L_RATE_MULTIPLIER:
813 if(!is_integer(optarg)||((rate_multiplier=atoi(optarg))<=0))
814 usage2(_("Rate multiplier must be a positive integer"),optarg);
815 break;
816 case L_INVERT_SEARCH:
817 invert_search=1;
818 break;
819 }
820 }
822 if (server_address == NULL)
823 server_address = argv[optind];
825 if (community == NULL)
826 community = strdup (DEFAULT_COMMUNITY);
828 return validate_arguments ();
829 }
832 /******************************************************************************
834 @@-
835 <sect3>
836 <title>validate_arguments</title>
838 <para>&PROTO_validate_arguments;</para>
840 <para>Checks to see if the default miblist needs to be loaded. Also verifies
841 the authentication and authorization combinations based on protocol version
842 selected.</para>
844 <para></para>
846 </sect3>
847 -@@
848 ******************************************************************************/
852 int
853 validate_arguments ()
854 {
855 /* check whether to load locally installed MIBS (CPU/disk intensive) */
856 if (miblist == NULL) {
857 if ( needmibs == TRUE ) {
858 miblist = strdup (DEFAULT_MIBLIST);
859 }else{
860 miblist = ""; /* don't read any mib files for numeric oids */
861 }
862 }
864 /* Check server_address is given */
865 if (server_address == NULL)
866 die(STATE_UNKNOWN, _("No host specified\n"));
868 /* Check oid is given */
869 if (numoids == 0)
870 die(STATE_UNKNOWN, _("No OIDs specified\n"));
872 if (proto == NULL)
873 asprintf(&proto, DEFAULT_PROTOCOL);
875 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */
876 numauthpriv = 2;
877 authpriv = calloc (numauthpriv, sizeof (char *));
878 authpriv[0] = strdup ("-c");
879 authpriv[1] = strdup (community);
880 }
881 else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */
882 if (seclevel == NULL)
883 asprintf(&seclevel, "noAuthNoPriv");
885 if (strcmp(seclevel, "noAuthNoPriv") == 0) {
886 numauthpriv = 2;
887 authpriv = calloc (numauthpriv, sizeof (char *));
888 authpriv[0] = strdup ("-l");
889 authpriv[1] = strdup ("noAuthNoPriv");
890 } else {
891 if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
892 usage2 (_("Invalid seclevel"), seclevel);
893 }
895 if (authproto == NULL )
896 asprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
898 if (secname == NULL)
899 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
901 if (authpasswd == NULL)
902 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
904 if ( strcmp(seclevel, "authNoPriv") == 0 ) {
905 numauthpriv = 8;
906 authpriv = calloc (numauthpriv, sizeof (char *));
907 authpriv[0] = strdup ("-l");
908 authpriv[1] = strdup ("authNoPriv");
909 authpriv[2] = strdup ("-a");
910 authpriv[3] = strdup (authproto);
911 authpriv[4] = strdup ("-u");
912 authpriv[5] = strdup (secname);
913 authpriv[6] = strdup ("-A");
914 authpriv[7] = strdup (authpasswd);
915 } else if ( strcmp(seclevel, "authPriv") == 0 ) {
916 if (privproto == NULL )
917 asprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
919 if (privpasswd == NULL)
920 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
922 numauthpriv = 12;
923 authpriv = calloc (numauthpriv, sizeof (char *));
924 authpriv[0] = strdup ("-l");
925 authpriv[1] = strdup ("authPriv");
926 authpriv[2] = strdup ("-a");
927 authpriv[3] = strdup (authproto);
928 authpriv[4] = strdup ("-u");
929 authpriv[5] = strdup (secname);
930 authpriv[6] = strdup ("-A");
931 authpriv[7] = strdup (authpasswd);
932 authpriv[8] = strdup ("-x");
933 authpriv[9] = strdup (privproto);
934 authpriv[10] = strdup ("-X");
935 authpriv[11] = strdup (privpasswd);
936 }
937 }
939 }
940 else {
941 usage2 (_("Invalid SNMP version"), proto);
942 }
944 return OK;
945 }
949 /* trim leading whitespace
950 if there is a leading quote, make sure it balances */
952 char *
953 thisarg (char *str)
954 {
955 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
956 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */
957 if (strlen (str) == 1 || !strstr (str + 1, "'"))
958 die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
959 }
960 return str;
961 }
965 /* if there's a leading quote, advance to the trailing quote
966 set the trailing quote to '\x0'
967 if the string continues, advance beyond the comma */
969 char *
970 nextarg (char *str)
971 {
972 if (strstr (str, "'") == str) {
973 str[0] = 0;
974 if (strlen (str) > 1) {
975 str = strstr (str + 1, "'");
976 return (++str);
977 }
978 else {
979 return NULL;
980 }
981 }
982 if (strstr (str, ",") == str) {
983 str[0] = 0;
984 if (strlen (str) > 1) {
985 return (++str);
986 }
987 else {
988 return NULL;
989 }
990 }
991 if ((str = strstr (str, ",")) && strlen (str) > 1) {
992 str[0] = 0;
993 return (++str);
994 }
995 return NULL;
996 }
1000 void
1001 print_help (void)
1002 {
1003 print_revision (progname, NP_VERSION);
1005 printf (COPYRIGHT, copyright, email);
1007 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1009 printf ("\n\n");
1011 print_usage ();
1013 printf (UT_HELP_VRSN);
1014 printf (UT_EXTRA_OPTS);
1016 printf (UT_HOST_PORT, 'p', DEFAULT_PORT);
1018 /* SNMP and Authentication Protocol */
1019 printf (" %s\n", "-n, --next");
1020 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1021 printf (" %s\n", "-P, --protocol=[1|2c|3]");
1022 printf (" %s\n", _("SNMP protocol version"));
1023 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1024 printf (" %s\n", _("SNMPv3 securityLevel"));
1025 printf (" %s\n", "-a, --authproto=[MD5|SHA]");
1026 printf (" %s\n", _("SNMPv3 auth proto"));
1027 printf (" %s\n", "-x, --privproto=[DES|AES]");
1028 printf (" %s\n", _("SNMPv3 priv proto (default DES)"));
1030 /* Authentication Tokens*/
1031 printf (" %s\n", "-C, --community=STRING");
1032 printf (" %s ", _("Optional community string for SNMP communication"));
1033 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
1034 printf (" %s\n", "-U, --secname=USERNAME");
1035 printf (" %s\n", _("SNMPv3 username"));
1036 printf (" %s\n", "-A, --authpassword=PASSWORD");
1037 printf (" %s\n", _("SNMPv3 authentication password"));
1038 printf (" %s\n", "-X, --privpasswd=PASSWORD");
1039 printf (" %s\n", _("SNMPv3 privacy password"));
1041 /* OID Stuff */
1042 printf (" %s\n", "-o, --oid=OID(s)");
1043 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1044 printf (" %s\n", "-m, --miblist=STRING");
1045 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1046 printf (" %s\n", _("for symbolic OIDs.)"));
1047 printf (" %s\n", "-d, --delimiter=STRING");
1048 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
1049 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1050 printf (" %s\n", _("to be the data that should be used in the evaluation."));
1052 /* Tests Against Integers */
1053 printf (" %s\n", "-w, --warning=THRESHOLD(s)");
1054 printf (" %s\n", _("Warning threshold range(s)"));
1055 printf (" %s\n", "-c, --critical=THRESHOLD(s)");
1056 printf (" %s\n", _("Critical threshold range(s)"));
1057 printf (" %s\n", "--rate");
1058 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1059 printf (" %s\n", "--rate-multiplier");
1060 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1062 /* Tests Against Strings */
1063 printf (" %s\n", "-s, --string=STRING");
1064 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1065 printf (" %s\n", "-r, --ereg=REGEX");
1066 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1067 printf (" %s\n", "-R, --eregi=REGEX");
1068 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1069 printf (" %s\n", "--invert-search");
1070 printf (" %s\n", _("Invert search result (CRITICAL if found)"));
1072 /* Output Formatting */
1073 printf (" %s\n", "-l, --label=STRING");
1074 printf (" %s\n", _("Prefix label for output from plugin"));
1075 printf (" %s\n", "-u, --units=STRING");
1076 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1077 printf (" %s\n", "-D, --output-delimiter=STRING");
1078 printf (" %s\n", _("Separates output on multiple OID requests"));
1080 printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1081 printf (" %s\n", "-e, --retries=INTEGER");
1082 printf (" %s\n", _("Number of retries to be used in the requests"));
1084 printf (UT_VERBOSE);
1086 printf ("\n");
1087 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1088 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1089 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1091 printf ("\n");
1092 printf ("%s\n", _("Notes:"));
1093 printf (" %s\n", _("- Multiple OIDs may be indicated by a comma or space-delimited list (lists with"));
1094 printf (" %s %i %s\n", _("internal spaces must be quoted). Maximum:"), MAX_OIDS, _("OIDs."));
1096 printf(" -%s", UT_THRESHOLDS_NOTES);
1098 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1099 printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1100 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1101 printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
1103 printf("\n");
1104 printf("%s\n", _("Rate Calculation:"));
1105 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1106 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1107 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1108 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1109 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1110 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1111 printf(" %s\n", _("changing the arguments will create a new state file."));
1113 printf (UT_SUPPORT);
1114 }
1118 void
1119 print_usage (void)
1120 {
1121 printf ("%s\n", _("Usage:"));
1122 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname);
1123 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1124 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1125 printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
1126 printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");
1127 }