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