Code

Merge branch 'master' of ssh://repo.or.cz/srv/git/nagiosplugins
[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 "popen.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 *oid;
110 char *label;
111 char *units;
112 char *port;
113 char string_value[MAX_INPUT_BUFFER] = "";
114 char **labels = NULL;
115 char **unitv = NULL;
116 size_t nlabels = 0;
117 size_t labels_size = 8;
118 size_t nunits = 0;
119 size_t unitv_size = 8;
120 int verbose = FALSE;
121 int usesnmpgetnext = FALSE;
122 unsigned long long lower_warn_lim[MAX_OIDS];
123 unsigned long long upper_warn_lim[MAX_OIDS];
124 unsigned long long lower_crit_lim[MAX_OIDS];
125 unsigned long long upper_crit_lim[MAX_OIDS];
126 unsigned long long response_value[MAX_OIDS];
127 int check_warning_value = FALSE;
128 int check_critical_value = FALSE;
129 int retries = 0;
130 unsigned long long eval_method[MAX_OIDS];
131 char *delimiter;
132 char *output_delim;
133 char *miblist = NULL;
134 int needmibs = FALSE;
137 int
138 main (int argc, char **argv)
140         int i = 0;
141         int iresult = STATE_UNKNOWN;
142         int found = 0;
143         int result = STATE_DEPENDENT;
144         char input_buffer[MAX_INPUT_BUFFER];
145         char *command_line = NULL;
146         char *cl_hidden_auth = NULL;
147         char *response = NULL;
148         char *outbuff;
149         char *output;
150         char *ptr = NULL;
151         char *p2 = NULL;
152         char *show = NULL;
153         char type[8] = "";
155         setlocale (LC_ALL, "");
156         bindtextdomain (PACKAGE, LOCALEDIR);
157         textdomain (PACKAGE);
159         labels = malloc (labels_size);
160         unitv = malloc (unitv_size);
161         for (i = 0; i < MAX_OIDS; i++)
162                 eval_method[i] = CHECK_UNDEF;
163         i = 0;
165         oid = strdup ("");
166         label = strdup ("SNMP");
167         units = strdup ("");
168         port = strdup (DEFAULT_PORT);
169         outbuff = strdup ("");
170         output = strdup ("");
171         delimiter = strdup (" = ");
172         output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
173         /* miblist = strdup (DEFAULT_MIBLIST); */
174         timeout_interval = DEFAULT_TIMEOUT;
175         retries = DEFAULT_RETRIES;
177         /* Parse extra opts if any */
178         argv=np_extra_opts (&argc, argv, progname);
180         if (process_arguments (argc, argv) == ERROR)
181                 usage4 (_("Could not parse arguments"));
183         /* create the command line to execute */
184                 if(usesnmpgetnext == TRUE) {
185                 asprintf(&command_line, "%s -t %d -r %d -m %s -v %s %s %s:%s %s",
186                         PATH_TO_SNMPGETNEXT, timeout_interval, retries, miblist, proto,
187                         authpriv, server_address, port, oid);
188                 asprintf(&cl_hidden_auth, "%s -t %d -r %d -m %s -v %s %s %s:%s %s",
189                         PATH_TO_SNMPGETNEXT, timeout_interval, retries, miblist, proto,
190                         "[authpriv]", server_address, port, oid);
191         }else{
193                 asprintf (&command_line, "%s -t %d -r %d -m %s -v %s %s %s:%s %s",
194                         PATH_TO_SNMPGET, timeout_interval, retries, miblist, proto,
195                         authpriv, server_address, port, oid);
196                 asprintf(&cl_hidden_auth, "%s -t %d -r %d -m %s -v %s %s %s:%s %s",
197                         PATH_TO_SNMPGET, timeout_interval, retries, miblist, proto,
198                         "[authpriv]", server_address, port, oid);
199         }
201         if (verbose)
202                 printf ("%s\n", command_line);
205         /* run the command */
206         child_process = spopen (command_line);
207         if (child_process == NULL) {
208                 printf (_("Could not open pipe: %s\n"), cl_hidden_auth);
209                 exit (STATE_UNKNOWN);
210         }
212 #if 0           /* Removed May 29, 2007 */
213         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
214         if (child_stderr == NULL) {
215                 printf (_("Could not open stderr for %s\n"), cl_hidden_auth);
216         }
217 #endif
219         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
220                 asprintf (&output, "%s%s", output, input_buffer);
222         if (verbose)
223                 printf ("%s\n", output);
225         ptr = output;
227         strncat(perfstr, "| ", sizeof(perfstr)-strlen(perfstr)-1);
228         while (ptr) {
229                 char *foo, *ptr2;
230                 unsigned int copylen;
232                 foo = strstr (ptr, delimiter);
233                 copylen = foo-ptr;
234                 if (copylen > sizeof(perfstr)-strlen(perfstr)-1)
235                         copylen = sizeof(perfstr)-strlen(perfstr)-1;
236                 ptr2 = ptr;
237                 ptr = foo;
239                 if (ptr == NULL)
240                         break;
242                 ptr += strlen (delimiter);
243                 ptr += strspn (ptr, " ");
245                 found++;
247                 if (ptr[0] == '"') {
248                         ptr++;
249                         response = strpcpy (response, ptr, "\"");
250                         ptr = strpbrk (ptr, "\"");
251                         ptr += strspn (ptr, "\"\n");
252                 }
253                 else {
254                         response = strpcpy (response, ptr, "\n");
255                         ptr = strpbrk (ptr, "\n");
256                         ptr += strspn (ptr, "\n");
257                         while
258                                 (strstr (ptr, delimiter) &&
259                                  strstr (ptr, "\n") && strstr (ptr, "\n") < strstr (ptr, delimiter)) {
260                                 response = strpcat (response, ptr, "\n");
261                                 ptr = strpbrk (ptr, "\n");
262                         }
263                         if (ptr && strstr (ptr, delimiter) == NULL) {
264                                 asprintf (&response, "%s%s", response, ptr);
265                                 ptr = NULL;
266                         }
267                 }
269                 /* We strip out the datatype indicator for PHBs */
271                 /* Clean up type array - Sol10 does not necessarily zero it out */
272                 bzero(type, sizeof(type));
274                 if (strstr (response, "Gauge: "))
275                         show = strstr (response, "Gauge: ") + 7;
276                 else if (strstr (response, "Gauge32: "))
277                         show = strstr (response, "Gauge32: ") + 9;
278                 else if (strstr (response, "Counter32: ")) {
279                         show = strstr (response, "Counter32: ") + 11;
280                         strcpy(type, "c");
281                 }
282                 else if (strstr (response, "Counter64: ")) {
283                         show = strstr (response, "Counter64: ") + 11;
284                         strcpy(type, "c");
285                 }
286                 else if (strstr (response, "INTEGER: "))
287                         show = strstr (response, "INTEGER: ") + 9;
288                 else if (strstr (response, "STRING: "))
289                         show = strstr (response, "STRING: ") + 8;
290                 else
291                         show = response;
292                 p2 = show;
294                 iresult = STATE_DEPENDENT;
296                 /* Process this block for integer comparisons */
297                 if (eval_method[i] & CRIT_GT ||
298                     eval_method[i] & CRIT_LT ||
299                     eval_method[i] & CRIT_GE ||
300                     eval_method[i] & CRIT_LE ||
301                     eval_method[i] & CRIT_EQ ||
302                     eval_method[i] & CRIT_NE ||
303                     eval_method[i] & WARN_GT ||
304                     eval_method[i] & WARN_LT ||
305                     eval_method[i] & WARN_GE ||
306                     eval_method[i] & WARN_LE ||
307                     eval_method[i] & WARN_EQ ||
308                     eval_method[i] & WARN_NE) {
309                         p2 = strpbrk (p2, "0123456789");
310                         if (p2 == NULL)
311                                 die (STATE_UNKNOWN,_("No valid data returned"));
312                         response_value[i] = strtoul (p2, NULL, 10);
313                         iresult = check_num (i);
314                         asprintf (&show, "%llu", response_value[i]);
315                 }
317                 /* Process this block for string matching */
318                 else if (eval_method[i] & CRIT_STRING) {
319                         if (strcmp (show, string_value))
320                                 iresult = STATE_CRITICAL;
321                         else
322                                 iresult = STATE_OK;
323                 }
325                 /* Process this block for regex matching */
326                 else if (eval_method[i] & CRIT_REGEX) {
327                         excode = regexec (&preg, response, 10, pmatch, eflags);
328                         if (excode == 0) {
329                                 iresult = STATE_OK;
330                         }
331                         else if (excode != REG_NOMATCH) {
332                                 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
333                                 printf (_("Execute Error: %s\n"), errbuf);
334                                 exit (STATE_CRITICAL);
335                         }
336                         else {
337                                 iresult = STATE_CRITICAL;
338                         }
339                 }
341                 /* Process this block for existence-nonexistence checks */
342                 else {
343                         if (eval_method[i] & CRIT_PRESENT)
344                                 iresult = STATE_CRITICAL;
345                         else if (eval_method[i] & WARN_PRESENT)
346                                 iresult = STATE_WARNING;
347                         else if (response && iresult == STATE_DEPENDENT)
348                                 iresult = STATE_OK;
349                 }
351                 /* Result is the worst outcome of all the OIDs tested */
352                 result = max_state (result, iresult);
354                 /* Prepend a label for this OID if there is one */
355                 if (nlabels > (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
356                         asprintf (&outbuff, "%s%s%s %s%s%s", outbuff,
357                                 (i == 0) ? " " : output_delim,
358                                 labels[i], mark (iresult), show, mark (iresult));
359                 else
360                         asprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
361                                 mark (iresult), show, mark (iresult));
363                 /* Append a unit string for this OID if there is one */
364                 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
365                         asprintf (&outbuff, "%s %s", outbuff, unitv[i]);
367                 i++;
369                 if (is_numeric(show)) {
370                         strncat(perfstr, ptr2, copylen);
371                         strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
372                         strncat(perfstr, show, sizeof(perfstr)-strlen(perfstr)-1);
374                         if (type)
375                                 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
376                         strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
377                 }
379         }       /* end while (ptr) */
381         if (found == 0)
382                 die (STATE_UNKNOWN,
383                         _("%s problem - No data received from host\nCMD: %s\n"),
384                         label,
385                         cl_hidden_auth);
387 #if 0           /* Removed May 29, 2007 */
388         /* WARNING if output found on stderr */
389         if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
390                 result = max_state (result, STATE_WARNING);
392         /* close stderr */
393         (void) fclose (child_stderr);
394 #endif
396         /* close the pipe */
397         if (spclose (child_process)) {
398                 if (result == STATE_OK)
399                         result = STATE_UNKNOWN;
400                 asprintf (&outbuff, "%s (%s)", outbuff, _("snmpget returned an error status"));
401         }
403 /*      if (nunits == 1 || i == 1) */
404 /*              printf ("%s %s -%s %s\n", label, state_text (result), outbuff, units); */
405 /*      else */
406         printf ("%s %s -%s %s \n", label, state_text (result), outbuff, perfstr);
408         return result;
413 /* process command-line arguments */
414 int
415 process_arguments (int argc, char **argv)
417         char *ptr;
418         int c = 1;
419         int j = 0, jj = 0, ii = 0;
421         int option = 0;
422         static struct option longopts[] = {
423                 STD_LONG_OPTS,
424                 {"community", required_argument, 0, 'C'},
425                 {"oid", required_argument, 0, 'o'},
426                 {"object", required_argument, 0, 'o'},
427                 {"delimiter", required_argument, 0, 'd'},
428                 {"output-delimiter", required_argument, 0, 'D'},
429                 {"string", required_argument, 0, 's'},
430                 {"timeout", required_argument, 0, 't'},
431                 {"regex", required_argument, 0, 'r'},
432                 {"ereg", required_argument, 0, 'r'},
433                 {"eregi", required_argument, 0, 'R'},
434                 {"label", required_argument, 0, 'l'},
435                 {"units", required_argument, 0, 'u'},
436                 {"port", required_argument, 0, 'p'},
437                 {"retries", required_argument, 0, 'e'},
438                 {"miblist", required_argument, 0, 'm'},
439                 {"protocol", required_argument, 0, 'P'},
440                 {"seclevel", required_argument, 0, 'L'},
441                 {"secname", required_argument, 0, 'U'},
442                 {"authproto", required_argument, 0, 'a'},
443                 {"privproto", required_argument, 0, 'x'},
444                 {"authpasswd", required_argument, 0, 'A'},
445                 {"privpasswd", required_argument, 0, 'X'},
446                 {"next", no_argument, 0, 'n'},
447                 {0, 0, 0, 0}
448         };
450         if (argc < 2)
451                 return ERROR;
453         /* reverse compatibility for very old non-POSIX usage forms */
454         for (c = 1; c < argc; c++) {
455                 if (strcmp ("-to", argv[c]) == 0)
456                         strcpy (argv[c], "-t");
457                 if (strcmp ("-wv", argv[c]) == 0)
458                         strcpy (argv[c], "-w");
459                 if (strcmp ("-cv", argv[c]) == 0)
460                         strcpy (argv[c], "-c");
461         }
463         while (1) {
464                 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:",
465                                                                          longopts, &option);
467                 if (c == -1 || c == EOF)
468                         break;
470                 switch (c) {
471                 case '?':       /* usage */
472                         usage5 ();
473                 case 'h':       /* help */
474                         print_help ();
475                         exit (STATE_OK);
476                 case 'V':       /* version */
477                         print_revision (progname, NP_VERSION);
478                         exit (STATE_OK);
479                 case 'v': /* verbose */
480                         verbose = TRUE;
481                         break;
483         /* Connection info */
484                 case 'C':                                                                       /* group or community */
485                         community = optarg;
486                         break;
487                 case 'H':                                                                       /* Host or server */
488                         server_address = optarg;
489                         break;
490                 case 'p':       /* TCP port number */
491                         port = optarg;
492                         break;
493                 case 'm':       /* List of MIBS  */
494                         miblist = optarg;
495                         break;
496                 case 'n':       /* usesnmpgetnext */
497                         usesnmpgetnext = TRUE;
498                         break;
499                 case 'P':       /* SNMP protocol version */
500                         proto = optarg;
501                         break;
502                 case 'L':       /* security level */
503                         seclevel = optarg;
504                         break;
505                 case 'U':       /* security username */
506                         secname = optarg;
507                         break;
508                 case 'a':       /* auth protocol */
509                         authproto = optarg;
510                         break;
511                 case 'x':       /* priv protocol */
512                         privproto = optarg;
513                         break;
514                 case 'A':       /* auth passwd */
515                         authpasswd = optarg;
516                         break;
517                 case 'X':       /* priv passwd */
518                         privpasswd = optarg;
519                         break;
520                 case 't':       /* timeout period */
521                         if (!is_integer (optarg))
522                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
523                         else
524                                 timeout_interval = atoi (optarg);
525                         break;
527         /* Test parameters */
528                 case 'c':                                                                       /* critical time threshold */
529                         if (strspn (optarg, "0123456789:,") < strlen (optarg))
530                                 usage2 (_("Invalid critical threshold"), optarg);
531                         for (ptr = optarg; ptr && jj < MAX_OIDS; jj++) {
532                                 if (llu_getll (&lower_crit_lim[jj], ptr) == 1)
533                                         eval_method[jj] |= CRIT_LT;
534                                 if (llu_getul (&upper_crit_lim[jj], ptr) == 1)
535                                         eval_method[jj] |= CRIT_GT;
536                                 (ptr = index (ptr, ',')) ? ptr++ : ptr;
537                         }
538                         break;
539                 case 'w':                                                                       /* warning time threshold */
540                         if (strspn (optarg, "0123456789:,") < strlen (optarg))
541                                 usage2 (_("Invalid warning threshold"), optarg);
542                         for (ptr = optarg; ptr && ii < MAX_OIDS; ii++) {
543                                 if (llu_getll (&lower_warn_lim[ii], ptr) == 1)
544                                         eval_method[ii] |= WARN_LT;
545                                 if (llu_getul (&upper_warn_lim[ii], ptr) == 1)
546                                         eval_method[ii] |= WARN_GT;
547                                 (ptr = index (ptr, ',')) ? ptr++ : ptr;
548                         }
549                         break;
550                 case 'e': /* PRELIMINARY - may change */
551                 case 'E': /* PRELIMINARY - may change */
552                         if (!is_integer (optarg))
553                                 usage2 (_("Retries interval must be a positive integer"), optarg);
554                         else
555                                 retries = atoi(optarg);
556                         break;
557                 case 'o':                                                                       /* object identifier */
558                         if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) {
559                                         /*
560                                          * we have something other than digits, periods and comas,
561                                          * so we have a mib variable, rather than just an SNMP OID,
562                                          * so we have to actually read the mib files
563                                          */
564                                         needmibs = TRUE;
565                         }
567                         for (ptr = optarg; (ptr = index (ptr, ',')); ptr++)
568                                 ptr[0] = ' '; /* relpace comma with space */
569                         for (ptr = optarg; (ptr = index (ptr, ' ')); ptr++)
570                                 j++; /* count OIDs */
571                         asprintf (&oid, "%s %s", (oid?oid:""), optarg);
572                         if (c == 'E' || c == 'e') {
573                                 jj++;
574                                 ii++;
575                         }
576                         if (c == 'E')
577                                 eval_method[j+1] |= WARN_PRESENT;
578                         else if (c == 'e')
579                                 eval_method[j+1] |= CRIT_PRESENT;
580                         break;
581                 case 's':                                                                       /* string or substring */
582                         strncpy (string_value, optarg, sizeof (string_value) - 1);
583                         string_value[sizeof (string_value) - 1] = 0;
584                         eval_method[jj++] = CRIT_STRING;
585                         ii++;
586                         break;
587                 case 'R':                                                                       /* regex */
588                         cflags = REG_ICASE;
589                 case 'r':                                                                       /* regex */
590                         cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
591                         strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
592                         regex_expect[sizeof (regex_expect) - 1] = 0;
593                         errcode = regcomp (&preg, regex_expect, cflags);
594                         if (errcode != 0) {
595                                 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
596                                 printf (_("Could Not Compile Regular Expression"));
597                                 return ERROR;
598                         }
599                         eval_method[jj++] = CRIT_REGEX;
600                         ii++;
601                         break;
603         /* Format */
604                 case 'd':                                                                       /* delimiter */
605                         delimiter = strscpy (delimiter, optarg);
606                         break;
607                 case 'D':                                                                       /* output-delimiter */
608                         output_delim = strscpy (output_delim, optarg);
609                         break;
610                 case 'l':                                                                       /* label */
611                         label = optarg;
612                         nlabels++;
613                         if (nlabels >= labels_size) {
614                                 labels_size += 8;
615                                 labels = realloc (labels, labels_size);
616                                 if (labels == NULL)
617                                         die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
618                         }
619                         labels[nlabels - 1] = optarg;
620                         ptr = thisarg (optarg);
621                         labels[nlabels - 1] = ptr;
622                         if (strstr (ptr, "'") == ptr)
623                                 labels[nlabels - 1] = ptr + 1;
624                         while (ptr && (ptr = nextarg (ptr))) {
625                                 if (nlabels >= labels_size) {
626                                         labels_size += 8;
627                                         labels = realloc (labels, labels_size);
628                                         if (labels == NULL)
629                                                 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
630                                 }
631                                 labels++;
632                                 ptr = thisarg (ptr);
633                                 if (strstr (ptr, "'") == ptr)
634                                         labels[nlabels - 1] = ptr + 1;
635                                 else
636                                         labels[nlabels - 1] = ptr;
637                         }
638                         break;
639                 case 'u':                                                                       /* units */
640                         units = optarg;
641                         nunits++;
642                         if (nunits >= unitv_size) {
643                                 unitv_size += 8;
644                                 unitv = realloc (unitv, unitv_size);
645                                 if (unitv == NULL)
646                                         die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
647                         }
648                         unitv[nunits - 1] = optarg;
649                         ptr = thisarg (optarg);
650                         unitv[nunits - 1] = ptr;
651                         if (strstr (ptr, "'") == ptr)
652                                 unitv[nunits - 1] = ptr + 1;
653                         while (ptr && (ptr = nextarg (ptr))) {
654                                 if (nunits >= unitv_size) {
655                                         unitv_size += 8;
656                                         unitv = realloc (unitv, unitv_size);
657                                         if (units == NULL)
658                                                 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
659                                 }
660                                 nunits++;
661                                 ptr = thisarg (ptr);
662                                 if (strstr (ptr, "'") == ptr)
663                                         unitv[nunits - 1] = ptr + 1;
664                                 else
665                                         unitv[nunits - 1] = ptr;
666                         }
667                         break;
669                 }
670         }
672         if (server_address == NULL)
673                 server_address = argv[optind];
675         if (community == NULL)
676                 community = strdup (DEFAULT_COMMUNITY);
680         return validate_arguments ();
684 /******************************************************************************
686 @@-
687 <sect3>
688 <title>validate_arguments</title>
690 <para>&PROTO_validate_arguments;</para>
692 <para>Checks to see if the default miblist needs to be loaded. Also verifies
693 the authentication and authorization combinations based on protocol version
694 selected.</para>
696 <para></para>
698 </sect3>
699 -@@
700 ******************************************************************************/
704 int
705 validate_arguments ()
707         /* check whether to load locally installed MIBS (CPU/disk intensive) */
708         if (miblist == NULL) {
709                 if ( needmibs  == TRUE ) {
710                         miblist = strdup (DEFAULT_MIBLIST);
711                 }else{
712                         miblist = "''";                 /* don't read any mib files for numeric oids */
713                 }
714         }
717         /* Need better checks to verify seclevel and authproto choices */
719         if (seclevel == NULL)
720                 asprintf (&seclevel, "noAuthNoPriv");
723         if (authproto == NULL )
724                 asprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
726         if (privproto == NULL )
727                 asprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
729         if (proto == NULL || (strcmp(proto,DEFAULT_PROTOCOL) == 0) ) {  /* default protocol version */
730                 asprintf(&proto, DEFAULT_PROTOCOL);
731                 asprintf(&authpriv, "%s%s", "-c ", community);
732         }
733         else if ( strcmp (proto, "2c") == 0 ) {         /* snmpv2c args */
734                 asprintf(&authpriv, "%s%s", "-c ", community);
735         }
736         else if ( strcmp (proto, "3") == 0 ) {          /* snmpv3 args */
737                 asprintf(&proto, "%s", "3");
739                 if ( (strcmp(seclevel, "noAuthNoPriv") == 0) || seclevel == NULL ) {
740                         asprintf(&authpriv, "%s", "-l noAuthNoPriv" );
741                 }
742                 else if ( strcmp(seclevel, "authNoPriv") == 0 ) {
743                         if ( secname == NULL || authpasswd == NULL) {
744                                 printf (_("Missing secname (%s) or authpassword (%s) ! \n"),secname, authpasswd );
745                                 print_usage ();
746                                 exit (STATE_UNKNOWN);
747                         }
748                         asprintf(&authpriv, "-l authNoPriv -a %s -u %s -A %s ", authproto, secname, authpasswd);
749                 }
750                 else if ( strcmp(seclevel, "authPriv") == 0 ) {
751                         if ( secname == NULL || authpasswd == NULL || privpasswd == NULL ) {
752                                 printf (_("Missing secname (%s), authpassword (%s), or privpasswd (%s)! \n"),secname, authpasswd,privpasswd );
753                                 print_usage ();
754                                 exit (STATE_UNKNOWN);
755                         }
756                         asprintf(&authpriv, "-l authPriv -a %s -u %s -A %s -x %s -X %s ", authproto, secname, authpasswd, privproto, privpasswd);
757                 }
759         }
760         else {
761                 usage2 (_("Invalid SNMP version"), proto);
762         }
764         return OK;
769 char *
770 clarify_message (char *msg)
772         int i = 0;
773         int foo;
774         char tmpmsg_c[MAX_INPUT_BUFFER];
775         char *tmpmsg = (char *) &tmpmsg_c;
776         tmpmsg = strcpy (tmpmsg, msg);
777         if (!strncmp (tmpmsg, " Hex:", 5)) {
778                 tmpmsg = strtok (tmpmsg, ":");
779                 while ((tmpmsg = strtok (NULL, " "))) {
780                         foo = strtol (tmpmsg, NULL, 16);
781                         /* Translate chars that are not the same value in the printers
782                          * character set.
783                          */
784                         switch (foo) {
785                         case 208:
786                                 {
787                                         foo = 197;
788                                         break;
789                                 }
790                         case 216:
791                                 {
792                                         foo = 196;
793                                         break;
794                                 }
795                         }
796                         msg[i] = foo;
797                         i++;
798                 }
799                 msg[i] = 0;
800         }
801         return (msg);
806 int
807 check_num (int i)
809         int result;
810         result = STATE_OK;
811         if (eval_method[i] & WARN_GT && eval_method[i] & WARN_LT &&
812                         lower_warn_lim[i] > upper_warn_lim[i]) {
813                 if (response_value[i] <= lower_warn_lim[i] &&
814                                 response_value[i] >= upper_warn_lim[i]) {
815                         result = STATE_WARNING;
816                 }
817         }
818         else if
819                 ((eval_method[i] & WARN_GT && response_value[i] > upper_warn_lim[i]) ||
820                  (eval_method[i] & WARN_GE && response_value[i] >= upper_warn_lim[i]) ||
821                  (eval_method[i] & WARN_LT && response_value[i] < lower_warn_lim[i]) ||
822                  (eval_method[i] & WARN_LE && response_value[i] <= lower_warn_lim[i]) ||
823                  (eval_method[i] & WARN_EQ && response_value[i] == upper_warn_lim[i]) ||
824                  (eval_method[i] & WARN_NE && response_value[i] != upper_warn_lim[i])) {
825                 result = STATE_WARNING;
826         }
828         if (eval_method[i] & CRIT_GT && eval_method[i] & CRIT_LT &&
829                         lower_crit_lim[i] > upper_crit_lim[i]) {
830                 if (response_value[i] <= lower_crit_lim[i] &&
831                                 response_value[i] >= upper_crit_lim[i]) {
832                         result = STATE_CRITICAL;
833                 }
834         }
835         else if
836                 ((eval_method[i] & CRIT_GT && response_value[i] > upper_crit_lim[i]) ||
837                  (eval_method[i] & CRIT_GE && response_value[i] >= upper_crit_lim[i]) ||
838                  (eval_method[i] & CRIT_LT && response_value[i] < lower_crit_lim[i]) ||
839                  (eval_method[i] & CRIT_LE && response_value[i] <= lower_crit_lim[i]) ||
840                  (eval_method[i] & CRIT_EQ && response_value[i] == upper_crit_lim[i]) ||
841                  (eval_method[i] & CRIT_NE && response_value[i] != upper_crit_lim[i])) {
842                 result = STATE_CRITICAL;
843         }
845         return result;
850 int
851 llu_getll (unsigned long long *ll, char *str)
853         char tmp[100];
854         if (strchr (str, ':') == NULL)
855                 return 0;
856         if (strchr (str, ',') != NULL && (strchr (str, ',') < strchr (str, ':')))
857                 return 0;
858         if (sscanf (str, "%llu%[:]", ll, tmp) == 2)
859                 return 1;
860         return 0;
865 int
866 llu_getul (unsigned long long *ul, char *str)
868         char tmp[100];
869         if (sscanf (str, "%llu%[^,]", ul, tmp) == 1)
870                 return 1;
871         if (sscanf (str, ":%llu%[^,]", ul, tmp) == 1)
872                 return 1;
873         if (sscanf (str, "%*u:%llu%[^,]", ul, tmp) == 1)
874                 return 1;
875         return 0;
880 /* trim leading whitespace
881          if there is a leading quote, make sure it balances */
883 char *
884 thisarg (char *str)
886         str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
887         if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */
888                 if (strlen (str) == 1 || !strstr (str + 1, "'"))
889                         die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
890         }
891         return str;
896 /* if there's a leading quote, advance to the trailing quote
897          set the trailing quote to '\x0'
898          if the string continues, advance beyond the comma */
900 char *
901 nextarg (char *str)
903         if (strstr (str, "'") == str) {
904                 str[0] = 0;
905                 if (strlen (str) > 1) {
906                         str = strstr (str + 1, "'");
907                         return (++str);
908                 }
909                 else {
910                         return NULL;
911                 }
912         }
913         if (strstr (str, ",") == str) {
914                 str[0] = 0;
915                 if (strlen (str) > 1) {
916                         return (++str);
917                 }
918                 else {
919                         return NULL;
920                 }
921         }
922         if ((str = strstr (str, ",")) && strlen (str) > 1) {
923                 str[0] = 0;
924                 return (++str);
925         }
926         return NULL;
931 void
932 print_help (void)
934         print_revision (progname, NP_VERSION);
936         printf (COPYRIGHT, copyright, email);
938         printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
940   printf ("\n\n");
942         print_usage ();
944         printf (_(UT_HELP_VRSN));
945         printf (_(UT_EXTRA_OPTS));
947         printf (_(UT_HOST_PORT), 'p', DEFAULT_PORT);
949         /* SNMP and Authentication Protocol */
950         printf (" %s\n", "-n, --next");
951   printf ("    %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
952   printf (" %s\n", "-P, --protocol=[1|2c|3]");
953   printf ("    %s\n", _("SNMP protocol version"));
954   printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
955   printf ("    %s\n", _("SNMPv3 securityLevel"));
956   printf (" %s\n", "-a, --authproto=[MD5|SHA]");
957   printf ("    %s\n", _("SNMPv3 auth proto"));
958   printf (" %s\n", "-x, --privproto=[DES|AES]");
959   printf ("    %s\n", _("SNMPv3 priv proto (default DES)"));
961         /* Authentication Tokens*/
962         printf (" %s\n", "-C, --community=STRING");
963   printf ("    %s ", _("Optional community string for SNMP communication"));
964   printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
965   printf (" %s\n", "-U, --secname=USERNAME");
966   printf ("    %s\n", _("SNMPv3 username"));
967   printf (" %s\n", "-A, --authpassword=PASSWORD");
968   printf ("    %s\n", _("SNMPv3 authentication password"));
969   printf (" %s\n", "-X, --privpasswd=PASSWORD");
970   printf ("    %s\n", _("SNMPv3 privacy password"));
972         /* OID Stuff */
973         printf (" %s\n", "-o, --oid=OID(s)");
974   printf ("    %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
975   printf (" %s\n", "-m, --miblist=STRING");
976   printf ("    %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
977   printf ("    %s\n", _("for symbolic OIDs.)"));
978   printf (" %s\n", "-d, --delimiter=STRING");
979   printf (_("    Delimiter to use when parsing returned data. Default is \"%s\""), DEFAULT_DELIMITER);
980   printf ("    %s\n", _("Any data on the right hand side of the delimiter is considered"));
981   printf ("    %s\n", _("to be the data that should be used in the evaluation."));
983         /* Tests Against Integers */
984         printf (" %s\n", "-w, --warning=INTEGER_RANGE(s)");
985   printf ("    %s\n", _("Range(s) which will not result in a WARNING status"));
986   printf (" %s\n", "-c, --critical=INTEGER_RANGE(s)");
987   printf ("    %s\n", _("Range(s) which will not result in a CRITICAL status"));
989         /* Tests Against Strings */
990         printf (" %s\n", "-s, --string=STRING");
991   printf ("    %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
992   printf (" %s\n", "-r, --ereg=REGEX");
993   printf ("    %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
994   printf (" %s\n", "-R, --eregi=REGEX");
995   printf ("    %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
996   printf (" %s\n", "-l, --label=STRING");
997   printf ("    %s\n", _("Prefix label for output from plugin (default -s 'SNMP')"));
999         /* Output Formatting */
1000         printf (" %s\n", "-u, --units=STRING");
1001   printf ("    %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1002   printf (" %s\n", "-D, --output-delimiter=STRING");
1003   printf ("    %s\n", _("Separates output on multiple OID requests"));
1005         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1006         printf (" %s\n", "-e, --retries=INTEGER");
1007         printf ("    %s\n", _("Number of retries to be used in the requests"));
1009         printf (_(UT_VERBOSE));
1011   printf ("\n");
1012   printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1013   printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1014   printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1016   printf ("\n");
1017   printf ("%s\n", _("Notes:"));
1018   printf (" %s\n", _("- Multiple OIDs may be indicated by a comma- or space-delimited list (lists with"));
1019   printf ("   %s\n", _("internal spaces must be quoted) [max 8 OIDs]"));
1021   printf (" %s\n", _("- Ranges are inclusive and are indicated with colons. When specified as"));
1022   printf ("   %s\n", _("'min:max' a STATE_OK will be returned if the result is within the indicated"));
1023   printf ("   %s\n", _("range or is equal to the upper or lower bound. A non-OK state will be"));
1024   printf ("   %s\n", _("returned if the result is outside the specified range."));
1026   printf (" %s\n", _("- If specified in the order 'max:min' a non-OK state will be returned if the"));
1027   printf ("   %s\n", _("result is within the (inclusive) range."));
1029   printf (" %s\n", _("- Upper or lower bounds may be omitted to skip checking the respective limit."));
1030   printf (" %s\n", _("- Bare integers are interpreted as upper limits."));
1031   printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1032   printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1033   printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1034   printf ("   %s\n", _("returned from the SNMP query is an unsigned integer."));
1035 #ifdef NP_EXTRA_OPTS
1036   printf (" -%s", _(UT_EXTRA_OPTS_NOTES));
1037 #endif
1039         printf (_(UT_SUPPORT));
1044 void
1045 print_usage (void)
1047   printf (_("Usage:"));
1048         printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname);
1049   printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1050   printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1051   printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
1052   printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");