Back to index

nagios-plugins  1.4.16
check_snmp.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 * 
00003 * Nagios check_snmp plugin
00004 * 
00005 * License: GPL
00006 * Copyright (c) 1999-2007 Nagios Plugins Development Team
00007 * 
00008 * Description:
00009 * 
00010 * This file contains the check_snmp plugin
00011 * 
00012 * Check status of remote machines and obtain system information via SNMP
00013 * 
00014 * 
00015 * This program is free software: you can redistribute it and/or modify
00016 * it under the terms of the GNU General Public License as published by
00017 * the Free Software Foundation, either version 3 of the License, or
00018 * (at your option) any later version.
00019 * 
00020 * This program is distributed in the hope that it will be useful,
00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 * GNU General Public License for more details.
00024 * 
00025 * You should have received a copy of the GNU General Public License
00026 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00027 * 
00028 * 
00029 *****************************************************************************/
00030 
00031 const char *progname = "check_snmp";
00032 const char *copyright = "1999-2007";
00033 const char *email = "nagiosplug-devel@lists.sourceforge.net";
00034 
00035 #include "common.h"
00036 #include "utils.h"
00037 #include "utils_cmd.h"
00038 
00039 #define DEFAULT_COMMUNITY "public"
00040 #define DEFAULT_PORT "161"
00041 #define DEFAULT_MIBLIST "ALL"
00042 #define DEFAULT_PROTOCOL "1"
00043 #define DEFAULT_TIMEOUT 1
00044 #define DEFAULT_RETRIES 5
00045 #define DEFAULT_AUTH_PROTOCOL "MD5"
00046 #define DEFAULT_PRIV_PROTOCOL "DES"
00047 #define DEFAULT_DELIMITER "="
00048 #define DEFAULT_OUTPUT_DELIMITER " "
00049 
00050 #define mark(a) ((a)!=0?"*":"")
00051 
00052 #define CHECK_UNDEF 0
00053 #define CRIT_PRESENT 1
00054 #define CRIT_STRING 2
00055 #define CRIT_REGEX 4
00056 #define WARN_PRESENT 8
00057 #define WARN_STRING 16
00058 #define WARN_REGEX 32
00059 
00060 #define MAX_OIDS 8
00061 
00062 /* Longopts only arguments */
00063 #define L_CALCULATE_RATE CHAR_MAX+1
00064 #define L_RATE_MULTIPLIER CHAR_MAX+2
00065 #define L_INVERT_SEARCH CHAR_MAX+3
00066 
00067 /* Gobble to string - stop incrementing c when c[0] match one of the
00068  * characters in s */
00069 #define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; }
00070 /* Given c, keep track of backslashes (bk) and double-quotes (dq)
00071  * from c[0] */
00072 #define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
00073        case '\\': \
00074               if (bk) bk--; \
00075               else bk++; \
00076               break; \
00077        case '"': \
00078               if (!dq) { dq++; } \
00079               else if(!bk) { dq--; } \
00080               else { bk--; } \
00081               break; \
00082        }
00083 
00084 
00085 
00086 int process_arguments (int, char **);
00087 int validate_arguments (void);
00088 char *thisarg (char *str);
00089 char *nextarg (char *str);
00090 void print_usage (void);
00091 void print_help (void);
00092 
00093 #include "regex.h"
00094 char regex_expect[MAX_INPUT_BUFFER] = "";
00095 regex_t preg;
00096 regmatch_t pmatch[10];
00097 char errbuf[MAX_INPUT_BUFFER] = "";
00098 char perfstr[MAX_INPUT_BUFFER] = "| ";
00099 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
00100 int eflags = 0;
00101 int errcode, excode;
00102 
00103 char *server_address = NULL;
00104 char *community = NULL;
00105 char **authpriv = NULL;
00106 char *proto = NULL;
00107 char *seclevel = NULL;
00108 char *secname = NULL;
00109 char *authproto = NULL;
00110 char *privproto = NULL;
00111 char *authpasswd = NULL;
00112 char *privpasswd = NULL;
00113 char **oids = NULL;
00114 char *label;
00115 char *units;
00116 char *port;
00117 char *snmpcmd;
00118 char string_value[MAX_INPUT_BUFFER] = "";
00119 int  invert_search=0;
00120 char **labels = NULL;
00121 char **unitv = NULL;
00122 size_t nlabels = 0;
00123 size_t labels_size = 8;
00124 size_t nunits = 0;
00125 size_t unitv_size = 8;
00126 int numoids = 0;
00127 int numauthpriv = 0;
00128 int verbose = 0;
00129 int usesnmpgetnext = FALSE;
00130 char *warning_thresholds = NULL;
00131 char *critical_thresholds = NULL;
00132 thresholds *thlds[MAX_OIDS];
00133 double response_value[MAX_OIDS];
00134 int retries = 0;
00135 int eval_method[MAX_OIDS];
00136 char *delimiter;
00137 char *output_delim;
00138 char *miblist = NULL;
00139 int needmibs = FALSE;
00140 int calculate_rate = 0;
00141 int rate_multiplier = 1;
00142 state_data *previous_state;
00143 double previous_value[MAX_OIDS];
00144 int perf_labels = 1;
00145 
00146 
00147 int
00148 main (int argc, char **argv)
00149 {
00150        int i, len, line, total_oids;
00151        unsigned int bk_count = 0, dq_count = 0;
00152        int iresult = STATE_UNKNOWN;
00153        int result = STATE_UNKNOWN;
00154        int return_code = 0;
00155        int external_error = 0;
00156        char **command_line = NULL;
00157        char *cl_hidden_auth = NULL;
00158        char *oidname = NULL;
00159        char *response = NULL;
00160        char *mult_resp = NULL;
00161        char *outbuff;
00162        char *ptr = NULL;
00163        char *show = NULL;
00164        char *th_warn=NULL;
00165        char *th_crit=NULL;
00166        char type[8] = "";
00167        output chld_out, chld_err;
00168        char *previous_string=NULL;
00169        char *ap=NULL;
00170        char *state_string=NULL;
00171        size_t response_length, current_length, string_length;
00172        char *temp_string=NULL;
00173        char *quote_string=NULL;
00174        time_t current_time;
00175        double temp_double;
00176        time_t duration;
00177        char *conv = "12345678";
00178        int is_counter=0;
00179 
00180        setlocale (LC_ALL, "");
00181        bindtextdomain (PACKAGE, LOCALEDIR);
00182        textdomain (PACKAGE);
00183 
00184        labels = malloc (labels_size);
00185        unitv = malloc (unitv_size);
00186        for (i = 0; i < MAX_OIDS; i++)
00187               eval_method[i] = CHECK_UNDEF;
00188 
00189        label = strdup ("SNMP");
00190        units = strdup ("");
00191        port = strdup (DEFAULT_PORT);
00192        outbuff = strdup ("");
00193        delimiter = strdup (" = ");
00194        output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
00195        timeout_interval = DEFAULT_TIMEOUT;
00196        retries = DEFAULT_RETRIES;
00197 
00198        np_init( (char *) progname, argc, argv );
00199 
00200        /* Parse extra opts if any */
00201        argv=np_extra_opts (&argc, argv, progname);
00202 
00203        np_set_args(argc, argv);
00204 
00205        if (process_arguments (argc, argv) == ERROR)
00206               usage4 (_("Could not parse arguments"));
00207 
00208        if(calculate_rate) {
00209               if (!strcmp(label, "SNMP"))
00210                      label = strdup("SNMP RATE");
00211               time(&current_time);
00212               i=0;
00213               previous_state = np_state_read();
00214               if(previous_state!=NULL) {
00215                      /* Split colon separated values */
00216                      previous_string = strdup((char *) previous_state->data);
00217                      while((ap = strsep(&previous_string, ":")) != NULL) {
00218                             if(verbose>2)
00219                                    printf("State for %d=%s\n", i, ap);
00220                             previous_value[i++]=strtod(ap,NULL);
00221                      }
00222               }
00223        }
00224 
00225        /* Populate the thresholds */
00226        th_warn=warning_thresholds;
00227        th_crit=critical_thresholds;
00228        for (i=0; i<numoids; i++) {
00229               char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
00230               char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
00231               /* Skip empty thresholds, while avoiding segfault */
00232               set_thresholds(&thlds[i],
00233                              w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL,
00234                              c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
00235               if (w) {
00236                      th_warn=strchr(th_warn, ',');
00237                      if (th_warn) th_warn++;
00238                      free(w);
00239               }
00240               if (c) {
00241                      th_crit=strchr(th_crit, ',');
00242                      if (th_crit) th_crit++;
00243                      free(c);
00244               }
00245        }
00246 
00247        /* Create the command array to execute */
00248        if(usesnmpgetnext == TRUE) {
00249               snmpcmd = strdup (PATH_TO_SNMPGETNEXT);
00250        }else{
00251               snmpcmd = strdup (PATH_TO_SNMPGET);
00252        }
00253 
00254        /* 9 arguments to pass before authpriv options + 1 for host and numoids. Add one for terminating NULL */
00255        command_line = calloc (9 + numauthpriv + 1 + numoids + 1, sizeof (char *));
00256        command_line[0] = snmpcmd;
00257        command_line[1] = strdup ("-t");
00258        asprintf (&command_line[2], "%d", timeout_interval);
00259        command_line[3] = strdup ("-r");
00260        asprintf (&command_line[4], "%d", retries);
00261        command_line[5] = strdup ("-m");
00262        command_line[6] = strdup (miblist);
00263        command_line[7] = "-v";
00264        command_line[8] = strdup (proto);
00265 
00266        for (i = 0; i < numauthpriv; i++) {
00267               command_line[9 + i] = authpriv[i];
00268        }
00269 
00270        asprintf (&command_line[9 + numauthpriv], "%s:%s", server_address, port);
00271 
00272        /* This is just for display purposes, so it can remain a string */
00273        asprintf(&cl_hidden_auth, "%s -t %d -r %d -m %s -v %s %s %s:%s",
00274               snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto, "[authpriv]",
00275               server_address, port);
00276 
00277        for (i = 0; i < numoids; i++) {
00278               command_line[9 + numauthpriv + 1 + i] = oids[i];
00279               asprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);   
00280        }
00281 
00282        command_line[9 + numauthpriv + 1 + numoids] = NULL;
00283 
00284        if (verbose)
00285               printf ("%s\n", cl_hidden_auth);
00286 
00287        /* Run the command */
00288        return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0);
00289 
00290        /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
00291           only return state unknown if return code is non zero or there is no stdout.
00292           Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
00293        */
00294        if (return_code != 0)
00295               external_error=1;
00296        if (chld_out.lines == 0)
00297               external_error=1;
00298        if (external_error) {
00299               if (chld_err.lines > 0) {
00300                      printf (_("External command error: %s\n"), chld_err.line[0]);
00301                      for (i = 1; i < chld_err.lines; i++) {
00302                             printf ("%s\n", chld_err.line[i]);
00303                      }
00304               } else {
00305                      printf(_("External command error with no output (return code: %d)\n"), return_code);
00306               }
00307               exit (STATE_UNKNOWN);
00308        }
00309 
00310        if (verbose) {
00311               for (i = 0; i < chld_out.lines; i++) {
00312                      printf ("%s\n", chld_out.line[i]);
00313               }
00314        }
00315 
00316        for (line=0, i=0; line < chld_out.lines; line++, i++) {
00317               if(calculate_rate)
00318                      conv = "%.10g";
00319               else
00320                      conv = "%.0f";
00321 
00322               ptr = chld_out.line[line];
00323               oidname = strpcpy (oidname, ptr, delimiter);
00324               response = strstr (ptr, delimiter);
00325               if (response == NULL)
00326                      break;
00327 
00328               if (verbose > 2) {
00329                      printf("Processing oid %i (line %i)\n  oidname: %s\n  response: %s\n", i+1, line+1, oidname, response);
00330               }
00331 
00332               /* Clean up type array - Sol10 does not necessarily zero it out */
00333               bzero(type, sizeof(type));
00334 
00335               is_counter=0;
00336               /* We strip out the datatype indicator for PHBs */
00337               if (strstr (response, "Gauge: ")) {
00338                      show = strstr (response, "Gauge: ") + 7;
00339               } 
00340               else if (strstr (response, "Gauge32: ")) {
00341                      show = strstr (response, "Gauge32: ") + 9;
00342               } 
00343               else if (strstr (response, "Counter32: ")) {
00344                      show = strstr (response, "Counter32: ") + 11;
00345                      is_counter=1;
00346                      if(!calculate_rate) 
00347                             strcpy(type, "c");
00348               }
00349               else if (strstr (response, "Counter64: ")) {
00350                      show = strstr (response, "Counter64: ") + 11;
00351                      is_counter=1;
00352                      if(!calculate_rate)
00353                             strcpy(type, "c");
00354               }
00355               else if (strstr (response, "INTEGER: ")) {
00356                      show = strstr (response, "INTEGER: ") + 9;
00357               }
00358               else if (strstr (response, "STRING: ")) {
00359                      show = strstr (response, "STRING: ") + 8;
00360                      conv = "%.10g";
00361 
00362                      /* Get the rest of the string on multi-line strings */
00363                      ptr = show;
00364                      COUNT_SEQ(ptr, bk_count, dq_count)
00365                      while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
00366                             ptr++;
00367                             GOBBLE_TOS(ptr, "\n\"\\")
00368                             COUNT_SEQ(ptr, bk_count, dq_count)
00369                      }
00370 
00371                      if (dq_count) { /* unfinished line */
00372                             /* copy show verbatim first */
00373                             if (!mult_resp) mult_resp = strdup("");
00374                             asprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
00375                             /* then strip out unmatched double-quote from single-line output */
00376                             if (show[0] == '"') show++;
00377 
00378                             /* Keep reading until we match end of double-quoted string */
00379                             for (line++; line < chld_out.lines; line++) {
00380                                    ptr = chld_out.line[line];
00381                                    asprintf (&mult_resp, "%s%s\n", mult_resp, ptr);
00382 
00383                                    COUNT_SEQ(ptr, bk_count, dq_count)
00384                                    while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
00385                                           ptr++;
00386                                           GOBBLE_TOS(ptr, "\n\"\\")
00387                                           COUNT_SEQ(ptr, bk_count, dq_count)
00388                                    }
00389                                    /* Break for loop before next line increment when done */
00390                                    if (!dq_count) break;
00391                             }
00392                      }
00393 
00394               }
00395               else if (strstr (response, "Timeticks: ")) {
00396                      show = strstr (response, "Timeticks: ");
00397               }
00398               else
00399                      show = response;
00400 
00401               iresult = STATE_DEPENDENT;
00402 
00403               /* Process this block for numeric comparisons */
00404               /* Make some special values,like Timeticks numeric only if a threshold is defined */
00405               if (thlds[i]->warning || thlds[i]->critical || calculate_rate) {
00406                      ptr = strpbrk (show, "0123456789");
00407                      if (ptr == NULL)
00408                             die (STATE_UNKNOWN,_("No valid data returned"));
00409                      response_value[i] = strtod (ptr, NULL);
00410 
00411                      if(calculate_rate) {
00412                             if (previous_state!=NULL) {
00413                                    duration = current_time-previous_state->time;
00414                                    if(duration<=0)
00415                                           die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid"));
00416                                    temp_double = response_value[i]-previous_value[i];
00417                                    /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
00418                                    if(is_counter) {
00419                                           if(temp_double<(double)0.0)
00420                                                  temp_double+=(double)4294967296.0; /* 2^32 */
00421                                           if(temp_double<(double)0.0)
00422                                                  temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */;
00423                                    }
00424                                    /* Convert to per second, then use multiplier */
00425                                    temp_double = temp_double/duration*rate_multiplier;
00426                                    iresult = get_status(temp_double, thlds[i]);
00427                                    asprintf (&show, conv, temp_double);
00428                             }
00429                      } else {
00430                             iresult = get_status(response_value[i], thlds[i]);
00431                             asprintf (&show, conv, response_value[i]);
00432                      }
00433               }
00434 
00435               /* Process this block for string matching */
00436               else if (eval_method[i] & CRIT_STRING) {
00437                      if (strcmp (show, string_value))
00438                             iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
00439                      else
00440                             iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
00441               }
00442 
00443               /* Process this block for regex matching */
00444               else if (eval_method[i] & CRIT_REGEX) {
00445                      excode = regexec (&preg, response, 10, pmatch, eflags);
00446                      if (excode == 0) {
00447                             iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
00448                      }
00449                      else if (excode != REG_NOMATCH) {
00450                             regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
00451                             printf (_("Execute Error: %s\n"), errbuf);
00452                             exit (STATE_CRITICAL);
00453                      }
00454                      else {
00455                             iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
00456                      }
00457               }
00458 
00459               /* Process this block for existence-nonexistence checks */
00460               /* TV: Should this be outside of this else block? */
00461               else {
00462                      if (eval_method[i] & CRIT_PRESENT)
00463                             iresult = STATE_CRITICAL;
00464                      else if (eval_method[i] & WARN_PRESENT)
00465                             iresult = STATE_WARNING;
00466                      else if (response && iresult == STATE_DEPENDENT)
00467                             iresult = STATE_OK;
00468               }
00469 
00470               /* Result is the worst outcome of all the OIDs tested */
00471               result = max_state (result, iresult);
00472 
00473               /* Prepend a label for this OID if there is one */
00474               if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
00475                      asprintf (&outbuff, "%s%s%s %s%s%s", outbuff,
00476                             (i == 0) ? " " : output_delim,
00477                             labels[i], mark (iresult), show, mark (iresult));
00478               else
00479                      asprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
00480                             mark (iresult), show, mark (iresult));
00481 
00482               /* Append a unit string for this OID if there is one */
00483               if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
00484                      asprintf (&outbuff, "%s %s", outbuff, unitv[i]);
00485 
00486               /* Write perfdata with whatever can be parsed by strtod, if possible */
00487               ptr = NULL;
00488               strtod(show, &ptr);
00489               if (ptr > show) {
00490                      if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
00491                             temp_string=labels[i];
00492                      else
00493                             temp_string=oidname;
00494                      if (strpbrk (temp_string, " ='\"") == NULL) {
00495                             strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
00496                      } else {
00497                             if (strpbrk (temp_string, "'") == NULL) {
00498                                    quote_string="'";
00499                             } else {
00500                                    quote_string="\"";
00501                             }
00502                             strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1);
00503                             strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
00504                             strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1);
00505                      }
00506                      strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
00507                      len = sizeof(perfstr)-strlen(perfstr)-1;
00508                      strncat(perfstr, show, len>ptr-show ? ptr-show : len);
00509 
00510                      if (type)
00511                             strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
00512                      strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
00513               }
00514        }
00515        total_oids=i;
00516 
00517        /* Save state data, as all data collected now */
00518        if(calculate_rate) {
00519               string_length=1024;
00520               state_string=malloc(string_length);
00521               if(state_string==NULL)
00522                      die(STATE_UNKNOWN, _("Cannot malloc"));
00523               
00524               current_length=0;
00525               for(i=0; i<total_oids; i++) {
00526                      asprintf(&temp_string,"%.0f",response_value[i]);
00527                      if(temp_string==NULL)
00528                             die(STATE_UNKNOWN,_("Cannot asprintf()"));
00529                      response_length = strlen(temp_string);
00530                      if(current_length+response_length>string_length) {
00531                             string_length=current_length+1024;
00532                             state_string=realloc(state_string,string_length);
00533                             if(state_string==NULL)
00534                                    die(STATE_UNKNOWN, _("Cannot realloc()"));
00535                      }
00536                      strcpy(&state_string[current_length],temp_string);
00537                      current_length=current_length+response_length;
00538                      state_string[current_length]=':';
00539                      current_length++;
00540                      free(temp_string);
00541               }
00542               state_string[--current_length]='\0';
00543               if (verbose > 2)
00544                      printf("State string=%s\n",state_string);
00545               
00546               /* This is not strictly the same as time now, but any subtle variations will cancel out */
00547               np_state_write_string(current_time, state_string );
00548               if(previous_state==NULL) {
00549                      /* Or should this be highest state? */
00550                      die( STATE_OK, _("No previous data to calculate rate - assume okay" ) );
00551               }
00552        }
00553 
00554        printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr);
00555        if (mult_resp) printf ("%s", mult_resp);
00556 
00557        return result;
00558 }
00559 
00560 
00561 
00562 /* process command-line arguments */
00563 int
00564 process_arguments (int argc, char **argv)
00565 {
00566        char *ptr;
00567        int c = 1;
00568        int j = 0, jj = 0, ii = 0;
00569 
00570        int option = 0;
00571        static struct option longopts[] = {
00572               STD_LONG_OPTS,
00573               {"community", required_argument, 0, 'C'},
00574               {"oid", required_argument, 0, 'o'},
00575               {"object", required_argument, 0, 'o'},
00576               {"delimiter", required_argument, 0, 'd'},
00577               {"output-delimiter", required_argument, 0, 'D'},
00578               {"string", required_argument, 0, 's'},
00579               {"timeout", required_argument, 0, 't'},
00580               {"regex", required_argument, 0, 'r'},
00581               {"ereg", required_argument, 0, 'r'},
00582               {"eregi", required_argument, 0, 'R'},
00583               {"label", required_argument, 0, 'l'},
00584               {"units", required_argument, 0, 'u'},
00585               {"port", required_argument, 0, 'p'},
00586               {"retries", required_argument, 0, 'e'},
00587               {"miblist", required_argument, 0, 'm'},
00588               {"protocol", required_argument, 0, 'P'},
00589               {"seclevel", required_argument, 0, 'L'},
00590               {"secname", required_argument, 0, 'U'},
00591               {"authproto", required_argument, 0, 'a'},
00592               {"privproto", required_argument, 0, 'x'},
00593               {"authpasswd", required_argument, 0, 'A'},
00594               {"privpasswd", required_argument, 0, 'X'},
00595               {"next", no_argument, 0, 'n'},
00596               {"rate", no_argument, 0, L_CALCULATE_RATE},
00597               {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
00598               {"invert-search", no_argument, 0, L_INVERT_SEARCH},
00599               {"perf-oids", no_argument, 0, 'O'},
00600               {0, 0, 0, 0}
00601        };
00602 
00603        if (argc < 2)
00604               return ERROR;
00605 
00606        /* reverse compatibility for very old non-POSIX usage forms */
00607        for (c = 1; c < argc; c++) {
00608               if (strcmp ("-to", argv[c]) == 0)
00609                      strcpy (argv[c], "-t");
00610               if (strcmp ("-wv", argv[c]) == 0)
00611                      strcpy (argv[c], "-w");
00612               if (strcmp ("-cv", argv[c]) == 0)
00613                      strcpy (argv[c], "-c");
00614        }
00615 
00616        while (1) {
00617               c = getopt_long (argc, argv, "nhvVOt:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:L:U:a:x:A:X:",
00618                                                                 longopts, &option);
00619 
00620               if (c == -1 || c == EOF)
00621                      break;
00622 
00623               switch (c) {
00624               case '?':     /* usage */
00625                      usage5 ();
00626               case 'h':     /* help */
00627                      print_help ();
00628                      exit (STATE_OK);
00629               case 'V':     /* version */
00630                      print_revision (progname, NP_VERSION);
00631                      exit (STATE_OK);
00632               case 'v': /* verbose */
00633                      verbose++;
00634                      break;
00635 
00636        /* Connection info */
00637               case 'C':                                                             /* group or community */
00638                      community = optarg;
00639                      break;
00640               case 'H':                                                             /* Host or server */
00641                      server_address = optarg;
00642                      break;
00643               case 'p':     /* TCP port number */
00644                      port = optarg;
00645                      break;
00646               case 'm':     /* List of MIBS */
00647                      miblist = optarg;
00648                      break;
00649               case 'n':     /* usesnmpgetnext */
00650                      usesnmpgetnext = TRUE;
00651                      break;
00652               case 'P':     /* SNMP protocol version */
00653                      proto = optarg;
00654                      break;
00655               case 'L':     /* security level */
00656                      seclevel = optarg;
00657                      break;
00658               case 'U':     /* security username */
00659                      secname = optarg;
00660                      break;
00661               case 'a':     /* auth protocol */
00662                      authproto = optarg;
00663                      break;
00664               case 'x':     /* priv protocol */
00665                      privproto = optarg;
00666                      break;
00667               case 'A':     /* auth passwd */
00668                      authpasswd = optarg;
00669                      break;
00670               case 'X':     /* priv passwd */
00671                      privpasswd = optarg;
00672                      break;
00673               case 't':     /* timeout period */
00674                      if (!is_integer (optarg))
00675                             usage2 (_("Timeout interval must be a positive integer"), optarg);
00676                      else
00677                             timeout_interval = atoi (optarg);
00678                      break;
00679 
00680        /* Test parameters */
00681               case 'c':                                                             /* critical threshold */
00682                      critical_thresholds = optarg;
00683                      break;
00684               case 'w':                                                             /* warning threshold */
00685                      warning_thresholds = optarg;
00686                      break;
00687               case 'e': /* PRELIMINARY - may change */
00688               case 'E': /* PRELIMINARY - may change */
00689                      if (!is_integer (optarg))
00690                             usage2 (_("Retries interval must be a positive integer"), optarg);
00691                      else
00692                             retries = atoi(optarg);
00693                      break;
00694               case 'o':                                                             /* object identifier */
00695                      if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) {
00696                                    /*
00697                                     * we have something other than digits, periods and comas,
00698                                     * so we have a mib variable, rather than just an SNMP OID,
00699                                     * so we have to actually read the mib files
00700                                     */
00701                                    needmibs = TRUE;
00702                      }
00703                      if (!oids) oids = calloc(MAX_OIDS, sizeof (char *));
00704                      for (ptr = strtok(optarg, ", "); ptr != NULL && j < MAX_OIDS; ptr = strtok(NULL, ", "), j++) {
00705                             oids[j] = strdup(ptr);
00706                      }
00707                      numoids = j;
00708                      if (c == 'E' || c == 'e') {
00709                             jj++;
00710                             ii++;
00711                      }
00712                      if (c == 'E')
00713                             eval_method[j+1] |= WARN_PRESENT;
00714                      else if (c == 'e')
00715                             eval_method[j+1] |= CRIT_PRESENT;
00716                      break;
00717               case 's':                                                             /* string or substring */
00718                      strncpy (string_value, optarg, sizeof (string_value) - 1);
00719                      string_value[sizeof (string_value) - 1] = 0;
00720                      eval_method[jj++] = CRIT_STRING;
00721                      ii++;
00722                      break;
00723               case 'R':                                                             /* regex */
00724                      cflags = REG_ICASE;
00725               case 'r':                                                             /* regex */
00726                      cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
00727                      strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
00728                      regex_expect[sizeof (regex_expect) - 1] = 0;
00729                      errcode = regcomp (&preg, regex_expect, cflags);
00730                      if (errcode != 0) {
00731                             regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
00732                             printf (_("Could Not Compile Regular Expression"));
00733                             return ERROR;
00734                      }
00735                      eval_method[jj++] = CRIT_REGEX;
00736                      ii++;
00737                      break;
00738 
00739        /* Format */
00740               case 'd':                                                             /* delimiter */
00741                      delimiter = strscpy (delimiter, optarg);
00742                      break;
00743               case 'D':                                                             /* output-delimiter */
00744                      output_delim = strscpy (output_delim, optarg);
00745                      break;
00746               case 'l':                                                             /* label */
00747                      nlabels++;
00748                      if (nlabels >= labels_size) {
00749                             labels_size += 8;
00750                             labels = realloc (labels, labels_size);
00751                             if (labels == NULL)
00752                                    die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
00753                      }
00754                      labels[nlabels - 1] = optarg;
00755                      ptr = thisarg (optarg);
00756                      labels[nlabels - 1] = ptr;
00757                      if (ptr[0] == '\'')
00758                             labels[nlabels - 1] = ptr + 1;
00759                      while (ptr && (ptr = nextarg (ptr))) {
00760                             if (nlabels >= labels_size) {
00761                                    labels_size += 8;
00762                                    labels = realloc (labels, labels_size);
00763                                    if (labels == NULL)
00764                                           die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
00765                             }
00766                             nlabels++;
00767                             ptr = thisarg (ptr);
00768                             if (ptr[0] == '\'')
00769                                    labels[nlabels - 1] = ptr + 1;
00770                             else
00771                                    labels[nlabels - 1] = ptr;
00772                      }
00773                      break;
00774               case 'u':                                                             /* units */
00775                      units = optarg;
00776                      nunits++;
00777                      if (nunits >= unitv_size) {
00778                             unitv_size += 8;
00779                             unitv = realloc (unitv, unitv_size);
00780                             if (unitv == NULL)
00781                                    die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
00782                      }
00783                      unitv[nunits - 1] = optarg;
00784                      ptr = thisarg (optarg);
00785                      unitv[nunits - 1] = ptr;
00786                      if (ptr[0] == '\'')
00787                             unitv[nunits - 1] = ptr + 1;
00788                      while (ptr && (ptr = nextarg (ptr))) {
00789                             if (nunits >= unitv_size) {
00790                                    unitv_size += 8;
00791                                    unitv = realloc (unitv, unitv_size);
00792                                    if (units == NULL)
00793                                           die (STATE_UNKNOWN, _("Could not realloc() units\n"));
00794                             }
00795                             nunits++;
00796                             ptr = thisarg (ptr);
00797                             if (ptr[0] == '\'')
00798                                    unitv[nunits - 1] = ptr + 1;
00799                             else
00800                                    unitv[nunits - 1] = ptr;
00801                      }
00802                      break;
00803               case L_CALCULATE_RATE:
00804                      if(calculate_rate==0)
00805                             np_enable_state(NULL, 1);
00806                      calculate_rate = 1;
00807                      break;
00808               case L_RATE_MULTIPLIER:
00809                      if(!is_integer(optarg)||((rate_multiplier=atoi(optarg))<=0))
00810                             usage2(_("Rate multiplier must be a positive integer"),optarg);
00811                      break;
00812               case L_INVERT_SEARCH:
00813                      invert_search=1;
00814                      break;
00815               case 'O':
00816                      perf_labels=0;
00817                      break;
00818               }
00819        }
00820 
00821        if (server_address == NULL)
00822               server_address = argv[optind];
00823 
00824        if (community == NULL)
00825               community = strdup (DEFAULT_COMMUNITY);
00826 
00827        return validate_arguments ();
00828 }
00829 
00830 
00831 /******************************************************************************
00832 
00833 @@-
00834 <sect3>
00835 <title>validate_arguments</title>
00836 
00837 <para>&PROTO_validate_arguments;</para>
00838 
00839 <para>Checks to see if the default miblist needs to be loaded. Also verifies
00840 the authentication and authorization combinations based on protocol version
00841 selected.</para>
00842 
00843 <para></para>
00844 
00845 </sect3>
00846 -@@
00847 ******************************************************************************/
00848 
00849 
00850 
00851 int
00852 validate_arguments ()
00853 {
00854        /* check whether to load locally installed MIBS (CPU/disk intensive) */
00855        if (miblist == NULL) {
00856               if ( needmibs == TRUE ) {
00857                      miblist = strdup (DEFAULT_MIBLIST);
00858               }else{
00859                      miblist = "";               /* don't read any mib files for numeric oids */
00860               }
00861        }
00862 
00863        /* Check server_address is given */
00864        if (server_address == NULL)
00865               die(STATE_UNKNOWN, _("No host specified\n"));
00866 
00867        /* Check oid is given */
00868        if (numoids == 0)
00869               die(STATE_UNKNOWN, _("No OIDs specified\n"));
00870 
00871        if (proto == NULL)
00872               asprintf(&proto, DEFAULT_PROTOCOL);
00873 
00874        if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) {    /* snmpv1 or snmpv2c */
00875               numauthpriv = 2;
00876               authpriv = calloc (numauthpriv, sizeof (char *));
00877               authpriv[0] = strdup ("-c");
00878               authpriv[1] = strdup (community);
00879        }
00880        else if ( strcmp (proto, "3") == 0 ) {           /* snmpv3 args */
00881               if (seclevel == NULL)
00882                      asprintf(&seclevel, "noAuthNoPriv");
00883 
00884               if (strcmp(seclevel, "noAuthNoPriv") == 0) {
00885                      numauthpriv = 2;
00886                      authpriv = calloc (numauthpriv, sizeof (char *));
00887                      authpriv[0] = strdup ("-l");
00888                      authpriv[1] = strdup ("noAuthNoPriv");
00889               } else {
00890                      if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
00891                             usage2 (_("Invalid seclevel"), seclevel);
00892                      }
00893 
00894                      if (authproto == NULL )
00895                             asprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
00896 
00897                      if (secname == NULL)
00898                             die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
00899 
00900                      if (authpasswd == NULL)
00901                             die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
00902 
00903                      if ( strcmp(seclevel, "authNoPriv") == 0 ) {
00904                             numauthpriv = 8;
00905                             authpriv = calloc (numauthpriv, sizeof (char *));
00906                             authpriv[0] = strdup ("-l");
00907                             authpriv[1] = strdup ("authNoPriv");
00908                             authpriv[2] = strdup ("-a");
00909                             authpriv[3] = strdup (authproto);
00910                             authpriv[4] = strdup ("-u");
00911                             authpriv[5] = strdup (secname);
00912                             authpriv[6] = strdup ("-A");
00913                             authpriv[7] = strdup (authpasswd);
00914                      } else if ( strcmp(seclevel, "authPriv") == 0 ) {
00915                             if (privproto == NULL )
00916                                    asprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
00917 
00918                             if (privpasswd == NULL)
00919                                    die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
00920 
00921                             numauthpriv = 12;
00922                             authpriv = calloc (numauthpriv, sizeof (char *));
00923                             authpriv[0] = strdup ("-l");
00924                             authpriv[1] = strdup ("authPriv");
00925                             authpriv[2] = strdup ("-a");
00926                             authpriv[3] = strdup (authproto);
00927                             authpriv[4] = strdup ("-u");
00928                             authpriv[5] = strdup (secname);
00929                             authpriv[6] = strdup ("-A");
00930                             authpriv[7] = strdup (authpasswd);
00931                             authpriv[8] = strdup ("-x");
00932                             authpriv[9] = strdup (privproto);
00933                             authpriv[10] = strdup ("-X");
00934                             authpriv[11] = strdup (privpasswd);
00935                      }
00936               }
00937 
00938        }
00939        else {
00940               usage2 (_("Invalid SNMP version"), proto);
00941        }
00942 
00943        return OK;
00944 }
00945 
00946 
00947 
00948 /* trim leading whitespace
00949         if there is a leading quote, make sure it balances */
00950 
00951 char *
00952 thisarg (char *str)
00953 {
00954        str += strspn (str, " \t\r\n");    /* trim any leading whitespace */
00955        if (str[0] == '\'') {       /* handle SIMPLE quoted strings */
00956               if (strlen (str) == 1 || !strstr (str + 1, "'"))
00957                      die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
00958        }
00959        return str;
00960 }
00961 
00962 
00963 
00964 /* if there's a leading quote, advance to the trailing quote
00965         set the trailing quote to '\x0'
00966         if the string continues, advance beyond the comma */
00967 
00968 char *
00969 nextarg (char *str)
00970 {
00971        if (str[0] == '\'') {
00972               str[0] = 0;
00973               if (strlen (str) > 1) {
00974                      str = strstr (str + 1, "'");
00975                      return (++str);
00976               }
00977               else {
00978                      return NULL;
00979               }
00980        }
00981        if (str[0] == ',') {
00982               str[0] = 0;
00983               if (strlen (str) > 1) {
00984                      return (++str);
00985               }
00986               else {
00987                      return NULL;
00988               }
00989        }
00990        if ((str = strstr (str, ",")) && strlen (str) > 1) {
00991               str[0] = 0;
00992               return (++str);
00993        }
00994        return NULL;
00995 }
00996 
00997 
00998 
00999 void
01000 print_help (void)
01001 {
01002        print_revision (progname, NP_VERSION);
01003 
01004        printf (COPYRIGHT, copyright, email);
01005 
01006        printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
01007 
01008        printf ("\n\n");
01009 
01010        print_usage ();
01011 
01012        printf (UT_HELP_VRSN);
01013        printf (UT_EXTRA_OPTS);
01014 
01015        printf (UT_HOST_PORT, 'p', DEFAULT_PORT);
01016 
01017        /* SNMP and Authentication Protocol */
01018        printf (" %s\n", "-n, --next");
01019        printf ("    %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
01020        printf (" %s\n", "-P, --protocol=[1|2c|3]");
01021        printf ("    %s\n", _("SNMP protocol version"));
01022        printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
01023        printf ("    %s\n", _("SNMPv3 securityLevel"));
01024        printf (" %s\n", "-a, --authproto=[MD5|SHA]");
01025        printf ("    %s\n", _("SNMPv3 auth proto"));
01026        printf (" %s\n", "-x, --privproto=[DES|AES]");
01027        printf ("    %s\n", _("SNMPv3 priv proto (default DES)"));
01028 
01029        /* Authentication Tokens*/
01030        printf (" %s\n", "-C, --community=STRING");
01031        printf ("    %s ", _("Optional community string for SNMP communication"));
01032        printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
01033        printf (" %s\n", "-U, --secname=USERNAME");
01034        printf ("    %s\n", _("SNMPv3 username"));
01035        printf (" %s\n", "-A, --authpassword=PASSWORD");
01036        printf ("    %s\n", _("SNMPv3 authentication password"));
01037        printf (" %s\n", "-X, --privpasswd=PASSWORD");
01038        printf ("    %s\n", _("SNMPv3 privacy password"));
01039 
01040        /* OID Stuff */
01041        printf (" %s\n", "-o, --oid=OID(s)");
01042        printf ("    %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
01043        printf (" %s\n", "-m, --miblist=STRING");
01044        printf ("    %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
01045        printf ("    %s\n", _("for symbolic OIDs.)"));
01046        printf (" %s\n", "-d, --delimiter=STRING");
01047        printf ("    %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
01048        printf ("    %s\n", _("Any data on the right hand side of the delimiter is considered"));
01049        printf ("    %s\n", _("to be the data that should be used in the evaluation."));
01050 
01051        /* Tests Against Integers */
01052        printf (" %s\n", "-w, --warning=THRESHOLD(s)");
01053        printf ("    %s\n", _("Warning threshold range(s)"));
01054        printf (" %s\n", "-c, --critical=THRESHOLD(s)");
01055        printf ("    %s\n", _("Critical threshold range(s)"));
01056        printf (" %s\n", "--rate");
01057        printf ("    %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
01058        printf (" %s\n", "--rate-multiplier");
01059        printf ("    %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
01060 
01061        /* Tests Against Strings */
01062        printf (" %s\n", "-s, --string=STRING");
01063        printf ("    %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
01064        printf (" %s\n", "-r, --ereg=REGEX");
01065        printf ("    %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
01066        printf (" %s\n", "-R, --eregi=REGEX");
01067        printf ("    %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
01068        printf (" %s\n", "--invert-search");
01069        printf ("    %s\n", _("Invert search result (CRITICAL if found)"));
01070 
01071        /* Output Formatting */
01072        printf (" %s\n", "-l, --label=STRING");
01073        printf ("    %s\n", _("Prefix label for output from plugin"));
01074        printf (" %s\n", "-u, --units=STRING");
01075        printf ("    %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
01076        printf (" %s\n", "-D, --output-delimiter=STRING");
01077        printf ("    %s\n", _("Separates output on multiple OID requests"));
01078 
01079        printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
01080        printf (" %s\n", "-e, --retries=INTEGER");
01081        printf ("    %s\n", _("Number of retries to be used in the requests"));
01082 
01083        printf (" %s\n", "-O, --perf-oids");
01084        printf ("    %s\n", _("Label performance data with OIDs instead of --label's"));
01085 
01086        printf (UT_VERBOSE);
01087 
01088        printf ("\n");
01089        printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
01090        printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
01091        printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
01092 
01093        printf ("\n");
01094        printf ("%s\n", _("Notes:"));
01095        printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited  "));
01096        printf ("   %s %i %s\n", _("list (lists with internal spaces must be quoted). Maximum:"), MAX_OIDS, _("OIDs."));
01097 
01098        printf(" -%s", UT_THRESHOLDS_NOTES);
01099 
01100        printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
01101        printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
01102        printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
01103        printf ("   %s\n", _("returned from the SNMP query is an unsigned integer."));
01104 
01105        printf("\n");
01106        printf("%s\n", _("Rate Calculation:"));
01107        printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
01108        printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
01109        printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
01110        printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
01111        printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
01112        printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
01113        printf(" %s\n", _("changing the arguments will create a new state file."));
01114 
01115        printf (UT_SUPPORT);
01116 }
01117 
01118 
01119 
01120 void
01121 print_usage (void)
01122 {
01123        printf ("%s\n", _("Usage:"));
01124        printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname);
01125        printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
01126        printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
01127        printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
01128        printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");
01129 }