Print this page
    
NEX-18417 bring back UUID-based OIDs for FM traps
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-17772 libfmd_snmp should learn about new FmProblem fields
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-16536 SUN-IREPORT-MIB is broken
NEX-16537 enhance FM traps
NEX-16545 SMF dict should have obsolete entries removed
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-14494 FMA related SNMP traps should add description
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/fm/notify/snmp-notify/common/snmp-notify.c
          +++ new/usr/src/cmd/fm/notify/snmp-notify/common/snmp-notify.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  
    | 
      ↓ open down ↓ | 
    15 lines elided | 
    
      ↑ open up ↑ | 
  
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   */
  25   25  
       26 +/*
       27 + * Copyright 2018 Nexenta Systems, Inc.
       28 + */
       29 +
  26   30  #include <sys/fm/protocol.h>
       31 +
  27   32  #include <fm/fmd_snmp.h>
  28   33  #include <fm/fmd_msg.h>
  29   34  #include <fm/libfmevent.h>
       35 +
  30   36  #include <net-snmp/net-snmp-config.h>
  31   37  #include <net-snmp/net-snmp-includes.h>
  32   38  #include <net-snmp/agent/net-snmp-agent-includes.h>
       39 +
       40 +#include <alloca.h>
  33   41  #include <errno.h>
       42 +#include <limits.h>
  34   43  #include <locale.h>
  35   44  #include <netdb.h>
       45 +#include <priv_utils.h>
  36   46  #include <signal.h>
  37      -#include <strings.h>
  38   47  #include <stdlib.h>
       48 +#include <strings.h>
  39   49  #include <unistd.h>
  40      -#include <limits.h>
  41      -#include <alloca.h>
  42      -#include <priv_utils.h>
  43   50  #include <zone.h>
       51 +
  44   52  #include "libfmnotify.h"
  45   53  
  46   54  /*
  47   55   * Debug messages can be enabled by setting the debug property to true
  48   56   *
  49   57   * # svccfg -s svc:/system/fm/snmp-notify setprop config/debug=true
  50   58   */
  51   59  #define SVCNAME         "system/fm/snmp-notify"
  52   60  
  53   61  typedef struct ireport_trap {
       62 +        long long tstamp;
  54   63          char *host;
  55   64          char *msgid;
       65 +        char *severity;
  56   66          char *desc;
  57      -        long long tstamp;
  58   67          char *fmri;
  59   68          uint32_t from_state;
  60   69          uint32_t to_state;
  61   70          char *reason;
  62   71          boolean_t is_stn_event;
  63   72  } ireport_trap_t;
  64   73  
       74 +typedef struct fmproblem_trap {
       75 +        char *uuid;
       76 +        char *host;
       77 +        char *code;
       78 +        char *type;
       79 +        char *severity;
       80 +        char *url;
       81 +        char *descr;
       82 +        char *fmri;
       83 +} fmproblem_trap_t;
       84 +
  65   85  static nd_hdl_t *nhdl;
  66   86  static const char optstr[] = "dfR:";
  67   87  static const char SNMP_SUPPCONF[] = "fmd-trapgen";
  68   88  static char hostname[MAXHOSTNAMELEN + 1];
  69   89  
  70   90  static int
  71   91  usage(const char *pname)
  72   92  {
  73   93          (void) fprintf(stderr, "Usage: %s [-df] [-R <altroot>]\n", pname);
  74   94  
  75   95          (void) fprintf(stderr,
  76   96              "\t-d  enable debug mode\n"
  77   97              "\t-f  stay in foreground\n"
  78   98              "\t-R  specify alternate root\n");
  79   99  
  80  100          return (1);
  81  101  }
  82  102  
  83  103  /*
  84  104   * If someone does an "svcadm refresh" on us, then this function gets called,
  85  105   * which rereads our service configuration.
  86  106   */
  87  107  static void
  88  108  get_svc_config()
  89  109  {
  90  110          int s = 0;
  91  111          uint8_t val;
  92  112  
  93  113          s = nd_get_boolean_prop(nhdl, SVCNAME, "config", "debug", &val);
  94  114          nhdl->nh_debug = val;
  95  115  
  96  116          s += nd_get_astring_prop(nhdl, SVCNAME, "config", "rootdir",
  97  117              &(nhdl->nh_rootdir));
  98  118  
  99  119          if (s != 0)
 100  120                  nd_error(nhdl, "Failed to read retrieve service "
 101  121                      "properties");
 102  122  }
 103  123  
 104  124  static void
 105  125  nd_sighandler(int sig)
 106  126  {
 107  127          if (sig == SIGHUP)
 108  128                  get_svc_config();
 109  129          else
 110  130                  nd_cleanup(nhdl);
 111  131  }
 112  132  
 113  133  static int
 114  134  get_snmp_prefs(nd_hdl_t *nhdl, nvlist_t **pref_nvl, uint_t npref)
 115  135  {
 116  136          boolean_t *a1, *a2;
 117  137          uint_t n;
 118  138          int r;
 119  139  
 120  140          /*
 121  141           * For SMF state transition events, pref_nvl contain two sets of
 122  142           * preferences, which will have to be merged.
 123  143           *
 124  144           * The "snmp" nvlist currently only supports a single boolean member,
 125  145           * "active" which will be set to true, if it is true in either set
 126  146           */
 127  147          if (npref == 2) {
 128  148                  r = nvlist_lookup_boolean_array(pref_nvl[0], "active", &a1, &n);
 129  149                  r += nvlist_lookup_boolean_array(pref_nvl[1], "active", &a2,
 130  150                      &n);
 131  151                  if (r != 0) {
 132  152                          nd_debug(nhdl, "Malformed snmp notification "
 133  153                              "preferences");
 134  154                          nd_dump_nvlist(nhdl, pref_nvl[0]);
 135  155                          nd_dump_nvlist(nhdl, pref_nvl[1]);
 136  156                          return (-1);
 137  157                  } else if (!a1[0] && !a2[0]) {
 138  158                          nd_debug(nhdl, "SNMP notification is disabled");
 139  159                          return (-1);
 140  160                  }
 141  161          } else {
 142  162                  if (nvlist_lookup_boolean_array(pref_nvl[0], "active",
 143  163                      &a1, &n)) {
 144  164                          nd_debug(nhdl, "Malformed snmp notification "
 145  165                              "preferences");
 146  166                          nd_dump_nvlist(nhdl, pref_nvl[0]);
 147  167                          return (-1);
 148  168                  } else if (!a1[0]) {
 149  169                          nd_debug(nhdl, "SNMP notification is disabled");
 150  170                          return (-1);
 151  171                  }
 152  172          }
 153  173          return (0);
 154  174  }
 155  175  
 156  176  static void
 157  177  send_ireport_trap(ireport_trap_t *t)
  
    | 
      ↓ open down ↓ | 
    83 lines elided | 
    
      ↑ open up ↑ | 
  
 158  178  {
 159  179          static const oid sunIreportTrap_oid[] =
 160  180              { SUNIREPORTTRAP_OID };
 161  181          const size_t sunIreportTrap_len =
 162  182              OID_LENGTH(sunIreportTrap_oid);
 163  183  
 164  184          static const oid sunIreportHostname_oid[] =
 165  185              { SUNIREPORTHOSTNAME_OID };
 166  186          static const oid sunIreportMsgid_oid[] =
 167  187              { SUNIREPORTMSGID_OID };
      188 +        static const oid sunIreportSeverity_oid[] =
      189 +            { SUNIREPORTSEVERITY_OID };
 168  190          static const oid sunIreportDescription_oid[] =
 169  191              { SUNIREPORTDESCRIPTION_OID };
 170  192          static const oid sunIreportTime_oid[] =
 171  193              { SUNIREPORTTIME_OID };
 172  194  
 173  195          static const oid sunIreportSmfFmri_oid[] =
 174  196              { SUNIREPORTSMFFMRI_OID };
 175  197          static const oid sunIreportSmfFromState_oid[] =
 176  198              { SUNIREPORTSMFFROMSTATE_OID };
 177  199          static const oid sunIreportSmfToState_oid[] =
 178  200              { SUNIREPORTSMFTOSTATE_OID };
 179  201          static const oid sunIreportSmfTransitionReason_oid[] =
 180  202              { SUNIREPORTTRANSITIONREASON_OID };
 181  203          const size_t
 182  204              sunIreport_base_len = OID_LENGTH(sunIreportHostname_oid);
 183  205  
      206 +        size_t oid_len = sunIreport_base_len * sizeof (oid);
 184  207          size_t var_len = sunIreport_base_len + 1;
 185      -        oid var_name[MAX_OID_LEN];
      208 +        oid var_name[MAX_OID_LEN] = { 0 };
 186  209  
 187  210          netsnmp_variable_list *notification_vars = NULL;
 188  211  
 189  212          size_t dt_len;
 190  213          uchar_t dt[11], *tdt;
 191  214          time_t ts = t->tstamp;
 192  215  
 193  216          tdt = date_n_time(&ts, &dt_len);
 194  217          /*
 195  218           * We know date_n_time is broken, it returns a buffer from
 196  219           * its stack. So we copy before we step over it!
  
    | 
      ↓ open down ↓ | 
    1 lines elided | 
    
      ↑ open up ↑ | 
  
 197  220           */
 198  221          for (int i = 0; i < dt_len; ++i)
 199  222                  dt[i] = tdt[i];
 200  223  
 201  224          if (var_len > MAX_OID_LEN) {
 202  225                  nd_error(nhdl, "var_len %d > MAX_OID_LEN %d\n", var_len,
 203  226                      MAX_OID_LEN);
 204  227                  return;
 205  228          }
 206  229  
 207      -        (void) memcpy(var_name, sunIreportHostname_oid, sunIreport_base_len *
 208      -            sizeof (oid));
      230 +        (void) memcpy(var_name, sunIreportHostname_oid, oid_len);
 209  231          (void) snmp_varlist_add_variable(¬ification_vars, var_name,
 210      -            sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->host,
 211      -            strlen(t->host));
      232 +            var_len, ASN_OCTET_STR, (uchar_t *)t->host, strlen(t->host));
 212  233  
 213      -        (void) memcpy(var_name, sunIreportMsgid_oid,
 214      -            sunIreport_base_len * sizeof (oid));
      234 +        (void) memcpy(var_name, sunIreportMsgid_oid, oid_len);
 215  235          (void) snmp_varlist_add_variable(¬ification_vars, var_name,
 216      -            sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->msgid,
 217      -            strlen(t->msgid));
      236 +            var_len, ASN_OCTET_STR, (uchar_t *)t->msgid, strlen(t->msgid));
 218  237  
 219      -        (void) memcpy(var_name, sunIreportDescription_oid,
 220      -            sunIreport_base_len * sizeof (oid));
      238 +        (void) memcpy(var_name, sunIreportSeverity_oid, oid_len);
 221  239          (void) snmp_varlist_add_variable(¬ification_vars, var_name,
 222      -            sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->desc,
 223      -            strlen(t->desc));
      240 +            var_len, ASN_OCTET_STR, (uchar_t *)t->severity,
      241 +            strlen(t->severity));
 224  242  
 225      -        (void) memcpy(var_name, sunIreportTime_oid, sunIreport_base_len *
 226      -            sizeof (oid));
      243 +        (void) memcpy(var_name, sunIreportDescription_oid, oid_len);
 227  244          (void) snmp_varlist_add_variable(¬ification_vars, var_name,
 228      -            sunIreport_base_len + 1, ASN_OCTET_STR, dt, dt_len);
      245 +            var_len, ASN_OCTET_STR, (uchar_t *)t->desc, strlen(t->desc));
 229  246  
      247 +        (void) memcpy(var_name, sunIreportTime_oid, oid_len);
      248 +        (void) snmp_varlist_add_variable(¬ification_vars, var_name,
      249 +            var_len, ASN_OCTET_STR, dt, dt_len);
      250 +
 230  251          if (t->is_stn_event) {
 231      -                (void) memcpy(var_name, sunIreportSmfFmri_oid,
 232      -                    sunIreport_base_len * sizeof (oid));
      252 +                (void) memcpy(var_name, sunIreportSmfFmri_oid, oid_len);
 233  253                  (void) snmp_varlist_add_variable(¬ification_vars, var_name,
 234      -                    sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->fmri,
      254 +                    var_len, ASN_OCTET_STR, (uchar_t *)t->fmri,
 235  255                      strlen(t->fmri));
 236  256  
 237      -                (void) memcpy(var_name, sunIreportSmfFromState_oid,
 238      -                    sunIreport_base_len * sizeof (oid));
      257 +                (void) memcpy(var_name, sunIreportSmfFromState_oid, oid_len);
 239  258                  (void) snmp_varlist_add_variable(¬ification_vars, var_name,
 240      -                    sunIreport_base_len + 1, ASN_INTEGER,
 241      -                    (uchar_t *)&t->from_state, sizeof (uint32_t));
      259 +                    var_len, ASN_INTEGER, (uchar_t *)&t->from_state,
      260 +                    sizeof (uint32_t));
 242  261  
 243      -                (void) memcpy(var_name, sunIreportSmfToState_oid,
 244      -                    sunIreport_base_len * sizeof (oid));
      262 +                (void) memcpy(var_name, sunIreportSmfToState_oid, oid_len);
 245  263                  (void) snmp_varlist_add_variable(¬ification_vars, var_name,
 246      -                    sunIreport_base_len + 1, ASN_INTEGER,
 247      -                    (uchar_t *)&t->to_state, sizeof (uint32_t));
      264 +                    var_len, ASN_INTEGER, (uchar_t *)&t->to_state,
      265 +                    sizeof (uint32_t));
 248  266  
 249  267                  (void) memcpy(var_name, sunIreportSmfTransitionReason_oid,
 250      -                    sunIreport_base_len * sizeof (oid));
      268 +                    oid_len);
 251  269                  (void) snmp_varlist_add_variable(¬ification_vars, var_name,
 252      -                    sunIreport_base_len + 1, ASN_OCTET_STR,
 253      -                    (uchar_t *)t->reason, strlen(t->reason));
      270 +                    var_len, ASN_OCTET_STR, (uchar_t *)t->reason,
      271 +                    strlen(t->reason));
 254  272          }
 255  273  
 256  274          /*
 257  275           * This function is capable of sending both v1 and v2/v3 traps.
 258  276           * Which is sent to a specific destination is determined by the
 259  277           * configuration file(s).
 260  278           */
 261  279          send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC,
 262  280              sunIreportTrap_oid[sunIreportTrap_len - 1],
 263  281              (oid *)sunIreportTrap_oid, sunIreportTrap_len - 2,
 264  282              notification_vars);
 265  283          nd_debug(nhdl, "Sent SNMP trap for %s", t->msgid);
 266  284  
 267  285          snmp_free_varbind(notification_vars);
 268      -
 269  286  }
 270  287  
 271      -/*ARGSUSED*/
 272  288  static void
 273      -send_fm_trap(const char *uuid, const char *code, const char *url)
      289 +send_fm_trap(fmproblem_trap_t *t)
 274  290  {
 275  291          static const oid sunFmProblemTrap_oid[] = { SUNFMPROBLEMTRAP_OID };
 276  292          const size_t sunFmProblemTrap_len = OID_LENGTH(sunFmProblemTrap_oid);
 277  293  
 278  294          static const oid sunFmProblemUUID_oid[] =
 279  295              { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_UUID };
      296 +        static const oid sunFmProblemHostname_oid[] =
      297 +            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_HOSTNAME };
 280  298          static const oid sunFmProblemCode_oid[] =
 281  299              { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_CODE };
      300 +        static const oid sunFmProblemType_oid[] =
      301 +            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_TYPE };
      302 +        static const oid sunFmProblemSeverity_oid[] =
      303 +            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_SEVERITY };
 282  304          static const oid sunFmProblemURL_oid[] =
 283  305              { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_URL };
      306 +        static const oid sunFmProblemDescr_oid[] =
      307 +            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_DESC };
      308 +        static const oid sunFmProblemFMRI_oid[] =
      309 +            { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_FMRI };
 284  310  
 285  311          const size_t sunFmProblem_base_len = OID_LENGTH(sunFmProblemUUID_oid);
 286  312  
 287      -        size_t uuid_len = strlen(uuid);
      313 +        size_t oid_len = sunFmProblem_base_len * sizeof (oid);
      314 +        size_t uuid_len = strlen(t->uuid);
 288  315          size_t var_len = sunFmProblem_base_len + 1 + uuid_len;
 289  316          oid var_name[MAX_OID_LEN];
 290  317  
 291  318          netsnmp_variable_list *notification_vars = NULL;
 292  319  
 293  320          /*
 294  321           * The format of our trap varbinds' oids is as follows:
 295  322           *
 296  323           * +-----------------------+---+--------+----------+------+
 297  324           * | SUNFMPROBLEMTABLE_OID | 1 | column | uuid_len | uuid |
 298  325           * +-----------------------+---+--------+----------+------+
 299  326           *                                       \---- index ----/
 300  327           *
 301  328           * A common mistake here is to send the trap with varbinds that
 302  329           * do not contain the index.  All the indices are the same, and
  
    | 
      ↓ open down ↓ | 
    5 lines elided | 
    
      ↑ open up ↑ | 
  
 303  330           * all the oids are the same length, so the only thing we need to
 304  331           * do for each varbind is set the table and column parts of the
 305  332           * variable name.
 306  333           */
 307  334  
 308  335          if (var_len > MAX_OID_LEN)
 309  336                  return;
 310  337  
 311  338          var_name[sunFmProblem_base_len] = (oid)uuid_len;
 312  339          for (int i = 0; i < uuid_len; i++)
 313      -                var_name[i + sunFmProblem_base_len + 1] = (oid)uuid[i];
      340 +                var_name[i + sunFmProblem_base_len + 1] = (oid)t->uuid[i];
 314  341  
 315  342          /*
 316  343           * Ordinarily, we would need to add the OID of the trap itself
 317  344           * to the head of the variable list; this is required by SNMP v2.
 318  345           * However, send_enterprise_trap_vars does this for us as a part
 319  346           * of converting between v1 and v2 traps, so we skip directly to
 320  347           * the objects we're sending.
 321  348           */
 322  349  
 323      -        (void) memcpy(var_name, sunFmProblemUUID_oid,
 324      -            sunFmProblem_base_len * sizeof (oid));
      350 +        (void) memcpy(var_name, sunFmProblemUUID_oid, oid_len);
 325  351          (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len,
 326      -            ASN_OCTET_STR, (uchar_t *)uuid, strlen(uuid));
 327      -        (void) memcpy(var_name, sunFmProblemCode_oid,
 328      -            sunFmProblem_base_len * sizeof (oid));
      352 +            ASN_OCTET_STR, (uchar_t *)t->uuid, strlen(t->uuid));
      353 +
      354 +        (void) memcpy(var_name, sunFmProblemHostname_oid, oid_len);
 329  355          (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len,
 330      -            ASN_OCTET_STR, (uchar_t *)code, strlen(code));
 331      -        (void) memcpy(var_name, sunFmProblemURL_oid,
 332      -            sunFmProblem_base_len * sizeof (oid));
      356 +            ASN_OCTET_STR, (uchar_t *)t->host, strlen(t->host));
      357 +
      358 +        (void) memcpy(var_name, sunFmProblemCode_oid, oid_len);
 333  359          (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len,
 334      -            ASN_OCTET_STR, (uchar_t *)url, strlen(url));
      360 +            ASN_OCTET_STR, (uchar_t *)t->code, strlen(t->code));
 335  361  
      362 +        (void) memcpy(var_name, sunFmProblemType_oid, oid_len);
      363 +        (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len,
      364 +            ASN_OCTET_STR, (uchar_t *)t->type, strlen(t->type));
      365 +
      366 +        (void) memcpy(var_name, sunFmProblemSeverity_oid, oid_len);
      367 +        (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len,
      368 +            ASN_OCTET_STR, (uchar_t *)t->severity, strlen(t->severity));
      369 +
      370 +        (void) memcpy(var_name, sunFmProblemURL_oid, oid_len);
      371 +        (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len,
      372 +            ASN_OCTET_STR, (uchar_t *)t->url, strlen(t->url));
      373 +
      374 +        (void) memcpy(var_name, sunFmProblemDescr_oid, oid_len);
      375 +        (void) snmp_varlist_add_variable(¬ification_vars, var_name, var_len,
      376 +            ASN_OCTET_STR, (uchar_t *)t->descr, strlen(t->descr));
      377 +
      378 +        if (strcmp(t->fmri, ND_UNKNOWN) != 0) {
      379 +                (void) memcpy(var_name, sunFmProblemFMRI_oid, oid_len);
      380 +                (void) snmp_varlist_add_variable(¬ification_vars, var_name,
      381 +                    var_len, ASN_OCTET_STR, (uchar_t *)t->fmri,
      382 +                    strlen(t->fmri));
      383 +        }
      384 +
 336  385          /*
 337  386           * This function is capable of sending both v1 and v2/v3 traps.
 338  387           * Which is sent to a specific destination is determined by the
 339  388           * configuration file(s).
 340  389           */
 341  390          send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC,
 342  391              sunFmProblemTrap_oid[sunFmProblemTrap_len - 1],
 343  392              (oid *)sunFmProblemTrap_oid, sunFmProblemTrap_len - 2,
 344  393              notification_vars);
 345      -        nd_debug(nhdl, "Sent SNMP trap for %s", code);
      394 +        nd_debug(nhdl, "Sent SNMP trap for %s", t->code);
 346  395  
 347  396          snmp_free_varbind(notification_vars);
 348  397  }
 349  398  
 350  399  /*
 351  400   * The SUN-IREPORT-MIB declares the following enum to represent SMF service
 352  401   * states.
 353  402   *
 354  403   * offline(0), online(1), degraded(2), disabled(3), maintenance(4),
 355  404   * uninitialized(5)
 356  405   *
 357  406   * This function converts a string representation of an SMF service state
 358      - * to it's corresponding enum val.
      407 + * to its corresponding enum val.
 359  408   */
 360  409  static int
 361  410  state_to_val(char *statestr, uint32_t *stateval)
 362  411  {
 363  412          if (strcmp(statestr, "offline") == 0)
 364  413                  *stateval = 0;
 365  414          else if (strcmp(statestr, "online") == 0)
 366  415                  *stateval = 1;
 367  416          else if (strcmp(statestr, "degraded") == 0)
 368  417                  *stateval = 2;
 369  418          else if (strcmp(statestr, "disabled") == 0)
 370  419                  *stateval = 3;
 371  420          else if (strcmp(statestr, "maintenance") == 0)
 372  421                  *stateval = 4;
 373  422          else if (strcmp(statestr, "uninitialized") == 0)
 374  423                  *stateval = 5;
 375  424          else
 376  425                  return (-1);
 377  426          return (0);
 378  427  }
 379  428  
 380  429  /*ARGSUSED*/
 381  430  static void
 382  431  ireport_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
 383  432  {
 384  433          nvlist_t **pref_nvl = NULL;
 385  434          nd_ev_info_t *ev_info = NULL;
 386  435          ireport_trap_t swtrap;
 387  436          uint_t npref;
 388  437          int ret;
 389  438  
 390  439          nd_debug(nhdl, "Received event of class %s", class);
 391  440  
 392  441          ret = nd_get_notify_prefs(nhdl, "snmp", ev, &pref_nvl, &npref);
 393  442          if (ret == SCF_ERROR_NOT_FOUND) {
 394  443                  /*
 395  444                   * No snmp notification preferences specified for this type of
 396  445                   * event, so we're done
 397  446                   */
 398  447                  return;
 399  448          } else if (ret != 0) {
 400  449                  nd_error(nhdl, "Failed to retrieve notification preferences "
 401  450                      "for this event");
 402  451                  return;
  
    | 
      ↓ open down ↓ | 
    34 lines elided | 
    
      ↑ open up ↑ | 
  
 403  452          }
 404  453  
 405  454          if (get_snmp_prefs(nhdl, pref_nvl, npref) != 0)
 406  455                  goto irpt_done;
 407  456  
 408  457          if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
 409  458                  goto irpt_done;
 410  459  
 411  460          swtrap.host = hostname;
 412  461          swtrap.msgid = ev_info->ei_diagcode;
      462 +        swtrap.severity = ev_info->ei_severity;
 413  463          swtrap.desc = ev_info->ei_descr;
 414  464          swtrap.tstamp = (time_t)fmev_time_sec(ev);
 415  465  
 416  466          if (strncmp(class, "ireport.os.smf", 14) == 0) {
 417  467                  swtrap.fmri = ev_info->ei_fmri;
 418  468                  if (state_to_val(ev_info->ei_from_state, &swtrap.from_state)
 419  469                      < 0 ||
 420  470                      state_to_val(ev_info->ei_to_state, &swtrap.to_state) < 0) {
 421  471                          nd_error(nhdl, "Malformed event - invalid svc state");
 422  472                          nd_dump_nvlist(nhdl, ev_info->ei_payload);
 423  473                          goto irpt_done;
 424  474                  }
 425  475                  swtrap.reason = ev_info->ei_reason;
 426  476                  swtrap.is_stn_event = B_TRUE;
 427  477          }
 428  478          send_ireport_trap(&swtrap);
  
    | 
      ↓ open down ↓ | 
    6 lines elided | 
    
      ↑ open up ↑ | 
  
 429  479  irpt_done:
 430  480          if (ev_info)
 431  481                  nd_free_event_info(ev_info);
 432  482          nd_free_nvlarray(pref_nvl, npref);
 433  483  }
 434  484  
 435  485  /*ARGSUSED*/
 436  486  static void
 437  487  list_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
 438  488  {
 439      -        char *uuid;
 440  489          uint8_t version;
 441  490          nd_ev_info_t *ev_info = NULL;
 442  491          nvlist_t **pref_nvl = NULL;
      492 +        fmproblem_trap_t fmtrap;
 443  493          uint_t npref;
 444  494          int ret;
 445  495          boolean_t domsg;
 446  496  
 447  497          nd_debug(nhdl, "Received event of class %s", class);
 448  498  
 449  499          ret = nd_get_notify_prefs(nhdl, "snmp", ev, &pref_nvl, &npref);
 450  500          if (ret == SCF_ERROR_NOT_FOUND) {
 451  501                  /*
 452  502                   * No snmp notification preferences specified for this type of
 453  503                   * event, so we're done
 454  504                   */
 455  505                  return;
 456  506          } else if (ret != 0) {
 457  507                  nd_error(nhdl, "Failed to retrieve notification preferences "
 458  508                      "for this event");
 459  509                  return;
 460  510          }
 461  511  
 462  512          if (get_snmp_prefs(nhdl, pref_nvl, npref) != 0)
 463  513                  goto listcb_done;
 464  514  
 465  515          if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
 466  516                  goto listcb_done;
 467  517  
  
    | 
      ↓ open down ↓ | 
    15 lines elided | 
    
      ↑ open up ↑ | 
  
 468  518          /*
 469  519           * If the message payload member is set to 0, then it's an event we
 470  520           * typically suppress messaging on, so we won't send a trap for it.
 471  521           */
 472  522          if (nvlist_lookup_boolean_value(ev_info->ei_payload, FM_SUSPECT_MESSAGE,
 473  523              &domsg) == 0 && !domsg) {
 474  524                  nd_debug(nhdl, "Messaging suppressed for this event");
 475  525                  goto listcb_done;
 476  526          }
 477  527  
 478      -        if (nvlist_lookup_uint8(ev_info->ei_payload, FM_VERSION, &version)
 479      -            != 0 || version > FM_SUSPECT_VERSION) {
      528 +        if (nvlist_lookup_uint8(ev_info->ei_payload, FM_VERSION,
      529 +            &version) != 0 || version > FM_SUSPECT_VERSION) {
 480  530                  nd_error(nhdl, "invalid event version: %u", version);
 481  531                  goto listcb_done;
 482  532          }
 483  533  
 484      -        (void) nvlist_lookup_string(ev_info->ei_payload, FM_SUSPECT_UUID,
 485      -            &uuid);
      534 +        fmtrap.uuid = ev_info->ei_uuid;
      535 +        fmtrap.host = hostname;
      536 +        fmtrap.code = ev_info->ei_diagcode;
      537 +        fmtrap.type = ev_info->ei_type;
      538 +        fmtrap.severity = ev_info->ei_severity;
      539 +        fmtrap.url = ev_info->ei_url;
      540 +        fmtrap.descr = ev_info->ei_descr;
      541 +        fmtrap.fmri = ev_info->ei_fmri;
 486  542  
 487      -        if (strcmp(ev_info->ei_url, ND_UNKNOWN) != 0)
 488      -                send_fm_trap(uuid, ev_info->ei_diagcode, ev_info->ei_url);
 489      -        else
 490      -                nd_error(nhdl, "failed to format url for %s", uuid);
      543 +        send_fm_trap(&fmtrap);
 491  544  listcb_done:
 492  545          nd_free_nvlarray(pref_nvl, npref);
 493  546          if (ev_info)
 494  547                  nd_free_event_info(ev_info);
 495  548  }
 496  549  
 497  550  static int
 498  551  init_sma(void)
 499  552  {
 500  553          int err;
 501  554  
 502  555          /*
 503  556           * The only place we could possibly log is syslog, but the
 504  557           * full agent doesn't normally log there.  It would be confusing
 505  558           * if this agent did so; therefore we disable logging entirely.
 506  559           */
 507  560          snmp_disable_log();
 508  561  
 509  562          /*
 510  563           * Net-SNMP has a provision for reading an arbitrary number of
 511  564           * configuration files.  A configuration file is read if it has
 512  565           * had any handlers registered for it, or if it's the value in
 513  566           * of NETSNMP_DS_LIB_APPTYPE.  Our objective here is to read
 514  567           * both snmpd.conf and fmd-trapgen.conf.
 515  568           */
 516  569          if ((err = netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
 517  570              NETSNMP_DS_AGENT_ROLE, 0 /* MASTER_AGENT */)) != SNMPERR_SUCCESS)
 518  571                  return (err);
 519  572  
 520  573          init_agent_read_config("snmpd");
 521  574          if ((err = netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
 522  575              NETSNMP_DS_LIB_APPTYPE, SNMP_SUPPCONF)) != SNMPERR_SUCCESS)
 523  576                  return (err);
 524  577          if (register_app_config_handler("trapsink", snmpd_parse_config_trapsink,
 525  578              snmpd_free_trapsinks, "host [community] [port]") == NULL)
 526  579                  return (SNMPERR_MALLOC);
 527  580          if (register_app_config_handler("trap2sink",
 528  581              snmpd_parse_config_trap2sink, NULL, "host [community] [port]") ==
 529  582              NULL)
 530  583                  return (SNMPERR_MALLOC);
 531  584          if (register_app_config_handler("trapsess", snmpd_parse_config_trapsess,
 532  585              NULL, "[snmpcmdargs] host") == NULL)
 533  586                  return (SNMPERR_MALLOC);
 534  587  
 535  588          init_traps();
 536  589          init_snmp(SNMP_SUPPCONF);
 537  590  
 538  591          return (SNMPERR_SUCCESS);
 539  592  }
 540  593  
 541  594  int
 542  595  main(int argc, char *argv[])
 543  596  {
 544  597          struct rlimit rlim;
 545  598          struct sigaction act;
 546  599          sigset_t set;
 547  600          char c;
 548  601          boolean_t run_fg = B_FALSE;
 549  602  
 550  603          if ((nhdl = malloc(sizeof (nd_hdl_t))) == NULL) {
 551  604                  (void) fprintf(stderr, "Failed to allocate space for notifyd "
 552  605                      "handle (%s)", strerror(errno));
 553  606                  return (1);
 554  607          }
 555  608          bzero(nhdl, sizeof (nd_hdl_t));
 556  609          nhdl->nh_keep_running = B_TRUE;
 557  610          nhdl->nh_log_fd = stderr;
 558  611          nhdl->nh_pname = argv[0];
 559  612  
 560  613          get_svc_config();
 561  614  
 562  615          /*
 563  616           * In the case where we get started outside of SMF, args passed on the
 564  617           * command line override SMF property setting
 565  618           */
 566  619          while (optind < argc) {
 567  620                  while ((c = getopt(argc, argv, optstr)) != -1) {
 568  621                          switch (c) {
 569  622                          case 'd':
 570  623                                  nhdl->nh_debug = B_TRUE;
 571  624                                  break;
 572  625                          case 'f':
 573  626                                  run_fg = B_TRUE;
 574  627                                  break;
 575  628                          case 'R':
 576  629                                  nhdl->nh_rootdir = strdup(optarg);
 577  630                                  break;
 578  631                          default:
 579  632                                  free(nhdl);
 580  633                                  return (usage(nhdl->nh_pname));
 581  634                          }
 582  635                  }
 583  636          }
 584  637  
 585  638          /*
 586  639           * Set up a signal handler for SIGTERM (and SIGINT if we'll
 587  640           * be running in the foreground) to ensure sure we get a chance to exit
 588  641           * in an orderly fashion.  We also catch SIGHUP, which will be sent to
 589  642           * us by SMF if the service is refreshed.
 590  643           */
 591  644          (void) sigfillset(&set);
 592  645          (void) sigfillset(&act.sa_mask);
 593  646          act.sa_handler = nd_sighandler;
 594  647          act.sa_flags = 0;
 595  648  
 596  649          (void) sigaction(SIGTERM, &act, NULL);
 597  650          (void) sigdelset(&set, SIGTERM);
 598  651          (void) sigaction(SIGHUP, &act, NULL);
 599  652          (void) sigdelset(&set, SIGHUP);
 600  653  
 601  654          if (run_fg) {
 602  655                  (void) sigaction(SIGINT, &act, NULL);
 603  656                  (void) sigdelset(&set, SIGINT);
 604  657          } else
 605  658                  nd_daemonize(nhdl);
 606  659  
 607  660          rlim.rlim_cur = RLIM_INFINITY;
 608  661          rlim.rlim_max = RLIM_INFINITY;
 609  662          (void) setrlimit(RLIMIT_CORE, &rlim);
 610  663  
 611  664          /*
 612  665           * We need to be root initialize our libfmevent handle (because that
 613  666           * involves reading/writing to /dev/sysevent), so we do this before
 614  667           * calling __init_daemon_priv.
 615  668           */
 616  669          nhdl->nh_evhdl = fmev_shdl_init(LIBFMEVENT_VERSION_2, NULL, NULL, NULL);
 617  670          if (nhdl->nh_evhdl == NULL) {
 618  671                  (void) sleep(5);
 619  672                  nd_abort(nhdl, "failed to initialize libfmevent: %s",
 620  673                      fmev_strerror(fmev_errno));
 621  674          }
 622  675  
 623  676          /*
 624  677           * If we're in the global zone, reset all of our privilege sets to
 625  678           * the minimum set of required privileges.   We also change our
 626  679           * uid/gid to noaccess/noaccess
 627  680           *
 628  681           * __init_daemon_priv will also set the process core path for us
 629  682           *
 630  683           */
 631  684          if (getzoneid() == GLOBAL_ZONEID)
 632  685                  if (__init_daemon_priv(
 633  686                      PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS,
 634  687                      60002, 60002, PRIV_FILE_DAC_READ, NULL) != 0)
 635  688                          nd_abort(nhdl, "additional privileges required to run");
 636  689  
 637  690          nhdl->nh_msghdl = fmd_msg_init(nhdl->nh_rootdir, FMD_MSG_VERSION);
 638  691          if (nhdl->nh_msghdl == NULL)
 639  692                  nd_abort(nhdl, "failed to initialize libfmd_msg");
 640  693  
 641  694          if (init_sma() != SNMPERR_SUCCESS)
 642  695                  nd_abort(nhdl, "SNMP initialization failed");
 643  696  
 644  697          (void) gethostname(hostname, MAXHOSTNAMELEN + 1);
 645  698          /*
 646  699           * Set up our event subscriptions.  We subscribe to everything and then
 647  700           * consult libscf when we receive an event to determine what (if any)
 648  701           * notification to send.
 649  702           */
 650  703          nd_debug(nhdl, "Subscribing to ireport.os.smf.* events");
 651  704          if (fmev_shdl_subscribe(nhdl->nh_evhdl, "ireport.os.smf.*",
 652  705              ireport_cb, NULL) != FMEV_SUCCESS) {
 653  706                  nd_abort(nhdl, "fmev_shdl_subscribe failed: %s",
 654  707                      fmev_strerror(fmev_errno));
 655  708          }
 656  709  
 657  710          nd_debug(nhdl, "Subscribing to list.* events");
 658  711          if (fmev_shdl_subscribe(nhdl->nh_evhdl, "list.*", list_cb,
 659  712              NULL) != FMEV_SUCCESS) {
 660  713                  nd_abort(nhdl, "fmev_shdl_subscribe failed: %s",
 661  714                      fmev_strerror(fmev_errno));
 662  715          }
 663  716  
 664  717          /*
 665  718           * We run until someone kills us
 666  719           */
 667  720          while (nhdl->nh_keep_running)
 668  721                  (void) sigsuspend(&set);
 669  722  
 670  723          /*
 671  724           * snmp_shutdown, which we would normally use here, calls free_slots,
 672  725           * a callback that is supposed to tear down the pkcs11 state; however,
 673  726           * it abuses C_Finalize, causing fmd to drop core on shutdown.  Avoid
 674  727           * this by shutting down the library piecemeal.
 675  728           */
 676  729          snmp_store(SNMP_SUPPCONF);
 677  730          snmp_alarm_unregister_all();
 678  731          (void) snmp_close_sessions();
 679  732          shutdown_mib();
 680  733          unregister_all_config_handlers();
 681  734          netsnmp_ds_shutdown();
 682  735  
 683  736          free(nhdl->nh_rootdir);
 684  737          free(nhdl);
 685  738  
 686  739          return (0);
 687  740  }
  
    | 
      ↓ open down ↓ | 
    187 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX