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