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