Code

ce3919d1af4f3592f08b3fa229cffe1102ce4bc5
[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 WARN_PRESENT 8
57 #define WARN_STRING 16
58 #define WARN_REGEX 32
60 #define MAX_OIDS 8
62 int process_arguments (int, char **);
63 int validate_arguments (void);
64 char *thisarg (char *str);
65 char *nextarg (char *str);
66 void print_usage (void);
67 void print_help (void);
69 #include "regex.h"
70 char regex_expect[MAX_INPUT_BUFFER] = "";
71 regex_t preg;
72 regmatch_t pmatch[10];
73 char errbuf[MAX_INPUT_BUFFER] = "";
74 char perfstr[MAX_INPUT_BUFFER] = "| ";
75 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
76 int eflags = 0;
77 int errcode, excode;
79 char *server_address = NULL;
80 char *community = NULL;
81 char **authpriv = NULL;
82 char *proto = NULL;
83 char *seclevel = NULL;
84 char *secname = NULL;
85 char *authproto = NULL;
86 char *privproto = NULL;
87 char *authpasswd = NULL;
88 char *privpasswd = NULL;
89 char **oids = NULL;
90 char *label;
91 char *units;
92 char *port;
93 char *snmpcmd;
94 char string_value[MAX_INPUT_BUFFER] = "";
95 char **labels = NULL;
96 char **unitv = NULL;
97 size_t nlabels = 0;
98 size_t labels_size = 8;
99 size_t nunits = 0;
100 size_t unitv_size = 8;
101 int numoids = 0;
102 int numauthpriv = 0;
103 int verbose = 0;
104 int usesnmpgetnext = FALSE;
105 char *warning_thresholds = NULL;
106 char *critical_thresholds = NULL;
107 thresholds *thlds[MAX_OIDS];
108 double response_value[MAX_OIDS];
109 int retries = 0;
110 int eval_method[MAX_OIDS];
111 char *delimiter;
112 char *output_delim;
113 char *miblist = NULL;
114 int needmibs = FALSE;
117 int
118 main (int argc, char **argv)
120         int i;
121         int iresult = STATE_UNKNOWN;
122         int result = STATE_UNKNOWN;
123         int return_code = 0;
124         int external_error = 0;
125         double perftmp;
126         char **command_line = NULL;
127         char *cl_hidden_auth = NULL;
128         char *oidname = NULL;
129         char *response = NULL;
130         char *outbuff;
131         char *ptr = NULL;
132         char *show = NULL;
133         char *th_warn=NULL;
134         char *th_crit=NULL;
135         char type[8] = "";
136         output chld_out, chld_err;
138         setlocale (LC_ALL, "");
139         bindtextdomain (PACKAGE, LOCALEDIR);
140         textdomain (PACKAGE);
142         labels = malloc (labels_size);
143         unitv = malloc (unitv_size);
144         for (i = 0; i < MAX_OIDS; i++)
145                 eval_method[i] = CHECK_UNDEF;
147         label = strdup ("SNMP");
148         units = strdup ("");
149         port = strdup (DEFAULT_PORT);
150         outbuff = strdup ("");
151         delimiter = strdup (" = ");
152         output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
153         timeout_interval = DEFAULT_TIMEOUT;
154         retries = DEFAULT_RETRIES;
156         /* Parse extra opts if any */
157         argv=np_extra_opts (&argc, argv, progname);
159         if (process_arguments (argc, argv) == ERROR)
160                 usage4 (_("Could not parse arguments"));
162         /* Populate the thresholds */
163         th_warn=warning_thresholds;
164         th_crit=critical_thresholds;
165         for (i=0; i<numoids; i++) {
166                 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
167                 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
168                 /* Skip empty thresholds, while avoiding segfault */
169                 set_thresholds(&thlds[i],
170                                w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL,
171                                c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
172                 if (w) {
173                         th_warn=strchr(th_warn, ',');
174                         if (th_warn) th_warn++;
175                         free(w);
176                 }
177                 if (c) {
178                         th_crit=strchr(th_crit, ',');
179                         if (th_crit) th_crit++;
180                         free(c);
181                 }
182         }
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, strlen(miblist) ? 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                 const char *conv = "%.0f";
256                 ptr = chld_out.line[i];
257                 oidname = strpcpy (oidname, ptr, delimiter);
258                 response = strstr (ptr, delimiter);
259                 if (response == NULL)
260                         break;
262                 if (verbose > 2) {
263                         printf("Processing line %i\n  oidname: %s\n  response: %s\n", i+1, oidname, response);
264                 }
266                 /* Clean up type array - Sol10 does not necessarily zero it out */
267                 bzero(type, sizeof(type));
269                 /* We strip out the datatype indicator for PHBs */
270                 if (strstr (response, "Gauge: "))
271                         show = strstr (response, "Gauge: ") + 7;
272                 else if (strstr (response, "Gauge32: "))
273                         show = strstr (response, "Gauge32: ") + 9;
274                 else if (strstr (response, "Counter32: ")) {
275                         show = strstr (response, "Counter32: ") + 11;
276                         strcpy(type, "c");
277                 }
278                 else if (strstr (response, "Counter64: ")) {
279                         show = strstr (response, "Counter64: ") + 11;
280                         strcpy(type, "c");
281                 }
282                 else if (strstr (response, "INTEGER: "))
283                         show = strstr (response, "INTEGER: ") + 9;
284                 else if (strstr (response, "STRING: ")) {
285                         show = strstr (response, "STRING: ") + 8;
286                         conv = "%.10g";
287                 }
288                 else if (strstr (response, "Timeticks: "))
289                         show = strstr (response, "Timeticks: ");
290                 else
291                         show = response;
293                 iresult = STATE_DEPENDENT;
295                 /* Process this block for integer comparisons */
296                 if (thlds[i]->warning || thlds[i]->critical) {
297                         ptr = strpbrk (show, "0123456789");
298                         if (ptr == NULL)
299                                 die (STATE_UNKNOWN,_("No valid data returned"));
300                         response_value[i] = strtod (ptr, NULL);
301                         iresult = get_status(response_value[i], thlds[i]);
302                         asprintf (&show, conv, 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                 /* Try a two-way conversion of show and add perfdata only if we get
356                  * something back at the end */
357                 ptr = NULL;
358                 perftmp = strtod(show, &ptr);
359                 if (ptr != show) {
360                         ptr = NULL;
361                         asprintf(&ptr, "%0.9g", perftmp);
362                         strncat(perfstr, oidname, sizeof(perfstr)-strlen(perfstr)-1);
363                         strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
364                         strncat(perfstr, ptr, sizeof(perfstr)-strlen(perfstr)-1);
365                         free(ptr);
367                         if (type)
368                                 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
369                         strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
370                 }
371         }
373         printf ("%s %s -%s %s \n", label, state_text (result), outbuff, perfstr);
375         return result;
380 /* process command-line arguments */
381 int
382 process_arguments (int argc, char **argv)
384         char *ptr;
385         int c = 1;
386         int j = 0, jj = 0, ii = 0;
388         int option = 0;
389         static struct option longopts[] = {
390                 STD_LONG_OPTS,
391                 {"community", required_argument, 0, 'C'},
392                 {"oid", required_argument, 0, 'o'},
393                 {"object", required_argument, 0, 'o'},
394                 {"delimiter", required_argument, 0, 'd'},
395                 {"output-delimiter", required_argument, 0, 'D'},
396                 {"string", required_argument, 0, 's'},
397                 {"timeout", required_argument, 0, 't'},
398                 {"regex", required_argument, 0, 'r'},
399                 {"ereg", required_argument, 0, 'r'},
400                 {"eregi", required_argument, 0, 'R'},
401                 {"label", required_argument, 0, 'l'},
402                 {"units", required_argument, 0, 'u'},
403                 {"port", required_argument, 0, 'p'},
404                 {"retries", required_argument, 0, 'e'},
405                 {"miblist", required_argument, 0, 'm'},
406                 {"protocol", required_argument, 0, 'P'},
407                 {"seclevel", required_argument, 0, 'L'},
408                 {"secname", required_argument, 0, 'U'},
409                 {"authproto", required_argument, 0, 'a'},
410                 {"privproto", required_argument, 0, 'x'},
411                 {"authpasswd", required_argument, 0, 'A'},
412                 {"privpasswd", required_argument, 0, 'X'},
413                 {"next", no_argument, 0, 'n'},
414                 {0, 0, 0, 0}
415         };
417         if (argc < 2)
418                 return ERROR;
420         /* reverse compatibility for very old non-POSIX usage forms */
421         for (c = 1; c < argc; c++) {
422                 if (strcmp ("-to", argv[c]) == 0)
423                         strcpy (argv[c], "-t");
424                 if (strcmp ("-wv", argv[c]) == 0)
425                         strcpy (argv[c], "-w");
426                 if (strcmp ("-cv", argv[c]) == 0)
427                         strcpy (argv[c], "-c");
428         }
430         while (1) {
431                 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:",
432                                                                          longopts, &option);
434                 if (c == -1 || c == EOF)
435                         break;
437                 switch (c) {
438                 case '?':       /* usage */
439                         usage5 ();
440                 case 'h':       /* help */
441                         print_help ();
442                         exit (STATE_OK);
443                 case 'V':       /* version */
444                         print_revision (progname, NP_VERSION);
445                         exit (STATE_OK);
446                 case 'v': /* verbose */
447                         verbose++;
448                         break;
450         /* Connection info */
451                 case 'C':                                                                       /* group or community */
452                         community = optarg;
453                         break;
454                 case 'H':                                                                       /* Host or server */
455                         server_address = optarg;
456                         break;
457                 case 'p':       /* TCP port number */
458                         port = optarg;
459                         break;
460                 case 'm':       /* List of MIBS */
461                         miblist = optarg;
462                         break;
463                 case 'n':       /* usesnmpgetnext */
464                         usesnmpgetnext = TRUE;
465                         break;
466                 case 'P':       /* SNMP protocol version */
467                         proto = optarg;
468                         break;
469                 case 'L':       /* security level */
470                         seclevel = optarg;
471                         break;
472                 case 'U':       /* security username */
473                         secname = optarg;
474                         break;
475                 case 'a':       /* auth protocol */
476                         authproto = optarg;
477                         break;
478                 case 'x':       /* priv protocol */
479                         privproto = optarg;
480                         break;
481                 case 'A':       /* auth passwd */
482                         authpasswd = optarg;
483                         break;
484                 case 'X':       /* priv passwd */
485                         privpasswd = optarg;
486                         break;
487                 case 't':       /* timeout period */
488                         if (!is_integer (optarg))
489                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
490                         else
491                                 timeout_interval = atoi (optarg);
492                         break;
494         /* Test parameters */
495                 case 'c':                                                                       /* critical threshold */
496                         critical_thresholds = optarg;
497                         break;
498                 case 'w':                                                                       /* warning threshold */
499                         warning_thresholds = optarg;
500                         break;
501                 case 'e': /* PRELIMINARY - may change */
502                 case 'E': /* PRELIMINARY - may change */
503                         if (!is_integer (optarg))
504                                 usage2 (_("Retries interval must be a positive integer"), optarg);
505                         else
506                                 retries = atoi(optarg);
507                         break;
508                 case 'o':                                                                       /* object identifier */
509                         if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) {
510                                         /*
511                                          * we have something other than digits, periods and comas,
512                                          * so we have a mib variable, rather than just an SNMP OID,
513                                          * so we have to actually read the mib files
514                                          */
515                                         needmibs = TRUE;
516                         }
517                         if (!oids) oids = calloc(MAX_OIDS, sizeof (char *));
518                         for (ptr = strtok(optarg, ", "); ptr != NULL && j < MAX_OIDS; ptr = strtok(NULL, ", "), j++) {
519                                 oids[j] = strdup(ptr);
520                         }
521                         numoids = j;
522                         if (c == 'E' || c == 'e') {
523                                 jj++;
524                                 ii++;
525                         }
526                         if (c == 'E')
527                                 eval_method[j+1] |= WARN_PRESENT;
528                         else if (c == 'e')
529                                 eval_method[j+1] |= CRIT_PRESENT;
530                         break;
531                 case 's':                                                                       /* string or substring */
532                         strncpy (string_value, optarg, sizeof (string_value) - 1);
533                         string_value[sizeof (string_value) - 1] = 0;
534                         eval_method[jj++] = CRIT_STRING;
535                         ii++;
536                         break;
537                 case 'R':                                                                       /* regex */
538                         cflags = REG_ICASE;
539                 case 'r':                                                                       /* regex */
540                         cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
541                         strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
542                         regex_expect[sizeof (regex_expect) - 1] = 0;
543                         errcode = regcomp (&preg, regex_expect, cflags);
544                         if (errcode != 0) {
545                                 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
546                                 printf (_("Could Not Compile Regular Expression"));
547                                 return ERROR;
548                         }
549                         eval_method[jj++] = CRIT_REGEX;
550                         ii++;
551                         break;
553         /* Format */
554                 case 'd':                                                                       /* delimiter */
555                         delimiter = strscpy (delimiter, optarg);
556                         break;
557                 case 'D':                                                                       /* output-delimiter */
558                         output_delim = strscpy (output_delim, optarg);
559                         break;
560                 case 'l':                                                                       /* label */
561                         label = optarg;
562                         nlabels++;
563                         if (nlabels >= labels_size) {
564                                 labels_size += 8;
565                                 labels = realloc (labels, labels_size);
566                                 if (labels == NULL)
567                                         die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
568                         }
569                         labels[nlabels - 1] = optarg;
570                         ptr = thisarg (optarg);
571                         labels[nlabels - 1] = ptr;
572                         if (strstr (ptr, "'") == ptr)
573                                 labels[nlabels - 1] = ptr + 1;
574                         while (ptr && (ptr = nextarg (ptr))) {
575                                 if (nlabels >= labels_size) {
576                                         labels_size += 8;
577                                         labels = realloc (labels, labels_size);
578                                         if (labels == NULL)
579                                                 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
580                                 }
581                                 labels++;
582                                 ptr = thisarg (ptr);
583                                 if (strstr (ptr, "'") == ptr)
584                                         labels[nlabels - 1] = ptr + 1;
585                                 else
586                                         labels[nlabels - 1] = ptr;
587                         }
588                         break;
589                 case 'u':                                                                       /* units */
590                         units = optarg;
591                         nunits++;
592                         if (nunits >= unitv_size) {
593                                 unitv_size += 8;
594                                 unitv = realloc (unitv, unitv_size);
595                                 if (unitv == NULL)
596                                         die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
597                         }
598                         unitv[nunits - 1] = optarg;
599                         ptr = thisarg (optarg);
600                         unitv[nunits - 1] = ptr;
601                         if (strstr (ptr, "'") == ptr)
602                                 unitv[nunits - 1] = ptr + 1;
603                         while (ptr && (ptr = nextarg (ptr))) {
604                                 if (nunits >= unitv_size) {
605                                         unitv_size += 8;
606                                         unitv = realloc (unitv, unitv_size);
607                                         if (units == NULL)
608                                                 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
609                                 }
610                                 nunits++;
611                                 ptr = thisarg (ptr);
612                                 if (strstr (ptr, "'") == ptr)
613                                         unitv[nunits - 1] = ptr + 1;
614                                 else
615                                         unitv[nunits - 1] = ptr;
616                         }
617                         break;
619                 }
620         }
622         if (server_address == NULL)
623                 server_address = argv[optind];
625         if (community == NULL)
626                 community = strdup (DEFAULT_COMMUNITY);
628         return validate_arguments ();
632 /******************************************************************************
634 @@-
635 <sect3>
636 <title>validate_arguments</title>
638 <para>&PROTO_validate_arguments;</para>
640 <para>Checks to see if the default miblist needs to be loaded. Also verifies
641 the authentication and authorization combinations based on protocol version
642 selected.</para>
644 <para></para>
646 </sect3>
647 -@@
648 ******************************************************************************/
652 int
653 validate_arguments ()
655         /* check whether to load locally installed MIBS (CPU/disk intensive) */
656         if (miblist == NULL) {
657                 if ( needmibs == TRUE ) {
658                         miblist = strdup (DEFAULT_MIBLIST);
659                 }else{
660                         miblist = "";                   /* don't read any mib files for numeric oids */
661                 }
662         }
664         /* Check server_address is given */
665         if (server_address == NULL)
666                 die(STATE_UNKNOWN, _("No host specified\n"));
668         /* Check oid is given */
669         if (numoids == 0)
670                 die(STATE_UNKNOWN, _("No OIDs specified\n"));
672         if (proto == NULL)
673                 asprintf(&proto, DEFAULT_PROTOCOL);
675         if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) {     /* snmpv1 or snmpv2c */
676                 numauthpriv = 2;
677                 authpriv = calloc (numauthpriv, sizeof (char *));
678                 authpriv[0] = strdup ("-c");
679                 authpriv[1] = strdup (community);
680         }
681         else if ( strcmp (proto, "3") == 0 ) {          /* snmpv3 args */
682                 if (seclevel == NULL)
683                         asprintf(&seclevel, "noAuthNoPriv");
685                 if (strcmp(seclevel, "noAuthNoPriv") == 0) {
686                         numauthpriv = 2;
687                         authpriv = calloc (numauthpriv, sizeof (char *));
688                         authpriv[0] = strdup ("-l");
689                         authpriv[1] = strdup ("noAuthNoPriv");
690                 } else {
691                         if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
692                                 usage2 (_("Invalid seclevel"), seclevel);
693                         }
695                         if (authproto == NULL )
696                                 asprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
698                         if (secname == NULL)
699                                 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
701                         if (authpasswd == NULL)
702                                 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
704                         if ( strcmp(seclevel, "authNoPriv") == 0 ) {
705                                 numauthpriv = 8;
706                                 authpriv = calloc (numauthpriv, sizeof (char *));
707                                 authpriv[0] = strdup ("-l");
708                                 authpriv[1] = strdup ("authNoPriv");
709                                 authpriv[2] = strdup ("-a");
710                                 authpriv[3] = strdup (authproto);
711                                 authpriv[4] = strdup ("-u");
712                                 authpriv[5] = strdup (secname);
713                                 authpriv[6] = strdup ("-A");
714                                 authpriv[7] = strdup (authpasswd);
715                         } else if ( strcmp(seclevel, "authPriv") == 0 ) {
716                                 if (privproto == NULL )
717                                         asprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
719                                 if (privpasswd == NULL)
720                                         die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
722                                 numauthpriv = 12;
723                                 authpriv = calloc (numauthpriv, sizeof (char *));
724                                 authpriv[0] = strdup ("-l");
725                                 authpriv[1] = strdup ("authPriv");
726                                 authpriv[2] = strdup ("-a");
727                                 authpriv[3] = strdup (authproto);
728                                 authpriv[4] = strdup ("-u");
729                                 authpriv[5] = strdup (secname);
730                                 authpriv[6] = strdup ("-A");
731                                 authpriv[7] = strdup (authpasswd);
732                                 authpriv[8] = strdup ("-x");
733                                 authpriv[9] = strdup (privproto);
734                                 authpriv[10] = strdup ("-X");
735                                 authpriv[11] = strdup (privpasswd);
736                         }
737                 }
739         }
740         else {
741                 usage2 (_("Invalid SNMP version"), proto);
742         }
744         return OK;
749 /* trim leading whitespace
750          if there is a leading quote, make sure it balances */
752 char *
753 thisarg (char *str)
755         str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
756         if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */
757                 if (strlen (str) == 1 || !strstr (str + 1, "'"))
758                         die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
759         }
760         return str;
765 /* if there's a leading quote, advance to the trailing quote
766          set the trailing quote to '\x0'
767          if the string continues, advance beyond the comma */
769 char *
770 nextarg (char *str)
772         if (strstr (str, "'") == str) {
773                 str[0] = 0;
774                 if (strlen (str) > 1) {
775                         str = strstr (str + 1, "'");
776                         return (++str);
777                 }
778                 else {
779                         return NULL;
780                 }
781         }
782         if (strstr (str, ",") == str) {
783                 str[0] = 0;
784                 if (strlen (str) > 1) {
785                         return (++str);
786                 }
787                 else {
788                         return NULL;
789                 }
790         }
791         if ((str = strstr (str, ",")) && strlen (str) > 1) {
792                 str[0] = 0;
793                 return (++str);
794         }
795         return NULL;
800 void
801 print_help (void)
803         print_revision (progname, NP_VERSION);
805         printf (COPYRIGHT, copyright, email);
807         printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
809         printf ("\n\n");
811         print_usage ();
813         printf (_(UT_HELP_VRSN));
814         printf (_(UT_EXTRA_OPTS));
816         printf (_(UT_HOST_PORT), 'p', DEFAULT_PORT);
818         /* SNMP and Authentication Protocol */
819         printf (" %s\n", "-n, --next");
820         printf ("    %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
821         printf (" %s\n", "-P, --protocol=[1|2c|3]");
822         printf ("    %s\n", _("SNMP protocol version"));
823         printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
824         printf ("    %s\n", _("SNMPv3 securityLevel"));
825         printf (" %s\n", "-a, --authproto=[MD5|SHA]");
826         printf ("    %s\n", _("SNMPv3 auth proto"));
827         printf (" %s\n", "-x, --privproto=[DES|AES]");
828         printf ("    %s\n", _("SNMPv3 priv proto (default DES)"));
830         /* Authentication Tokens*/
831         printf (" %s\n", "-C, --community=STRING");
832         printf ("    %s ", _("Optional community string for SNMP communication"));
833         printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
834         printf (" %s\n", "-U, --secname=USERNAME");
835         printf ("    %s\n", _("SNMPv3 username"));
836         printf (" %s\n", "-A, --authpassword=PASSWORD");
837         printf ("    %s\n", _("SNMPv3 authentication password"));
838         printf (" %s\n", "-X, --privpasswd=PASSWORD");
839         printf ("    %s\n", _("SNMPv3 privacy password"));
841         /* OID Stuff */
842         printf (" %s\n", "-o, --oid=OID(s)");
843         printf ("    %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
844         printf (" %s\n", "-m, --miblist=STRING");
845         printf ("    %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
846         printf ("    %s\n", _("for symbolic OIDs.)"));
847         printf (" %s\n", "-d, --delimiter=STRING");
848         printf ("    %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
849         printf ("    %s\n", _("Any data on the right hand side of the delimiter is considered"));
850         printf ("    %s\n", _("to be the data that should be used in the evaluation."));
852         /* Tests Against Integers */
853         printf (" %s\n", "-w, --warning=THRESHOLD(s)");
854         printf ("    %s\n", _("Warning threshold range(s)"));
855         printf (" %s\n", "-c, --critical=THRESHOLD(s)");
856         printf ("    %s\n", _("Critical threshold range(s)"));
858         /* Tests Against Strings */
859         printf (" %s\n", "-s, --string=STRING");
860         printf ("    %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
861         printf (" %s\n", "-r, --ereg=REGEX");
862         printf ("    %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
863         printf (" %s\n", "-R, --eregi=REGEX");
864         printf ("    %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
865         printf (" %s\n", "-l, --label=STRING");
866         printf ("    %s\n", _("Prefix label for output from plugin (default -s 'SNMP')"));
868         /* Output Formatting */
869         printf (" %s\n", "-u, --units=STRING");
870         printf ("    %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
871         printf (" %s\n", "-D, --output-delimiter=STRING");
872         printf ("    %s\n", _("Separates output on multiple OID requests"));
874         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
875         printf (" %s\n", "-e, --retries=INTEGER");
876         printf ("    %s\n", _("Number of retries to be used in the requests"));
878         printf (_(UT_VERBOSE));
880         printf ("\n");
881         printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
882         printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
883         printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
885         printf ("\n");
886         printf ("%s\n", _("Notes:"));
887         printf (" %s\n", _("- Multiple OIDs may be indicated by a comma- or space-delimited list (lists with"));
888         printf ("   %s\n", _("internal spaces must be quoted) [max 8 OIDs]"));
890         printf(" -%s", _(UT_THRESHOLDS_NOTES));
892         printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
893         printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
894         printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
895         printf ("   %s\n", _("returned from the SNMP query is an unsigned integer."));
896 #ifdef NP_EXTRA_OPTS
897         printf (" -%s", _(UT_EXTRA_OPTS_NOTES));
898 #endif
900         printf (_(UT_SUPPORT));
905 void
906 print_usage (void)
908         printf (_("Usage:"));
909         printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname);
910         printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
911         printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
912         printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
913         printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");