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>


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 




  26 #include <sys/fm/protocol.h>

  27 #include <fm/fmd_snmp.h>
  28 #include <fm/fmd_msg.h>
  29 #include <fm/libfmevent.h>

  30 #include <net-snmp/net-snmp-config.h>
  31 #include <net-snmp/net-snmp-includes.h>
  32 #include <net-snmp/agent/net-snmp-agent-includes.h>


  33 #include <errno.h>

  34 #include <locale.h>
  35 #include <netdb.h>

  36 #include <signal.h>
  37 #include <strings.h>
  38 #include <stdlib.h>

  39 #include <unistd.h>
  40 #include <limits.h>
  41 #include <alloca.h>
  42 #include <priv_utils.h>
  43 #include <zone.h>

  44 #include "libfmnotify.h"
  45 
  46 /*
  47  * Debug messages can be enabled by setting the debug property to true
  48  *
  49  * # svccfg -s svc:/system/fm/snmp-notify setprop config/debug=true
  50  */
  51 #define SVCNAME         "system/fm/snmp-notify"
  52 
  53 typedef struct ireport_trap {

  54         char *host;
  55         char *msgid;

  56         char *desc;
  57         long long tstamp;
  58         char *fmri;
  59         uint32_t from_state;
  60         uint32_t to_state;
  61         char *reason;
  62         boolean_t is_stn_event;
  63 } ireport_trap_t;
  64 











  65 static nd_hdl_t *nhdl;
  66 static const char optstr[] = "dfR:";
  67 static const char SNMP_SUPPCONF[] = "fmd-trapgen";
  68 static char hostname[MAXHOSTNAMELEN + 1];
  69 
  70 static int
  71 usage(const char *pname)
  72 {
  73         (void) fprintf(stderr, "Usage: %s [-df] [-R <altroot>]\n", pname);
  74 
  75         (void) fprintf(stderr,
  76             "\t-d  enable debug mode\n"
  77             "\t-f  stay in foreground\n"
  78             "\t-R  specify alternate root\n");
  79 
  80         return (1);
  81 }
  82 
  83 /*
  84  * If someone does an "svcadm refresh" on us, then this function gets called,


 148                 } else if (!a1[0]) {
 149                         nd_debug(nhdl, "SNMP notification is disabled");
 150                         return (-1);
 151                 }
 152         }
 153         return (0);
 154 }
 155 
 156 static void
 157 send_ireport_trap(ireport_trap_t *t)
 158 {
 159         static const oid sunIreportTrap_oid[] =
 160             { SUNIREPORTTRAP_OID };
 161         const size_t sunIreportTrap_len =
 162             OID_LENGTH(sunIreportTrap_oid);
 163 
 164         static const oid sunIreportHostname_oid[] =
 165             { SUNIREPORTHOSTNAME_OID };
 166         static const oid sunIreportMsgid_oid[] =
 167             { SUNIREPORTMSGID_OID };


 168         static const oid sunIreportDescription_oid[] =
 169             { SUNIREPORTDESCRIPTION_OID };
 170         static const oid sunIreportTime_oid[] =
 171             { SUNIREPORTTIME_OID };
 172 
 173         static const oid sunIreportSmfFmri_oid[] =
 174             { SUNIREPORTSMFFMRI_OID };
 175         static const oid sunIreportSmfFromState_oid[] =
 176             { SUNIREPORTSMFFROMSTATE_OID };
 177         static const oid sunIreportSmfToState_oid[] =
 178             { SUNIREPORTSMFTOSTATE_OID };
 179         static const oid sunIreportSmfTransitionReason_oid[] =
 180             { SUNIREPORTTRANSITIONREASON_OID };
 181         const size_t
 182             sunIreport_base_len = OID_LENGTH(sunIreportHostname_oid);
 183 

 184         size_t var_len = sunIreport_base_len + 1;
 185         oid var_name[MAX_OID_LEN];
 186 
 187         netsnmp_variable_list *notification_vars = NULL;
 188 
 189         size_t dt_len;
 190         uchar_t dt[11], *tdt;
 191         time_t ts = t->tstamp;
 192 
 193         tdt = date_n_time(&ts, &dt_len);
 194         /*
 195          * We know date_n_time is broken, it returns a buffer from
 196          * its stack. So we copy before we step over it!
 197          */
 198         for (int i = 0; i < dt_len; ++i)
 199                 dt[i] = tdt[i];
 200 
 201         if (var_len > MAX_OID_LEN) {
 202                 nd_error(nhdl, "var_len %d > MAX_OID_LEN %d\n", var_len,
 203                     MAX_OID_LEN);
 204                 return;
 205         }
 206 
 207         (void) memcpy(var_name, sunIreportHostname_oid, sunIreport_base_len *
 208             sizeof (oid));
 209         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 210             sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->host,
 211             strlen(t->host));
 212 
 213         (void) memcpy(var_name, sunIreportMsgid_oid,
 214             sunIreport_base_len * sizeof (oid));
 215         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 216             sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->msgid,
 217             strlen(t->msgid));
 218 
 219         (void) memcpy(var_name, sunIreportDescription_oid,
 220             sunIreport_base_len * sizeof (oid));
 221         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 222             sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->desc,
 223             strlen(t->desc));
 224 
 225         (void) memcpy(var_name, sunIreportTime_oid, sunIreport_base_len *
 226             sizeof (oid));
 227         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 228             sunIreport_base_len + 1, ASN_OCTET_STR, dt, dt_len);
 229 




 230         if (t->is_stn_event) {
 231                 (void) memcpy(var_name, sunIreportSmfFmri_oid,
 232                     sunIreport_base_len * sizeof (oid));
 233                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
 234                     sunIreport_base_len + 1, ASN_OCTET_STR, (uchar_t *)t->fmri,
 235                     strlen(t->fmri));
 236 
 237                 (void) memcpy(var_name, sunIreportSmfFromState_oid,
 238                     sunIreport_base_len * sizeof (oid));
 239                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
 240                     sunIreport_base_len + 1, ASN_INTEGER,
 241                     (uchar_t *)&t->from_state, sizeof (uint32_t));
 242 
 243                 (void) memcpy(var_name, sunIreportSmfToState_oid,
 244                     sunIreport_base_len * sizeof (oid));
 245                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
 246                     sunIreport_base_len + 1, ASN_INTEGER,
 247                     (uchar_t *)&t->to_state, sizeof (uint32_t));
 248 
 249                 (void) memcpy(var_name, sunIreportSmfTransitionReason_oid,
 250                     sunIreport_base_len * sizeof (oid));
 251                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
 252                     sunIreport_base_len + 1, ASN_OCTET_STR,
 253                     (uchar_t *)t->reason, strlen(t->reason));
 254         }
 255 
 256         /*
 257          * This function is capable of sending both v1 and v2/v3 traps.
 258          * Which is sent to a specific destination is determined by the
 259          * configuration file(s).
 260          */
 261         send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC,
 262             sunIreportTrap_oid[sunIreportTrap_len - 1],
 263             (oid *)sunIreportTrap_oid, sunIreportTrap_len - 2,
 264             notification_vars);
 265         nd_debug(nhdl, "Sent SNMP trap for %s", t->msgid);
 266 
 267         snmp_free_varbind(notification_vars);
 268 
 269 }
 270 
 271 /*ARGSUSED*/
 272 static void
 273 send_fm_trap(const char *uuid, const char *code, const char *url)
 274 {
 275         static const oid sunFmProblemTrap_oid[] = { SUNFMPROBLEMTRAP_OID };
 276         const size_t sunFmProblemTrap_len = OID_LENGTH(sunFmProblemTrap_oid);
 277 
 278         static const oid sunFmProblemUUID_oid[] =
 279             { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_UUID };


 280         static const oid sunFmProblemCode_oid[] =
 281             { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_CODE };




 282         static const oid sunFmProblemURL_oid[] =
 283             { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_URL };




 284 
 285         const size_t sunFmProblem_base_len = OID_LENGTH(sunFmProblemUUID_oid);
 286 
 287         size_t uuid_len = strlen(uuid);

 288         size_t var_len = sunFmProblem_base_len + 1 + uuid_len;
 289         oid var_name[MAX_OID_LEN];
 290 
 291         netsnmp_variable_list *notification_vars = NULL;
 292 
 293         /*
 294          * The format of our trap varbinds' oids is as follows:
 295          *
 296          * +-----------------------+---+--------+----------+------+
 297          * | SUNFMPROBLEMTABLE_OID | 1 | column | uuid_len | uuid |
 298          * +-----------------------+---+--------+----------+------+
 299          *                                       \---- index ----/
 300          *
 301          * A common mistake here is to send the trap with varbinds that
 302          * do not contain the index.  All the indices are the same, and
 303          * all the oids are the same length, so the only thing we need to
 304          * do for each varbind is set the table and column parts of the
 305          * variable name.
 306          */
 307 
 308         if (var_len > MAX_OID_LEN)
 309                 return;
 310 
 311         var_name[sunFmProblem_base_len] = (oid)uuid_len;
 312         for (int i = 0; i < uuid_len; i++)
 313                 var_name[i + sunFmProblem_base_len + 1] = (oid)uuid[i];
 314 
 315         /*
 316          * Ordinarily, we would need to add the OID of the trap itself
 317          * to the head of the variable list; this is required by SNMP v2.
 318          * However, send_enterprise_trap_vars does this for us as a part
 319          * of converting between v1 and v2 traps, so we skip directly to
 320          * the objects we're sending.
 321          */
 322 
 323         (void) memcpy(var_name, sunFmProblemUUID_oid,
 324             sunFmProblem_base_len * sizeof (oid));
 325         (void) snmp_varlist_add_variable(&notification_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));
 329         (void) snmp_varlist_add_variable(&notification_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));
 333         (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
 334             ASN_OCTET_STR, (uchar_t *)url, strlen(url));
 335 























 336         /*
 337          * This function is capable of sending both v1 and v2/v3 traps.
 338          * Which is sent to a specific destination is determined by the
 339          * configuration file(s).
 340          */
 341         send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC,
 342             sunFmProblemTrap_oid[sunFmProblemTrap_len - 1],
 343             (oid *)sunFmProblemTrap_oid, sunFmProblemTrap_len - 2,
 344             notification_vars);
 345         nd_debug(nhdl, "Sent SNMP trap for %s", code);
 346 
 347         snmp_free_varbind(notification_vars);
 348 }
 349 
 350 /*
 351  * The SUN-IREPORT-MIB declares the following enum to represent SMF service
 352  * states.
 353  *
 354  * offline(0), online(1), degraded(2), disabled(3), maintenance(4),
 355  * uninitialized(5)
 356  *
 357  * This function converts a string representation of an SMF service state
 358  * to it's corresponding enum val.
 359  */
 360 static int
 361 state_to_val(char *statestr, uint32_t *stateval)
 362 {
 363         if (strcmp(statestr, "offline") == 0)
 364                 *stateval = 0;
 365         else if (strcmp(statestr, "online") == 0)
 366                 *stateval = 1;
 367         else if (strcmp(statestr, "degraded") == 0)
 368                 *stateval = 2;
 369         else if (strcmp(statestr, "disabled") == 0)
 370                 *stateval = 3;
 371         else if (strcmp(statestr, "maintenance") == 0)
 372                 *stateval = 4;
 373         else if (strcmp(statestr, "uninitialized") == 0)
 374                 *stateval = 5;
 375         else
 376                 return (-1);
 377         return (0);
 378 }


 393         if (ret == SCF_ERROR_NOT_FOUND) {
 394                 /*
 395                  * No snmp notification preferences specified for this type of
 396                  * event, so we're done
 397                  */
 398                 return;
 399         } else if (ret != 0) {
 400                 nd_error(nhdl, "Failed to retrieve notification preferences "
 401                     "for this event");
 402                 return;
 403         }
 404 
 405         if (get_snmp_prefs(nhdl, pref_nvl, npref) != 0)
 406                 goto irpt_done;
 407 
 408         if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
 409                 goto irpt_done;
 410 
 411         swtrap.host = hostname;
 412         swtrap.msgid = ev_info->ei_diagcode;

 413         swtrap.desc = ev_info->ei_descr;
 414         swtrap.tstamp = (time_t)fmev_time_sec(ev);
 415 
 416         if (strncmp(class, "ireport.os.smf", 14) == 0) {
 417                 swtrap.fmri = ev_info->ei_fmri;
 418                 if (state_to_val(ev_info->ei_from_state, &swtrap.from_state)
 419                     < 0 ||
 420                     state_to_val(ev_info->ei_to_state, &swtrap.to_state) < 0) {
 421                         nd_error(nhdl, "Malformed event - invalid svc state");
 422                         nd_dump_nvlist(nhdl, ev_info->ei_payload);
 423                         goto irpt_done;
 424                 }
 425                 swtrap.reason = ev_info->ei_reason;
 426                 swtrap.is_stn_event = B_TRUE;
 427         }
 428         send_ireport_trap(&swtrap);
 429 irpt_done:
 430         if (ev_info)
 431                 nd_free_event_info(ev_info);
 432         nd_free_nvlarray(pref_nvl, npref);
 433 }
 434 
 435 /*ARGSUSED*/
 436 static void
 437 list_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
 438 {
 439         char *uuid;
 440         uint8_t version;
 441         nd_ev_info_t *ev_info = NULL;
 442         nvlist_t **pref_nvl = NULL;

 443         uint_t npref;
 444         int ret;
 445         boolean_t domsg;
 446 
 447         nd_debug(nhdl, "Received event of class %s", class);
 448 
 449         ret = nd_get_notify_prefs(nhdl, "snmp", ev, &pref_nvl, &npref);
 450         if (ret == SCF_ERROR_NOT_FOUND) {
 451                 /*
 452                  * No snmp notification preferences specified for this type of
 453                  * event, so we're done
 454                  */
 455                 return;
 456         } else if (ret != 0) {
 457                 nd_error(nhdl, "Failed to retrieve notification preferences "
 458                     "for this event");
 459                 return;
 460         }
 461 
 462         if (get_snmp_prefs(nhdl, pref_nvl, npref) != 0)
 463                 goto listcb_done;
 464 
 465         if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
 466                 goto listcb_done;
 467 
 468         /*
 469          * If the message payload member is set to 0, then it's an event we
 470          * typically suppress messaging on, so we won't send a trap for it.
 471          */
 472         if (nvlist_lookup_boolean_value(ev_info->ei_payload, FM_SUSPECT_MESSAGE,
 473             &domsg) == 0 && !domsg) {
 474                 nd_debug(nhdl, "Messaging suppressed for this event");
 475                 goto listcb_done;
 476         }
 477 
 478         if (nvlist_lookup_uint8(ev_info->ei_payload, FM_VERSION, &version)
 479             != 0 || version > FM_SUSPECT_VERSION) {
 480                 nd_error(nhdl, "invalid event version: %u", version);
 481                 goto listcb_done;
 482         }
 483 
 484         (void) nvlist_lookup_string(ev_info->ei_payload, FM_SUSPECT_UUID,
 485             &uuid);






 486 
 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);
 491 listcb_done:
 492         nd_free_nvlarray(pref_nvl, npref);
 493         if (ev_info)
 494                 nd_free_event_info(ev_info);
 495 }
 496 
 497 static int
 498 init_sma(void)
 499 {
 500         int err;
 501 
 502         /*
 503          * The only place we could possibly log is syslog, but the
 504          * full agent doesn't normally log there.  It would be confusing
 505          * if this agent did so; therefore we disable logging entirely.
 506          */
 507         snmp_disable_log();
 508 
 509         /*
 510          * Net-SNMP has a provision for reading an arbitrary number of




   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2018 Nexenta Systems, Inc.
  28  */
  29 
  30 #include <sys/fm/protocol.h>
  31 
  32 #include <fm/fmd_snmp.h>
  33 #include <fm/fmd_msg.h>
  34 #include <fm/libfmevent.h>
  35 
  36 #include <net-snmp/net-snmp-config.h>
  37 #include <net-snmp/net-snmp-includes.h>
  38 #include <net-snmp/agent/net-snmp-agent-includes.h>
  39 
  40 #include <alloca.h>
  41 #include <errno.h>
  42 #include <limits.h>
  43 #include <locale.h>
  44 #include <netdb.h>
  45 #include <priv_utils.h>
  46 #include <signal.h>

  47 #include <stdlib.h>
  48 #include <strings.h>
  49 #include <unistd.h>



  50 #include <zone.h>
  51 
  52 #include "libfmnotify.h"
  53 
  54 /*
  55  * Debug messages can be enabled by setting the debug property to true
  56  *
  57  * # svccfg -s svc:/system/fm/snmp-notify setprop config/debug=true
  58  */
  59 #define SVCNAME         "system/fm/snmp-notify"
  60 
  61 typedef struct ireport_trap {
  62         long long tstamp;
  63         char *host;
  64         char *msgid;
  65         char *severity;
  66         char *desc;

  67         char *fmri;
  68         uint32_t from_state;
  69         uint32_t to_state;
  70         char *reason;
  71         boolean_t is_stn_event;
  72 } ireport_trap_t;
  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 
  85 static nd_hdl_t *nhdl;
  86 static const char optstr[] = "dfR:";
  87 static const char SNMP_SUPPCONF[] = "fmd-trapgen";
  88 static char hostname[MAXHOSTNAMELEN + 1];
  89 
  90 static int
  91 usage(const char *pname)
  92 {
  93         (void) fprintf(stderr, "Usage: %s [-df] [-R <altroot>]\n", pname);
  94 
  95         (void) fprintf(stderr,
  96             "\t-d  enable debug mode\n"
  97             "\t-f  stay in foreground\n"
  98             "\t-R  specify alternate root\n");
  99 
 100         return (1);
 101 }
 102 
 103 /*
 104  * If someone does an "svcadm refresh" on us, then this function gets called,


 168                 } else if (!a1[0]) {
 169                         nd_debug(nhdl, "SNMP notification is disabled");
 170                         return (-1);
 171                 }
 172         }
 173         return (0);
 174 }
 175 
 176 static void
 177 send_ireport_trap(ireport_trap_t *t)
 178 {
 179         static const oid sunIreportTrap_oid[] =
 180             { SUNIREPORTTRAP_OID };
 181         const size_t sunIreportTrap_len =
 182             OID_LENGTH(sunIreportTrap_oid);
 183 
 184         static const oid sunIreportHostname_oid[] =
 185             { SUNIREPORTHOSTNAME_OID };
 186         static const oid sunIreportMsgid_oid[] =
 187             { SUNIREPORTMSGID_OID };
 188         static const oid sunIreportSeverity_oid[] =
 189             { SUNIREPORTSEVERITY_OID };
 190         static const oid sunIreportDescription_oid[] =
 191             { SUNIREPORTDESCRIPTION_OID };
 192         static const oid sunIreportTime_oid[] =
 193             { SUNIREPORTTIME_OID };
 194 
 195         static const oid sunIreportSmfFmri_oid[] =
 196             { SUNIREPORTSMFFMRI_OID };
 197         static const oid sunIreportSmfFromState_oid[] =
 198             { SUNIREPORTSMFFROMSTATE_OID };
 199         static const oid sunIreportSmfToState_oid[] =
 200             { SUNIREPORTSMFTOSTATE_OID };
 201         static const oid sunIreportSmfTransitionReason_oid[] =
 202             { SUNIREPORTTRANSITIONREASON_OID };
 203         const size_t
 204             sunIreport_base_len = OID_LENGTH(sunIreportHostname_oid);
 205 
 206         size_t oid_len = sunIreport_base_len * sizeof (oid);
 207         size_t var_len = sunIreport_base_len + 1;
 208         oid var_name[MAX_OID_LEN] = { 0 };
 209 
 210         netsnmp_variable_list *notification_vars = NULL;
 211 
 212         size_t dt_len;
 213         uchar_t dt[11], *tdt;
 214         time_t ts = t->tstamp;
 215 
 216         tdt = date_n_time(&ts, &dt_len);
 217         /*
 218          * We know date_n_time is broken, it returns a buffer from
 219          * its stack. So we copy before we step over it!
 220          */
 221         for (int i = 0; i < dt_len; ++i)
 222                 dt[i] = tdt[i];
 223 
 224         if (var_len > MAX_OID_LEN) {
 225                 nd_error(nhdl, "var_len %d > MAX_OID_LEN %d\n", var_len,
 226                     MAX_OID_LEN);
 227                 return;
 228         }
 229 
 230         (void) memcpy(var_name, sunIreportHostname_oid, oid_len);

 231         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 232             var_len, ASN_OCTET_STR, (uchar_t *)t->host, strlen(t->host));

 233 
 234         (void) memcpy(var_name, sunIreportMsgid_oid, oid_len);

 235         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 236             var_len, ASN_OCTET_STR, (uchar_t *)t->msgid, strlen(t->msgid));

 237 
 238         (void) memcpy(var_name, sunIreportSeverity_oid, oid_len);

 239         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 240             var_len, ASN_OCTET_STR, (uchar_t *)t->severity,
 241             strlen(t->severity));
 242 
 243         (void) memcpy(var_name, sunIreportDescription_oid, oid_len);

 244         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 245             var_len, ASN_OCTET_STR, (uchar_t *)t->desc, strlen(t->desc));
 246 
 247         (void) memcpy(var_name, sunIreportTime_oid, oid_len);
 248         (void) snmp_varlist_add_variable(&notification_vars, var_name,
 249             var_len, ASN_OCTET_STR, dt, dt_len);
 250 
 251         if (t->is_stn_event) {
 252                 (void) memcpy(var_name, sunIreportSmfFmri_oid, oid_len);

 253                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
 254                     var_len, ASN_OCTET_STR, (uchar_t *)t->fmri,
 255                     strlen(t->fmri));
 256 
 257                 (void) memcpy(var_name, sunIreportSmfFromState_oid, oid_len);

 258                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
 259                     var_len, ASN_INTEGER, (uchar_t *)&t->from_state,
 260                     sizeof (uint32_t));
 261 
 262                 (void) memcpy(var_name, sunIreportSmfToState_oid, oid_len);

 263                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
 264                     var_len, ASN_INTEGER, (uchar_t *)&t->to_state,
 265                     sizeof (uint32_t));
 266 
 267                 (void) memcpy(var_name, sunIreportSmfTransitionReason_oid,
 268                     oid_len);
 269                 (void) snmp_varlist_add_variable(&notification_vars, var_name,
 270                     var_len, ASN_OCTET_STR, (uchar_t *)t->reason,
 271                     strlen(t->reason));
 272         }
 273 
 274         /*
 275          * This function is capable of sending both v1 and v2/v3 traps.
 276          * Which is sent to a specific destination is determined by the
 277          * configuration file(s).
 278          */
 279         send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC,
 280             sunIreportTrap_oid[sunIreportTrap_len - 1],
 281             (oid *)sunIreportTrap_oid, sunIreportTrap_len - 2,
 282             notification_vars);
 283         nd_debug(nhdl, "Sent SNMP trap for %s", t->msgid);
 284 
 285         snmp_free_varbind(notification_vars);

 286 }
 287 

 288 static void
 289 send_fm_trap(fmproblem_trap_t *t)
 290 {
 291         static const oid sunFmProblemTrap_oid[] = { SUNFMPROBLEMTRAP_OID };
 292         const size_t sunFmProblemTrap_len = OID_LENGTH(sunFmProblemTrap_oid);
 293 
 294         static const oid sunFmProblemUUID_oid[] =
 295             { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_UUID };
 296         static const oid sunFmProblemHostname_oid[] =
 297             { SUNFMPROBLEMTABLE_OID, 1, SUNFMPROBLEM_COL_HOSTNAME };
 298         static const oid sunFmProblemCode_oid[] =
 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 };
 304         static const oid sunFmProblemURL_oid[] =
 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 };
 310 
 311         const size_t sunFmProblem_base_len = OID_LENGTH(sunFmProblemUUID_oid);
 312 
 313         size_t oid_len = sunFmProblem_base_len * sizeof (oid);
 314         size_t uuid_len = strlen(t->uuid);
 315         size_t var_len = sunFmProblem_base_len + 1 + uuid_len;
 316         oid var_name[MAX_OID_LEN];
 317 
 318         netsnmp_variable_list *notification_vars = NULL;
 319 
 320         /*
 321          * The format of our trap varbinds' oids is as follows:
 322          *
 323          * +-----------------------+---+--------+----------+------+
 324          * | SUNFMPROBLEMTABLE_OID | 1 | column | uuid_len | uuid |
 325          * +-----------------------+---+--------+----------+------+
 326          *                                       \---- index ----/
 327          *
 328          * A common mistake here is to send the trap with varbinds that
 329          * do not contain the index.  All the indices are the same, and
 330          * all the oids are the same length, so the only thing we need to
 331          * do for each varbind is set the table and column parts of the
 332          * variable name.
 333          */
 334 
 335         if (var_len > MAX_OID_LEN)
 336                 return;
 337 
 338         var_name[sunFmProblem_base_len] = (oid)uuid_len;
 339         for (int i = 0; i < uuid_len; i++)
 340                 var_name[i + sunFmProblem_base_len + 1] = (oid)t->uuid[i];
 341 
 342         /*
 343          * Ordinarily, we would need to add the OID of the trap itself
 344          * to the head of the variable list; this is required by SNMP v2.
 345          * However, send_enterprise_trap_vars does this for us as a part
 346          * of converting between v1 and v2 traps, so we skip directly to
 347          * the objects we're sending.
 348          */
 349 
 350         (void) memcpy(var_name, sunFmProblemUUID_oid, oid_len);

 351         (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
 352             ASN_OCTET_STR, (uchar_t *)t->uuid, strlen(t->uuid));
 353 
 354         (void) memcpy(var_name, sunFmProblemHostname_oid, oid_len);
 355         (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
 356             ASN_OCTET_STR, (uchar_t *)t->host, strlen(t->host));
 357 
 358         (void) memcpy(var_name, sunFmProblemCode_oid, oid_len);
 359         (void) snmp_varlist_add_variable(&notification_vars, var_name, var_len,
 360             ASN_OCTET_STR, (uchar_t *)t->code, strlen(t->code));
 361 
 362         (void) memcpy(var_name, sunFmProblemType_oid, oid_len);
 363         (void) snmp_varlist_add_variable(&notification_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(&notification_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(&notification_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(&notification_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(&notification_vars, var_name,
 381                     var_len, ASN_OCTET_STR, (uchar_t *)t->fmri,
 382                     strlen(t->fmri));
 383         }
 384 
 385         /*
 386          * This function is capable of sending both v1 and v2/v3 traps.
 387          * Which is sent to a specific destination is determined by the
 388          * configuration file(s).
 389          */
 390         send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC,
 391             sunFmProblemTrap_oid[sunFmProblemTrap_len - 1],
 392             (oid *)sunFmProblemTrap_oid, sunFmProblemTrap_len - 2,
 393             notification_vars);
 394         nd_debug(nhdl, "Sent SNMP trap for %s", t->code);
 395 
 396         snmp_free_varbind(notification_vars);
 397 }
 398 
 399 /*
 400  * The SUN-IREPORT-MIB declares the following enum to represent SMF service
 401  * states.
 402  *
 403  * offline(0), online(1), degraded(2), disabled(3), maintenance(4),
 404  * uninitialized(5)
 405  *
 406  * This function converts a string representation of an SMF service state
 407  * to its corresponding enum val.
 408  */
 409 static int
 410 state_to_val(char *statestr, uint32_t *stateval)
 411 {
 412         if (strcmp(statestr, "offline") == 0)
 413                 *stateval = 0;
 414         else if (strcmp(statestr, "online") == 0)
 415                 *stateval = 1;
 416         else if (strcmp(statestr, "degraded") == 0)
 417                 *stateval = 2;
 418         else if (strcmp(statestr, "disabled") == 0)
 419                 *stateval = 3;
 420         else if (strcmp(statestr, "maintenance") == 0)
 421                 *stateval = 4;
 422         else if (strcmp(statestr, "uninitialized") == 0)
 423                 *stateval = 5;
 424         else
 425                 return (-1);
 426         return (0);
 427 }


 442         if (ret == SCF_ERROR_NOT_FOUND) {
 443                 /*
 444                  * No snmp notification preferences specified for this type of
 445                  * event, so we're done
 446                  */
 447                 return;
 448         } else if (ret != 0) {
 449                 nd_error(nhdl, "Failed to retrieve notification preferences "
 450                     "for this event");
 451                 return;
 452         }
 453 
 454         if (get_snmp_prefs(nhdl, pref_nvl, npref) != 0)
 455                 goto irpt_done;
 456 
 457         if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
 458                 goto irpt_done;
 459 
 460         swtrap.host = hostname;
 461         swtrap.msgid = ev_info->ei_diagcode;
 462         swtrap.severity = ev_info->ei_severity;
 463         swtrap.desc = ev_info->ei_descr;
 464         swtrap.tstamp = (time_t)fmev_time_sec(ev);
 465 
 466         if (strncmp(class, "ireport.os.smf", 14) == 0) {
 467                 swtrap.fmri = ev_info->ei_fmri;
 468                 if (state_to_val(ev_info->ei_from_state, &swtrap.from_state)
 469                     < 0 ||
 470                     state_to_val(ev_info->ei_to_state, &swtrap.to_state) < 0) {
 471                         nd_error(nhdl, "Malformed event - invalid svc state");
 472                         nd_dump_nvlist(nhdl, ev_info->ei_payload);
 473                         goto irpt_done;
 474                 }
 475                 swtrap.reason = ev_info->ei_reason;
 476                 swtrap.is_stn_event = B_TRUE;
 477         }
 478         send_ireport_trap(&swtrap);
 479 irpt_done:
 480         if (ev_info)
 481                 nd_free_event_info(ev_info);
 482         nd_free_nvlarray(pref_nvl, npref);
 483 }
 484 
 485 /*ARGSUSED*/
 486 static void
 487 list_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
 488 {

 489         uint8_t version;
 490         nd_ev_info_t *ev_info = NULL;
 491         nvlist_t **pref_nvl = NULL;
 492         fmproblem_trap_t fmtrap;
 493         uint_t npref;
 494         int ret;
 495         boolean_t domsg;
 496 
 497         nd_debug(nhdl, "Received event of class %s", class);
 498 
 499         ret = nd_get_notify_prefs(nhdl, "snmp", ev, &pref_nvl, &npref);
 500         if (ret == SCF_ERROR_NOT_FOUND) {
 501                 /*
 502                  * No snmp notification preferences specified for this type of
 503                  * event, so we're done
 504                  */
 505                 return;
 506         } else if (ret != 0) {
 507                 nd_error(nhdl, "Failed to retrieve notification preferences "
 508                     "for this event");
 509                 return;
 510         }
 511 
 512         if (get_snmp_prefs(nhdl, pref_nvl, npref) != 0)
 513                 goto listcb_done;
 514 
 515         if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
 516                 goto listcb_done;
 517 
 518         /*
 519          * If the message payload member is set to 0, then it's an event we
 520          * typically suppress messaging on, so we won't send a trap for it.
 521          */
 522         if (nvlist_lookup_boolean_value(ev_info->ei_payload, FM_SUSPECT_MESSAGE,
 523             &domsg) == 0 && !domsg) {
 524                 nd_debug(nhdl, "Messaging suppressed for this event");
 525                 goto listcb_done;
 526         }
 527 
 528         if (nvlist_lookup_uint8(ev_info->ei_payload, FM_VERSION,
 529             &version) != 0 || version > FM_SUSPECT_VERSION) {
 530                 nd_error(nhdl, "invalid event version: %u", version);
 531                 goto listcb_done;
 532         }
 533 
 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;
 542 
 543         send_fm_trap(&fmtrap);



 544 listcb_done:
 545         nd_free_nvlarray(pref_nvl, npref);
 546         if (ev_info)
 547                 nd_free_event_info(ev_info);
 548 }
 549 
 550 static int
 551 init_sma(void)
 552 {
 553         int err;
 554 
 555         /*
 556          * The only place we could possibly log is syslog, but the
 557          * full agent doesn't normally log there.  It would be confusing
 558          * if this agent did so; therefore we disable logging entirely.
 559          */
 560         snmp_disable_log();
 561 
 562         /*
 563          * Net-SNMP has a provision for reading an arbitrary number of