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 CRIT_GT 8
57 #define CRIT_LT 16
58 #define CRIT_GE 32
59 #define CRIT_LE 64
60 #define CRIT_EQ 128
61 #define CRIT_NE 256
62 #define CRIT_RANGE 512
63 #define WARN_PRESENT 1024
64 #define WARN_STRING 2048
65 #define WARN_REGEX 4096
66 #define WARN_GT 8192
67 #define WARN_LT 16384
68 #define WARN_GE 32768
69 #define WARN_LE 65536
70 #define WARN_EQ 131072
71 #define WARN_NE 262144
72 #define WARN_RANGE 524288
74 #define MAX_OIDS 8
75 #define MAX_DELIM_LENGTH 8
77 int process_arguments (int, char **);
78 int validate_arguments (void);
79 char *clarify_message (char *);
80 int check_num (int);
81 int llu_getll (unsigned long long *, char *);
82 int llu_getul (unsigned long long *, char *);
83 char *thisarg (char *str);
84 char *nextarg (char *str);
85 void print_usage (void);
86 void print_help (void);
88 #include "regex.h"
89 char regex_expect[MAX_INPUT_BUFFER] = "";
90 regex_t preg;
91 regmatch_t pmatch[10];
92 char timestamp[10] = "";
93 char errbuf[MAX_INPUT_BUFFER] = "";
94 char perfstr[MAX_INPUT_BUFFER] = "| ";
95 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
96 int eflags = 0;
97 int errcode, excode;
99 char *server_address = NULL;
100 char *community = NULL;
101 char **authpriv = NULL;
102 char *proto = NULL;
103 char *seclevel = NULL;
104 char *secname = NULL;
105 char *authproto = NULL;
106 char *privproto = NULL;
107 char *authpasswd = NULL;
108 char *privpasswd = NULL;
109 char **oids = NULL;
110 char *label;
111 char *units;
112 char *port;
113 char *snmpcmd;
114 char string_value[MAX_INPUT_BUFFER] = "";
115 char **labels = NULL;
116 char **unitv = NULL;
117 size_t nlabels = 0;
118 size_t labels_size = 8;
119 size_t nunits = 0;
120 size_t unitv_size = 8;
121 int numoids = 0;
122 int numauthpriv = 0;
123 int verbose = FALSE;
124 int usesnmpgetnext = FALSE;
125 unsigned long long lower_warn_lim[MAX_OIDS];
126 unsigned long long upper_warn_lim[MAX_OIDS];
127 unsigned long long lower_crit_lim[MAX_OIDS];
128 unsigned long long upper_crit_lim[MAX_OIDS];
129 unsigned long long response_value[MAX_OIDS];
130 int check_warning_value = FALSE;
131 int check_critical_value = FALSE;
132 int retries = 0;
133 unsigned long long eval_method[MAX_OIDS];
134 char *delimiter;
135 char *output_delim;
136 char *miblist = NULL;
137 int needmibs = FALSE;
140 int
141 main (int argc, char **argv)
142 {
143 int i = 0;
144 int iresult = STATE_UNKNOWN;
145 int result = STATE_UNKNOWN;
146 int return_code = 0;
147 int external_error = 0;
148 char **command_line = NULL;
149 char *cl_hidden_auth = NULL;
150 char *oidname = NULL;
151 char *response = NULL;
152 char *outbuff;
153 char *ptr = NULL;
154 char *show = NULL;
155 char type[8] = "";
156 output chld_out, chld_err;
158 setlocale (LC_ALL, "");
159 bindtextdomain (PACKAGE, LOCALEDIR);
160 textdomain (PACKAGE);
162 labels = malloc (labels_size);
163 unitv = malloc (unitv_size);
164 for (i = 0; i < MAX_OIDS; i++)
165 eval_method[i] = CHECK_UNDEF;
166 i = 0;
168 label = strdup ("SNMP");
169 units = strdup ("");
170 port = strdup (DEFAULT_PORT);
171 outbuff = strdup ("");
172 delimiter = strdup (" = ");
173 output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
174 /* miblist = strdup (DEFAULT_MIBLIST); */
175 timeout_interval = DEFAULT_TIMEOUT;
176 retries = DEFAULT_RETRIES;
178 /* Parse extra opts if any */
179 argv=np_extra_opts (&argc, argv, progname);
181 if (process_arguments (argc, argv) == ERROR)
182 usage4 (_("Could not parse arguments"));
184 /* Create the command array to execute */
185 if(usesnmpgetnext == TRUE) {
186 snmpcmd = strdup (PATH_TO_SNMPGETNEXT);
187 }else{
188 snmpcmd = strdup (PATH_TO_SNMPGET);
189 }
191 /* 9 arguments to pass before authpriv options + 1 for host and numoids. Add one for terminating NULL */
192 command_line = calloc (9 + numauthpriv + 1 + numoids + 1, sizeof (char *));
193 command_line[0] = snmpcmd;
194 command_line[1] = strdup ("-t");
195 asprintf (&command_line[2], "%d", timeout_interval);
196 command_line[3] = strdup ("-r");
197 asprintf (&command_line[4], "%d", retries);
198 command_line[5] = strdup ("-m");
199 command_line[6] = strdup (miblist);
200 command_line[7] = "-v";
201 command_line[8] = strdup (proto);
203 for (i = 0; i < numauthpriv; i++) {
204 command_line[9 + i] = authpriv[i];
205 }
207 asprintf (&command_line[9 + numauthpriv], "%s:%s", server_address, port);
209 /* This is just for display purposes, so it can remain a string */
210 asprintf(&cl_hidden_auth, "%s -t %d -r %d -m %s -v %s %s %s:%s",
211 snmpcmd, timeout_interval, retries, miblist, proto, "[authpriv]",
212 server_address, port);
214 for (i = 0; i < numoids; i++) {
215 command_line[9 + numauthpriv + 1 + i] = oids[i];
216 asprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
217 }
219 command_line[9 + numauthpriv + 1 + numoids] = NULL;
221 if (verbose)
222 printf ("%s\n", cl_hidden_auth);
224 /* Run the command */
225 return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0);
227 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
228 only return state unknown if return code is non zero or there is no stdout.
229 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
230 */
231 if (return_code != 0)
232 external_error=1;
233 if (chld_out.lines == 0)
234 external_error=1;
235 if (external_error) {
236 if (chld_err.lines > 0) {
237 printf (_("External command error: %s\n"), chld_err.line[0]);
238 for (i = 1; i < chld_err.lines; i++) {
239 printf ("%s\n", chld_err.line[i]);
240 }
241 } else {
242 printf(_("External command error with no output (return code: %d)\n"), return_code);
243 }
244 exit (STATE_UNKNOWN);
245 }
247 if (verbose) {
248 for (i = 0; i < chld_out.lines; i++) {
249 printf ("%s\n", chld_out.line[i]);
250 }
251 }
253 for (i = 0; i < chld_out.lines; i++) {
254 ptr = chld_out.line[i];
255 oidname = strpcpy (oidname, ptr, delimiter);
256 response = strstr (ptr, delimiter);
258 /* We strip out the datatype indicator for PHBs */
260 /* Clean up type array - Sol10 does not necessarily zero it out */
261 bzero(type, sizeof(type));
263 if (strstr (response, "Gauge: "))
264 show = strstr (response, "Gauge: ") + 7;
265 else if (strstr (response, "Gauge32: "))
266 show = strstr (response, "Gauge32: ") + 9;
267 else if (strstr (response, "Counter32: ")) {
268 show = strstr (response, "Counter32: ") + 11;
269 strcpy(type, "c");
270 }
271 else if (strstr (response, "Counter64: ")) {
272 show = strstr (response, "Counter64: ") + 11;
273 strcpy(type, "c");
274 }
275 else if (strstr (response, "INTEGER: "))
276 show = strstr (response, "INTEGER: ") + 9;
277 else if (strstr (response, "STRING: "))
278 show = strstr (response, "STRING: ") + 8;
279 else
280 show = response;
282 iresult = STATE_DEPENDENT;
284 /* Process this block for integer comparisons */
285 if (eval_method[i] & CRIT_GT ||
286 eval_method[i] & CRIT_LT ||
287 eval_method[i] & CRIT_GE ||
288 eval_method[i] & CRIT_LE ||
289 eval_method[i] & CRIT_EQ ||
290 eval_method[i] & CRIT_NE ||
291 eval_method[i] & WARN_GT ||
292 eval_method[i] & WARN_LT ||
293 eval_method[i] & WARN_GE ||
294 eval_method[i] & WARN_LE ||
295 eval_method[i] & WARN_EQ ||
296 eval_method[i] & WARN_NE) {
297 ptr = strpbrk (show, "0123456789");
298 if (ptr == NULL)
299 die (STATE_UNKNOWN,_("No valid data returned"));
300 response_value[i] = strtoul (ptr, NULL, 10);
301 iresult = check_num (i);
302 asprintf (&show, "%llu", response_value[i]);
303 }
305 /* Process this block for string matching */
306 else if (eval_method[i] & CRIT_STRING) {
307 if (strcmp (show, string_value))
308 iresult = STATE_CRITICAL;
309 else
310 iresult = STATE_OK;
311 }
313 /* Process this block for regex matching */
314 else if (eval_method[i] & CRIT_REGEX) {
315 excode = regexec (&preg, response, 10, pmatch, eflags);
316 if (excode == 0) {
317 iresult = STATE_OK;
318 }
319 else if (excode != REG_NOMATCH) {
320 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
321 printf (_("Execute Error: %s\n"), errbuf);
322 exit (STATE_CRITICAL);
323 }
324 else {
325 iresult = STATE_CRITICAL;
326 }
327 }
329 /* Process this block for existence-nonexistence checks */
330 else {
331 if (eval_method[i] & CRIT_PRESENT)
332 iresult = STATE_CRITICAL;
333 else if (eval_method[i] & WARN_PRESENT)
334 iresult = STATE_WARNING;
335 else if (response && iresult == STATE_DEPENDENT)
336 iresult = STATE_OK;
337 }
339 /* Result is the worst outcome of all the OIDs tested */
340 result = max_state (result, iresult);
342 /* Prepend a label for this OID if there is one */
343 if (nlabels > (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
344 asprintf (&outbuff, "%s%s%s %s%s%s", outbuff,
345 (i == 0) ? " " : output_delim,
346 labels[i], mark (iresult), show, mark (iresult));
347 else
348 asprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
349 mark (iresult), show, mark (iresult));
351 /* Append a unit string for this OID if there is one */
352 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
353 asprintf (&outbuff, "%s %s", outbuff, unitv[i]);
355 if (is_numeric(show)) {
356 strncat(perfstr, oidname, sizeof(perfstr)-strlen(perfstr)-1);
357 strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
358 strncat(perfstr, show, sizeof(perfstr)-strlen(perfstr)-1);
360 if (type)
361 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
362 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
363 }
364 }
366 /* if (nunits == 1 || i == 1) */
367 /* printf ("%s %s -%s %s\n", label, state_text (result), outbuff, units); */
368 /* else */
369 printf ("%s %s -%s %s \n", label, state_text (result), outbuff, perfstr);
371 return result;
372 }
376 /* process command-line arguments */
377 int
378 process_arguments (int argc, char **argv)
379 {
380 char *ptr;
381 int c = 1;
382 int j = 0, jj = 0, ii = 0;
384 int option = 0;
385 static struct option longopts[] = {
386 STD_LONG_OPTS,
387 {"community", required_argument, 0, 'C'},
388 {"oid", required_argument, 0, 'o'},
389 {"object", required_argument, 0, 'o'},
390 {"delimiter", required_argument, 0, 'd'},
391 {"output-delimiter", required_argument, 0, 'D'},
392 {"string", required_argument, 0, 's'},
393 {"timeout", required_argument, 0, 't'},
394 {"regex", required_argument, 0, 'r'},
395 {"ereg", required_argument, 0, 'r'},
396 {"eregi", required_argument, 0, 'R'},
397 {"label", required_argument, 0, 'l'},
398 {"units", required_argument, 0, 'u'},
399 {"port", required_argument, 0, 'p'},
400 {"retries", required_argument, 0, 'e'},
401 {"miblist", required_argument, 0, 'm'},
402 {"protocol", required_argument, 0, 'P'},
403 {"seclevel", required_argument, 0, 'L'},
404 {"secname", required_argument, 0, 'U'},
405 {"authproto", required_argument, 0, 'a'},
406 {"privproto", required_argument, 0, 'x'},
407 {"authpasswd", required_argument, 0, 'A'},
408 {"privpasswd", required_argument, 0, 'X'},
409 {"next", no_argument, 0, 'n'},
410 {0, 0, 0, 0}
411 };
413 if (argc < 2)
414 return ERROR;
416 /* reverse compatibility for very old non-POSIX usage forms */
417 for (c = 1; c < argc; c++) {
418 if (strcmp ("-to", argv[c]) == 0)
419 strcpy (argv[c], "-t");
420 if (strcmp ("-wv", argv[c]) == 0)
421 strcpy (argv[c], "-w");
422 if (strcmp ("-cv", argv[c]) == 0)
423 strcpy (argv[c], "-c");
424 }
426 while (1) {
427 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:",
428 longopts, &option);
430 if (c == -1 || c == EOF)
431 break;
433 switch (c) {
434 case '?': /* usage */
435 usage5 ();
436 case 'h': /* help */
437 print_help ();
438 exit (STATE_OK);
439 case 'V': /* version */
440 print_revision (progname, NP_VERSION);
441 exit (STATE_OK);
442 case 'v': /* verbose */
443 verbose = TRUE;
444 break;
446 /* Connection info */
447 case 'C': /* group or community */
448 community = optarg;
449 break;
450 case 'H': /* Host or server */
451 server_address = optarg;
452 break;
453 case 'p': /* TCP port number */
454 port = optarg;
455 break;
456 case 'm': /* List of MIBS */
457 miblist = optarg;
458 break;
459 case 'n': /* usesnmpgetnext */
460 usesnmpgetnext = TRUE;
461 break;
462 case 'P': /* SNMP protocol version */
463 proto = optarg;
464 break;
465 case 'L': /* security level */
466 seclevel = optarg;
467 break;
468 case 'U': /* security username */
469 secname = optarg;
470 break;
471 case 'a': /* auth protocol */
472 authproto = optarg;
473 break;
474 case 'x': /* priv protocol */
475 privproto = optarg;
476 break;
477 case 'A': /* auth passwd */
478 authpasswd = optarg;
479 break;
480 case 'X': /* priv passwd */
481 privpasswd = optarg;
482 break;
483 case 't': /* timeout period */
484 if (!is_integer (optarg))
485 usage2 (_("Timeout interval must be a positive integer"), optarg);
486 else
487 timeout_interval = atoi (optarg);
488 break;
490 /* Test parameters */
491 case 'c': /* critical time threshold */
492 if (strspn (optarg, "0123456789:,") < strlen (optarg))
493 usage2 (_("Invalid critical threshold"), optarg);
494 for (ptr = optarg; ptr && jj < MAX_OIDS; jj++) {
495 if (llu_getll (&lower_crit_lim[jj], ptr) == 1)
496 eval_method[jj] |= CRIT_LT;
497 if (llu_getul (&upper_crit_lim[jj], ptr) == 1)
498 eval_method[jj] |= CRIT_GT;
499 (ptr = index (ptr, ',')) ? ptr++ : ptr;
500 }
501 break;
502 case 'w': /* warning time threshold */
503 if (strspn (optarg, "0123456789:,") < strlen (optarg))
504 usage2 (_("Invalid warning threshold"), optarg);
505 for (ptr = optarg; ptr && ii < MAX_OIDS; ii++) {
506 if (llu_getll (&lower_warn_lim[ii], ptr) == 1)
507 eval_method[ii] |= WARN_LT;
508 if (llu_getul (&upper_warn_lim[ii], ptr) == 1)
509 eval_method[ii] |= WARN_GT;
510 (ptr = index (ptr, ',')) ? ptr++ : ptr;
511 }
512 break;
513 case 'e': /* PRELIMINARY - may change */
514 case 'E': /* PRELIMINARY - may change */
515 if (!is_integer (optarg))
516 usage2 (_("Retries interval must be a positive integer"), optarg);
517 else
518 retries = atoi(optarg);
519 break;
520 case 'o': /* object identifier */
521 if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) {
522 /*
523 * we have something other than digits, periods and comas,
524 * so we have a mib variable, rather than just an SNMP OID,
525 * so we have to actually read the mib files
526 */
527 needmibs = TRUE;
528 }
529 oids = calloc(MAX_OIDS, sizeof (char *));
530 for (ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", ")) {
531 oids[j] = strdup(ptr);
532 j++;
533 }
534 numoids = j;
535 if (c == 'E' || c == 'e') {
536 jj++;
537 ii++;
538 }
539 if (c == 'E')
540 eval_method[j+1] |= WARN_PRESENT;
541 else if (c == 'e')
542 eval_method[j+1] |= CRIT_PRESENT;
543 break;
544 case 's': /* string or substring */
545 strncpy (string_value, optarg, sizeof (string_value) - 1);
546 string_value[sizeof (string_value) - 1] = 0;
547 eval_method[jj++] = CRIT_STRING;
548 ii++;
549 break;
550 case 'R': /* regex */
551 cflags = REG_ICASE;
552 case 'r': /* regex */
553 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
554 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
555 regex_expect[sizeof (regex_expect) - 1] = 0;
556 errcode = regcomp (&preg, regex_expect, cflags);
557 if (errcode != 0) {
558 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
559 printf (_("Could Not Compile Regular Expression"));
560 return ERROR;
561 }
562 eval_method[jj++] = CRIT_REGEX;
563 ii++;
564 break;
566 /* Format */
567 case 'd': /* delimiter */
568 delimiter = strscpy (delimiter, optarg);
569 break;
570 case 'D': /* output-delimiter */
571 output_delim = strscpy (output_delim, optarg);
572 break;
573 case 'l': /* label */
574 label = optarg;
575 nlabels++;
576 if (nlabels >= labels_size) {
577 labels_size += 8;
578 labels = realloc (labels, labels_size);
579 if (labels == NULL)
580 die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
581 }
582 labels[nlabels - 1] = optarg;
583 ptr = thisarg (optarg);
584 labels[nlabels - 1] = ptr;
585 if (strstr (ptr, "'") == ptr)
586 labels[nlabels - 1] = ptr + 1;
587 while (ptr && (ptr = nextarg (ptr))) {
588 if (nlabels >= labels_size) {
589 labels_size += 8;
590 labels = realloc (labels, labels_size);
591 if (labels == NULL)
592 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
593 }
594 labels++;
595 ptr = thisarg (ptr);
596 if (strstr (ptr, "'") == ptr)
597 labels[nlabels - 1] = ptr + 1;
598 else
599 labels[nlabels - 1] = ptr;
600 }
601 break;
602 case 'u': /* units */
603 units = optarg;
604 nunits++;
605 if (nunits >= unitv_size) {
606 unitv_size += 8;
607 unitv = realloc (unitv, unitv_size);
608 if (unitv == NULL)
609 die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
610 }
611 unitv[nunits - 1] = optarg;
612 ptr = thisarg (optarg);
613 unitv[nunits - 1] = ptr;
614 if (strstr (ptr, "'") == ptr)
615 unitv[nunits - 1] = ptr + 1;
616 while (ptr && (ptr = nextarg (ptr))) {
617 if (nunits >= unitv_size) {
618 unitv_size += 8;
619 unitv = realloc (unitv, unitv_size);
620 if (units == NULL)
621 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
622 }
623 nunits++;
624 ptr = thisarg (ptr);
625 if (strstr (ptr, "'") == ptr)
626 unitv[nunits - 1] = ptr + 1;
627 else
628 unitv[nunits - 1] = ptr;
629 }
630 break;
632 }
633 }
635 if (server_address == NULL)
636 server_address = argv[optind];
638 if (community == NULL)
639 community = strdup (DEFAULT_COMMUNITY);
641 return validate_arguments ();
642 }
645 /******************************************************************************
647 @@-
648 <sect3>
649 <title>validate_arguments</title>
651 <para>&PROTO_validate_arguments;</para>
653 <para>Checks to see if the default miblist needs to be loaded. Also verifies
654 the authentication and authorization combinations based on protocol version
655 selected.</para>
657 <para></para>
659 </sect3>
660 -@@
661 ******************************************************************************/
665 int
666 validate_arguments ()
667 {
668 /* check whether to load locally installed MIBS (CPU/disk intensive) */
669 if (miblist == NULL) {
670 if ( needmibs == TRUE ) {
671 miblist = strdup (DEFAULT_MIBLIST);
672 }else{
673 miblist = "''"; /* don't read any mib files for numeric oids */
674 }
675 }
677 /* Check server_address is given */
678 if (server_address == NULL)
679 die(STATE_UNKNOWN, _("No host specified\n"));
681 /* Check oid is given */
682 if (numoids == 0)
683 die(STATE_UNKNOWN, _("No OIDs specified\n"));
685 if (proto == NULL)
686 asprintf(&proto, DEFAULT_PROTOCOL);
688 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */
689 numauthpriv = 2;
690 authpriv = calloc (numauthpriv, sizeof (char *));
691 authpriv[0] = strdup ("-c");
692 authpriv[1] = strdup (community);
693 }
694 else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */
695 if (seclevel == NULL)
696 asprintf(&seclevel, "noAuthNoPriv");
698 if (strcmp(seclevel, "noAuthNoPriv") == 0) {
699 numauthpriv = 2;
700 authpriv = calloc (numauthpriv, sizeof (char *));
701 authpriv[0] = strdup ("-l");
702 authpriv[1] = strdup ("noAuthNoPriv");
703 } else {
704 if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
705 usage2 (_("Invalid seclevel"), seclevel);
706 }
708 if (authproto == NULL )
709 asprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
711 if (secname == NULL)
712 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
714 if (authpasswd == NULL)
715 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
717 if ( strcmp(seclevel, "authNoPriv") == 0 ) {
718 numauthpriv = 8;
719 authpriv = calloc (numauthpriv, sizeof (char *));
720 authpriv[0] = strdup ("-l");
721 authpriv[1] = strdup ("authNoPriv");
722 authpriv[2] = strdup ("-a");
723 authpriv[3] = strdup (authproto);
724 authpriv[4] = strdup ("-u");
725 authpriv[5] = strdup (secname);
726 authpriv[6] = strdup ("-A");
727 authpriv[7] = strdup (authpasswd);
728 } else if ( strcmp(seclevel, "authPriv") == 0 ) {
729 if (privproto == NULL )
730 asprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
732 if (privpasswd == NULL)
733 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
735 numauthpriv = 12;
736 authpriv = calloc (numauthpriv, sizeof (char *));
737 authpriv[0] = strdup ("-l");
738 authpriv[1] = strdup ("authPriv");
739 authpriv[2] = strdup ("-a");
740 authpriv[3] = strdup (authproto);
741 authpriv[4] = strdup ("-u");
742 authpriv[5] = strdup (secname);
743 authpriv[6] = strdup ("-A");
744 authpriv[7] = strdup (authpasswd);
745 authpriv[8] = strdup ("-x");
746 authpriv[9] = strdup (privproto);
747 authpriv[10] = strdup ("-X");
748 authpriv[11] = strdup (privpasswd);
749 }
750 }
752 }
753 else {
754 usage2 (_("Invalid SNMP version"), proto);
755 }
757 return OK;
758 }
762 char *
763 clarify_message (char *msg)
764 {
765 int i = 0;
766 int foo;
767 char tmpmsg_c[MAX_INPUT_BUFFER];
768 char *tmpmsg = (char *) &tmpmsg_c;
769 tmpmsg = strcpy (tmpmsg, msg);
770 if (!strncmp (tmpmsg, " Hex:", 5)) {
771 tmpmsg = strtok (tmpmsg, ":");
772 while ((tmpmsg = strtok (NULL, " "))) {
773 foo = strtol (tmpmsg, NULL, 16);
774 /* Translate chars that are not the same value in the printers
775 * character set.
776 */
777 switch (foo) {
778 case 208:
779 {
780 foo = 197;
781 break;
782 }
783 case 216:
784 {
785 foo = 196;
786 break;
787 }
788 }
789 msg[i] = foo;
790 i++;
791 }
792 msg[i] = 0;
793 }
794 return (msg);
795 }
799 int
800 check_num (int i)
801 {
802 int result;
803 result = STATE_OK;
804 if (eval_method[i] & WARN_GT && eval_method[i] & WARN_LT &&
805 lower_warn_lim[i] > upper_warn_lim[i]) {
806 if (response_value[i] <= lower_warn_lim[i] &&
807 response_value[i] >= upper_warn_lim[i]) {
808 result = STATE_WARNING;
809 }
810 }
811 else if
812 ((eval_method[i] & WARN_GT && response_value[i] > upper_warn_lim[i]) ||
813 (eval_method[i] & WARN_GE && response_value[i] >= upper_warn_lim[i]) ||
814 (eval_method[i] & WARN_LT && response_value[i] < lower_warn_lim[i]) ||
815 (eval_method[i] & WARN_LE && response_value[i] <= lower_warn_lim[i]) ||
816 (eval_method[i] & WARN_EQ && response_value[i] == upper_warn_lim[i]) ||
817 (eval_method[i] & WARN_NE && response_value[i] != upper_warn_lim[i])) {
818 result = STATE_WARNING;
819 }
821 if (eval_method[i] & CRIT_GT && eval_method[i] & CRIT_LT &&
822 lower_crit_lim[i] > upper_crit_lim[i]) {
823 if (response_value[i] <= lower_crit_lim[i] &&
824 response_value[i] >= upper_crit_lim[i]) {
825 result = STATE_CRITICAL;
826 }
827 }
828 else if
829 ((eval_method[i] & CRIT_GT && response_value[i] > upper_crit_lim[i]) ||
830 (eval_method[i] & CRIT_GE && response_value[i] >= upper_crit_lim[i]) ||
831 (eval_method[i] & CRIT_LT && response_value[i] < lower_crit_lim[i]) ||
832 (eval_method[i] & CRIT_LE && response_value[i] <= lower_crit_lim[i]) ||
833 (eval_method[i] & CRIT_EQ && response_value[i] == upper_crit_lim[i]) ||
834 (eval_method[i] & CRIT_NE && response_value[i] != upper_crit_lim[i])) {
835 result = STATE_CRITICAL;
836 }
838 return result;
839 }
843 int
844 llu_getll (unsigned long long *ll, char *str)
845 {
846 char tmp[100];
847 if (strchr (str, ':') == NULL)
848 return 0;
849 if (strchr (str, ',') != NULL && (strchr (str, ',') < strchr (str, ':')))
850 return 0;
851 if (sscanf (str, "%llu%[:]", ll, tmp) == 2)
852 return 1;
853 return 0;
854 }
858 int
859 llu_getul (unsigned long long *ul, char *str)
860 {
861 char tmp[100];
862 if (sscanf (str, "%llu%[^,]", ul, tmp) == 1)
863 return 1;
864 if (sscanf (str, ":%llu%[^,]", ul, tmp) == 1)
865 return 1;
866 if (sscanf (str, "%*u:%llu%[^,]", ul, tmp) == 1)
867 return 1;
868 return 0;
869 }
873 /* trim leading whitespace
874 if there is a leading quote, make sure it balances */
876 char *
877 thisarg (char *str)
878 {
879 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
880 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */
881 if (strlen (str) == 1 || !strstr (str + 1, "'"))
882 die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
883 }
884 return str;
885 }
889 /* if there's a leading quote, advance to the trailing quote
890 set the trailing quote to '\x0'
891 if the string continues, advance beyond the comma */
893 char *
894 nextarg (char *str)
895 {
896 if (strstr (str, "'") == str) {
897 str[0] = 0;
898 if (strlen (str) > 1) {
899 str = strstr (str + 1, "'");
900 return (++str);
901 }
902 else {
903 return NULL;
904 }
905 }
906 if (strstr (str, ",") == str) {
907 str[0] = 0;
908 if (strlen (str) > 1) {
909 return (++str);
910 }
911 else {
912 return NULL;
913 }
914 }
915 if ((str = strstr (str, ",")) && strlen (str) > 1) {
916 str[0] = 0;
917 return (++str);
918 }
919 return NULL;
920 }
924 void
925 print_help (void)
926 {
927 print_revision (progname, NP_VERSION);
929 printf (COPYRIGHT, copyright, email);
931 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
933 printf ("\n\n");
935 print_usage ();
937 printf (_(UT_HELP_VRSN));
938 printf (_(UT_EXTRA_OPTS));
940 printf (_(UT_HOST_PORT), 'p', DEFAULT_PORT);
942 /* SNMP and Authentication Protocol */
943 printf (" %s\n", "-n, --next");
944 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
945 printf (" %s\n", "-P, --protocol=[1|2c|3]");
946 printf (" %s\n", _("SNMP protocol version"));
947 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
948 printf (" %s\n", _("SNMPv3 securityLevel"));
949 printf (" %s\n", "-a, --authproto=[MD5|SHA]");
950 printf (" %s\n", _("SNMPv3 auth proto"));
951 printf (" %s\n", "-x, --privproto=[DES|AES]");
952 printf (" %s\n", _("SNMPv3 priv proto (default DES)"));
954 /* Authentication Tokens*/
955 printf (" %s\n", "-C, --community=STRING");
956 printf (" %s ", _("Optional community string for SNMP communication"));
957 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
958 printf (" %s\n", "-U, --secname=USERNAME");
959 printf (" %s\n", _("SNMPv3 username"));
960 printf (" %s\n", "-A, --authpassword=PASSWORD");
961 printf (" %s\n", _("SNMPv3 authentication password"));
962 printf (" %s\n", "-X, --privpasswd=PASSWORD");
963 printf (" %s\n", _("SNMPv3 privacy password"));
965 /* OID Stuff */
966 printf (" %s\n", "-o, --oid=OID(s)");
967 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
968 printf (" %s\n", "-m, --miblist=STRING");
969 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
970 printf (" %s\n", _("for symbolic OIDs.)"));
971 printf (" %s\n", "-d, --delimiter=STRING");
972 printf (_(" Delimiter to use when parsing returned data. Default is \"%s\""), DEFAULT_DELIMITER);
973 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
974 printf (" %s\n", _("to be the data that should be used in the evaluation."));
976 /* Tests Against Integers */
977 printf (" %s\n", "-w, --warning=INTEGER_RANGE(s)");
978 printf (" %s\n", _("Range(s) which will not result in a WARNING status"));
979 printf (" %s\n", "-c, --critical=INTEGER_RANGE(s)");
980 printf (" %s\n", _("Range(s) which will not result in a CRITICAL status"));
982 /* Tests Against Strings */
983 printf (" %s\n", "-s, --string=STRING");
984 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
985 printf (" %s\n", "-r, --ereg=REGEX");
986 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
987 printf (" %s\n", "-R, --eregi=REGEX");
988 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
989 printf (" %s\n", "-l, --label=STRING");
990 printf (" %s\n", _("Prefix label for output from plugin (default -s 'SNMP')"));
992 /* Output Formatting */
993 printf (" %s\n", "-u, --units=STRING");
994 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
995 printf (" %s\n", "-D, --output-delimiter=STRING");
996 printf (" %s\n", _("Separates output on multiple OID requests"));
998 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
999 printf (" %s\n", "-e, --retries=INTEGER");
1000 printf (" %s\n", _("Number of retries to be used in the requests"));
1002 printf (_(UT_VERBOSE));
1004 printf ("\n");
1005 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1006 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1007 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1009 printf ("\n");
1010 printf ("%s\n", _("Notes:"));
1011 printf (" %s\n", _("- Multiple OIDs may be indicated by a comma- or space-delimited list (lists with"));
1012 printf (" %s\n", _("internal spaces must be quoted) [max 8 OIDs]"));
1014 printf (" %s\n", _("- Ranges are inclusive and are indicated with colons. When specified as"));
1015 printf (" %s\n", _("'min:max' a STATE_OK will be returned if the result is within the indicated"));
1016 printf (" %s\n", _("range or is equal to the upper or lower bound. A non-OK state will be"));
1017 printf (" %s\n", _("returned if the result is outside the specified range."));
1019 printf (" %s\n", _("- If specified in the order 'max:min' a non-OK state will be returned if the"));
1020 printf (" %s\n", _("result is within the (inclusive) range."));
1022 printf (" %s\n", _("- Upper or lower bounds may be omitted to skip checking the respective limit."));
1023 printf (" %s\n", _("- Bare integers are interpreted as upper limits."));
1024 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1025 printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1026 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1027 printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
1028 #ifdef NP_EXTRA_OPTS
1029 printf (" -%s", _(UT_EXTRA_OPTS_NOTES));
1030 #endif
1032 printf (_(UT_SUPPORT));
1033 }
1037 void
1038 print_usage (void)
1039 {
1040 printf (_("Usage:"));
1041 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname);
1042 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1043 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1044 printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
1045 printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");
1046 }