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