Code

check_snmp fixes:
[nagiosplug.git] / plugins / check_snmp.c
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)
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         }
190         
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;
376 /* process command-line arguments */
377 int
378 process_arguments (int argc, char **argv)
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 ();
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 ()
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;
762 char *
763 clarify_message (char *msg)
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);
799 int
800 check_num (int i)
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;
843 int
844 llu_getll (unsigned long long *ll, char *str)
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;
858 int
859 llu_getul (unsigned long long *ul, char *str)
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;
873 /* trim leading whitespace
874          if there is a leading quote, make sure it balances */
876 char *
877 thisarg (char *str)
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;
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)
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;
924 void
925 print_help (void)
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));
1037 void
1038 print_usage (void)
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");