xref: /onnv-gate/usr/src/cmd/fm/notify/smtp-notify/common/smtp-notify.c (revision 12967:ab9ae749152f)
1*12967Sgavin.maltby@oracle.com /*
2*12967Sgavin.maltby@oracle.com  * CDDL HEADER START
3*12967Sgavin.maltby@oracle.com  *
4*12967Sgavin.maltby@oracle.com  * The contents of this file are subject to the terms of the
5*12967Sgavin.maltby@oracle.com  * Common Development and Distribution License (the "License").
6*12967Sgavin.maltby@oracle.com  * You may not use this file except in compliance with the License.
7*12967Sgavin.maltby@oracle.com  *
8*12967Sgavin.maltby@oracle.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12967Sgavin.maltby@oracle.com  * or http://www.opensolaris.org/os/licensing.
10*12967Sgavin.maltby@oracle.com  * See the License for the specific language governing permissions
11*12967Sgavin.maltby@oracle.com  * and limitations under the License.
12*12967Sgavin.maltby@oracle.com  *
13*12967Sgavin.maltby@oracle.com  * When distributing Covered Code, include this CDDL HEADER in each
14*12967Sgavin.maltby@oracle.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12967Sgavin.maltby@oracle.com  * If applicable, add the following below this CDDL HEADER, with the
16*12967Sgavin.maltby@oracle.com  * fields enclosed by brackets "[]" replaced with your own identifying
17*12967Sgavin.maltby@oracle.com  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12967Sgavin.maltby@oracle.com  *
19*12967Sgavin.maltby@oracle.com  * CDDL HEADER END
20*12967Sgavin.maltby@oracle.com  */
21*12967Sgavin.maltby@oracle.com 
22*12967Sgavin.maltby@oracle.com /*
23*12967Sgavin.maltby@oracle.com  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*12967Sgavin.maltby@oracle.com  */
25*12967Sgavin.maltby@oracle.com #include <stdio.h>
26*12967Sgavin.maltby@oracle.com #include <stdlib.h>
27*12967Sgavin.maltby@oracle.com #include <string.h>
28*12967Sgavin.maltby@oracle.com #include <alloca.h>
29*12967Sgavin.maltby@oracle.com #include <errno.h>
30*12967Sgavin.maltby@oracle.com #include <fcntl.h>
31*12967Sgavin.maltby@oracle.com #include <libscf.h>
32*12967Sgavin.maltby@oracle.com #include <priv_utils.h>
33*12967Sgavin.maltby@oracle.com #include <netdb.h>
34*12967Sgavin.maltby@oracle.com #include <signal.h>
35*12967Sgavin.maltby@oracle.com #include <strings.h>
36*12967Sgavin.maltby@oracle.com #include <time.h>
37*12967Sgavin.maltby@oracle.com #include <unistd.h>
38*12967Sgavin.maltby@oracle.com #include <zone.h>
39*12967Sgavin.maltby@oracle.com #include <sys/types.h>
40*12967Sgavin.maltby@oracle.com #include <sys/stat.h>
41*12967Sgavin.maltby@oracle.com #include <fm/fmd_msg.h>
42*12967Sgavin.maltby@oracle.com #include <fm/libfmevent.h>
43*12967Sgavin.maltby@oracle.com #include "libfmnotify.h"
44*12967Sgavin.maltby@oracle.com 
45*12967Sgavin.maltby@oracle.com #define	SENDMAIL	"/usr/sbin/sendmail"
46*12967Sgavin.maltby@oracle.com #define	SVCNAME		"system/fm/smtp-notify"
47*12967Sgavin.maltby@oracle.com 
48*12967Sgavin.maltby@oracle.com #define	XHDR_HOSTNAME		"X-FMEV-HOSTNAME"
49*12967Sgavin.maltby@oracle.com #define	XHDR_CLASS		"X-FMEV-CLASS"
50*12967Sgavin.maltby@oracle.com #define	XHDR_UUID		"X-FMEV-UUID"
51*12967Sgavin.maltby@oracle.com #define	XHDR_MSGID		"X-FMEV-CODE"
52*12967Sgavin.maltby@oracle.com #define	XHDR_SEVERITY		"X-FMEV-SEVERITY"
53*12967Sgavin.maltby@oracle.com #define	XHDR_FMRI		"X-FMEV-FMRI"
54*12967Sgavin.maltby@oracle.com #define	XHDR_FROM_STATE		"X-FMEV-FROM-STATE"
55*12967Sgavin.maltby@oracle.com #define	XHDR_TO_STATE		"X-FMEV-TO-STATE"
56*12967Sgavin.maltby@oracle.com 
57*12967Sgavin.maltby@oracle.com /*
58*12967Sgavin.maltby@oracle.com  * Debug messages can be enabled by setting the debug property to true
59*12967Sgavin.maltby@oracle.com  *
60*12967Sgavin.maltby@oracle.com  * # svccfg -s svc:/system/fm/smtp-notify setprop config/debug=true
61*12967Sgavin.maltby@oracle.com  *
62*12967Sgavin.maltby@oracle.com  * Debug messages will be spooled to the service log at:
63*12967Sgavin.maltby@oracle.com  * <root>/var/svc/log/system-fm-smtp-notify:default.log
64*12967Sgavin.maltby@oracle.com  */
65*12967Sgavin.maltby@oracle.com #define	PP_SCRIPT "usr/lib/fm/notify/process_msg_template.sh"
66*12967Sgavin.maltby@oracle.com 
67*12967Sgavin.maltby@oracle.com typedef struct email_pref
68*12967Sgavin.maltby@oracle.com {
69*12967Sgavin.maltby@oracle.com 	int ep_num_recips;
70*12967Sgavin.maltby@oracle.com 	char **ep_recips;
71*12967Sgavin.maltby@oracle.com 	char *ep_reply_to;
72*12967Sgavin.maltby@oracle.com 	char *ep_template_path;
73*12967Sgavin.maltby@oracle.com 	char *ep_template;
74*12967Sgavin.maltby@oracle.com } email_pref_t;
75*12967Sgavin.maltby@oracle.com 
76*12967Sgavin.maltby@oracle.com static nd_hdl_t *nhdl;
77*12967Sgavin.maltby@oracle.com static char hostname[MAXHOSTNAMELEN + 1];
78*12967Sgavin.maltby@oracle.com static const char optstr[] = "dfR:";
79*12967Sgavin.maltby@oracle.com static const char DEF_SUBJ_TEMPLATE[] = "smtp-notify-subject-template";
80*12967Sgavin.maltby@oracle.com static const char SMF_SUBJ_TEMPLATE[] = "smtp-notify-smf-subject-template";
81*12967Sgavin.maltby@oracle.com static const char FM_SUBJ_TEMPLATE[] = "smtp-notify-fm-subject-template";
82*12967Sgavin.maltby@oracle.com static const char IREPORT_MSG_TEMPLATE[] = "ireport-msg-template";
83*12967Sgavin.maltby@oracle.com static const char SMF_MSG_TEMPLATE[] = "ireport.os.smf-msg-template";
84*12967Sgavin.maltby@oracle.com 
85*12967Sgavin.maltby@oracle.com static int
usage(const char * pname)86*12967Sgavin.maltby@oracle.com usage(const char *pname)
87*12967Sgavin.maltby@oracle.com {
88*12967Sgavin.maltby@oracle.com 	(void) fprintf(stderr, "Usage: %s [-df] [-R <altroot>]\n", pname);
89*12967Sgavin.maltby@oracle.com 
90*12967Sgavin.maltby@oracle.com 	(void) fprintf(stderr,
91*12967Sgavin.maltby@oracle.com 	    "\t-d  enable debug mode\n"
92*12967Sgavin.maltby@oracle.com 	    "\t-f  stay in foreground\n"
93*12967Sgavin.maltby@oracle.com 	    "\t-R  specify alternate root\n");
94*12967Sgavin.maltby@oracle.com 
95*12967Sgavin.maltby@oracle.com 	return (1);
96*12967Sgavin.maltby@oracle.com }
97*12967Sgavin.maltby@oracle.com 
98*12967Sgavin.maltby@oracle.com /*
99*12967Sgavin.maltby@oracle.com  * This function simply reads the file specified by "template" into a buffer
100*12967Sgavin.maltby@oracle.com  * and returns a pointer to that buffer (or NULL on failure).  The caller is
101*12967Sgavin.maltby@oracle.com  * responsible for free'ing the returned buffer.
102*12967Sgavin.maltby@oracle.com  */
103*12967Sgavin.maltby@oracle.com static char *
read_template(const char * template)104*12967Sgavin.maltby@oracle.com read_template(const char *template)
105*12967Sgavin.maltby@oracle.com {
106*12967Sgavin.maltby@oracle.com 	int fd;
107*12967Sgavin.maltby@oracle.com 	struct stat statb;
108*12967Sgavin.maltby@oracle.com 	char *buf;
109*12967Sgavin.maltby@oracle.com 
110*12967Sgavin.maltby@oracle.com 	if (stat(template, &statb) != 0) {
111*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to stat %s (%s)", template,
112*12967Sgavin.maltby@oracle.com 		    strerror(errno));
113*12967Sgavin.maltby@oracle.com 		return (NULL);
114*12967Sgavin.maltby@oracle.com 	}
115*12967Sgavin.maltby@oracle.com 	if ((fd = open(template, O_RDONLY)) < 0) {
116*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to open %s (%s)", template,
117*12967Sgavin.maltby@oracle.com 		    strerror(errno));
118*12967Sgavin.maltby@oracle.com 		return (NULL);
119*12967Sgavin.maltby@oracle.com 	}
120*12967Sgavin.maltby@oracle.com 	if ((buf = malloc(statb.st_size + 1)) == NULL) {
121*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to allocate %d bytes", statb.st_size);
122*12967Sgavin.maltby@oracle.com 		(void) close(fd);
123*12967Sgavin.maltby@oracle.com 		return (NULL);
124*12967Sgavin.maltby@oracle.com 	}
125*12967Sgavin.maltby@oracle.com 	if (read(fd, buf, statb.st_size) < 0) {
126*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to read in template (%s)",
127*12967Sgavin.maltby@oracle.com 		    strerror(errno));
128*12967Sgavin.maltby@oracle.com 		free(buf);
129*12967Sgavin.maltby@oracle.com 		(void) close(fd);
130*12967Sgavin.maltby@oracle.com 		return (NULL);
131*12967Sgavin.maltby@oracle.com 	}
132*12967Sgavin.maltby@oracle.com 	buf[statb.st_size] = '\0';
133*12967Sgavin.maltby@oracle.com 	(void) close(fd);
134*12967Sgavin.maltby@oracle.com 	return (buf);
135*12967Sgavin.maltby@oracle.com }
136*12967Sgavin.maltby@oracle.com 
137*12967Sgavin.maltby@oracle.com /*
138*12967Sgavin.maltby@oracle.com  * This function runs a user-supplied message body template through a script
139*12967Sgavin.maltby@oracle.com  * which replaces the "committed" expansion macros with actual libfmd_msg
140*12967Sgavin.maltby@oracle.com  * expansion macros.
141*12967Sgavin.maltby@oracle.com  */
142*12967Sgavin.maltby@oracle.com static int
process_template(nd_ev_info_t * ev_info,email_pref_t * eprefs)143*12967Sgavin.maltby@oracle.com process_template(nd_ev_info_t *ev_info, email_pref_t *eprefs)
144*12967Sgavin.maltby@oracle.com {
145*12967Sgavin.maltby@oracle.com 	char pp_script[PATH_MAX], tmpfile[PATH_MAX], pp_cli[PATH_MAX];
146*12967Sgavin.maltby@oracle.com 	int ret = -1;
147*12967Sgavin.maltby@oracle.com 
148*12967Sgavin.maltby@oracle.com 	(void) snprintf(pp_script, sizeof (pp_script), "%s%s",
149*12967Sgavin.maltby@oracle.com 	    nhdl->nh_rootdir, PP_SCRIPT);
150*12967Sgavin.maltby@oracle.com 	(void) snprintf(tmpfile, sizeof (tmpfile), "%s%s",
151*12967Sgavin.maltby@oracle.com 	    nhdl->nh_rootdir, tmpnam(NULL));
152*12967Sgavin.maltby@oracle.com 
153*12967Sgavin.maltby@oracle.com 	/*
154*12967Sgavin.maltby@oracle.com 	 * If it's an SMF event, then the diagcode and severity won't be part
155*12967Sgavin.maltby@oracle.com 	 * of the event payload and so libfmd_msg won't be able to expand them.
156*12967Sgavin.maltby@oracle.com 	 * Therefore we pass the code and severity into the script and let the
157*12967Sgavin.maltby@oracle.com 	 * script do the expansion.
158*12967Sgavin.maltby@oracle.com 	 */
159*12967Sgavin.maltby@oracle.com 	/* LINTED: E_SEC_SPRINTF_UNBOUNDED_COPY */
160*12967Sgavin.maltby@oracle.com 	(void) sprintf(pp_cli, "%s %s %s %s %s", pp_script,
161*12967Sgavin.maltby@oracle.com 	    eprefs->ep_template_path, tmpfile, ev_info->ei_diagcode,
162*12967Sgavin.maltby@oracle.com 	    ev_info->ei_severity);
163*12967Sgavin.maltby@oracle.com 
164*12967Sgavin.maltby@oracle.com 	nd_debug(nhdl, "Executing %s", pp_cli);
165*12967Sgavin.maltby@oracle.com 	if (system(pp_cli) != -1)
166*12967Sgavin.maltby@oracle.com 		if ((eprefs->ep_template = read_template(tmpfile)) != NULL)
167*12967Sgavin.maltby@oracle.com 			ret = 0;
168*12967Sgavin.maltby@oracle.com 
169*12967Sgavin.maltby@oracle.com 	(void) unlink(tmpfile);
170*12967Sgavin.maltby@oracle.com 	return (ret);
171*12967Sgavin.maltby@oracle.com }
172*12967Sgavin.maltby@oracle.com 
173*12967Sgavin.maltby@oracle.com /*
174*12967Sgavin.maltby@oracle.com  * If someone does an "svcadm refresh" on us, then this function gets called,
175*12967Sgavin.maltby@oracle.com  * which rereads our service configuration.
176*12967Sgavin.maltby@oracle.com  */
177*12967Sgavin.maltby@oracle.com static void
get_svc_config()178*12967Sgavin.maltby@oracle.com get_svc_config()
179*12967Sgavin.maltby@oracle.com {
180*12967Sgavin.maltby@oracle.com 	int s = 0;
181*12967Sgavin.maltby@oracle.com 	uint8_t val;
182*12967Sgavin.maltby@oracle.com 
183*12967Sgavin.maltby@oracle.com 	s = nd_get_boolean_prop(nhdl, SVCNAME, "config", "debug", &val);
184*12967Sgavin.maltby@oracle.com 	nhdl->nh_debug = val;
185*12967Sgavin.maltby@oracle.com 
186*12967Sgavin.maltby@oracle.com 	s += nd_get_astring_prop(nhdl, SVCNAME, "config", "rootdir",
187*12967Sgavin.maltby@oracle.com 	    &(nhdl->nh_rootdir));
188*12967Sgavin.maltby@oracle.com 
189*12967Sgavin.maltby@oracle.com 	if (s != 0)
190*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to read retrieve service "
191*12967Sgavin.maltby@oracle.com 		    "properties\n");
192*12967Sgavin.maltby@oracle.com }
193*12967Sgavin.maltby@oracle.com 
194*12967Sgavin.maltby@oracle.com static void
nd_sighandler(int sig)195*12967Sgavin.maltby@oracle.com nd_sighandler(int sig)
196*12967Sgavin.maltby@oracle.com {
197*12967Sgavin.maltby@oracle.com 	if (sig == SIGHUP)
198*12967Sgavin.maltby@oracle.com 		get_svc_config();
199*12967Sgavin.maltby@oracle.com 	else
200*12967Sgavin.maltby@oracle.com 		nd_cleanup(nhdl);
201*12967Sgavin.maltby@oracle.com }
202*12967Sgavin.maltby@oracle.com 
203*12967Sgavin.maltby@oracle.com /*
204*12967Sgavin.maltby@oracle.com  * This function constructs all the email headers and puts them into the
205*12967Sgavin.maltby@oracle.com  * "headers" buffer handle.  The caller is responsible for free'ing this
206*12967Sgavin.maltby@oracle.com  * buffer.
207*12967Sgavin.maltby@oracle.com  */
208*12967Sgavin.maltby@oracle.com static int
build_headers(nd_hdl_t * nhdl,nd_ev_info_t * ev_info,email_pref_t * eprefs,char ** headers)209*12967Sgavin.maltby@oracle.com build_headers(nd_hdl_t *nhdl, nd_ev_info_t *ev_info, email_pref_t *eprefs,
210*12967Sgavin.maltby@oracle.com     char **headers)
211*12967Sgavin.maltby@oracle.com {
212*12967Sgavin.maltby@oracle.com 	const char *subj_key;
213*12967Sgavin.maltby@oracle.com 	char *subj_fmt, *subj = NULL;
214*12967Sgavin.maltby@oracle.com 	size_t len;
215*12967Sgavin.maltby@oracle.com 	boolean_t is_smf_event = B_FALSE, is_fm_event = B_FALSE;
216*12967Sgavin.maltby@oracle.com 
217*12967Sgavin.maltby@oracle.com 	/*
218*12967Sgavin.maltby@oracle.com 	 * Fetch and format the email subject.
219*12967Sgavin.maltby@oracle.com 	 */
220*12967Sgavin.maltby@oracle.com 	if (strncmp(ev_info->ei_class, "list.", 5) == 0) {
221*12967Sgavin.maltby@oracle.com 		is_fm_event = B_TRUE;
222*12967Sgavin.maltby@oracle.com 		subj_key = FM_SUBJ_TEMPLATE;
223*12967Sgavin.maltby@oracle.com 	} else if (strncmp(ev_info->ei_class, "ireport.os.smf", 14) == 0) {
224*12967Sgavin.maltby@oracle.com 		is_smf_event = B_TRUE;
225*12967Sgavin.maltby@oracle.com 		subj_key = SMF_SUBJ_TEMPLATE;
226*12967Sgavin.maltby@oracle.com 	} else {
227*12967Sgavin.maltby@oracle.com 		subj_key = DEF_SUBJ_TEMPLATE;
228*12967Sgavin.maltby@oracle.com 	}
229*12967Sgavin.maltby@oracle.com 
230*12967Sgavin.maltby@oracle.com 	if ((subj_fmt = fmd_msg_gettext_key(nhdl->nh_msghdl, NULL,
231*12967Sgavin.maltby@oracle.com 	    FMNOTIFY_MSG_DOMAIN, subj_key)) == NULL) {
232*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to contruct subject format");
233*12967Sgavin.maltby@oracle.com 		return (-1); /* libfmd_msg error */
234*12967Sgavin.maltby@oracle.com 	}
235*12967Sgavin.maltby@oracle.com 
236*12967Sgavin.maltby@oracle.com 	if (is_fm_event) {
237*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
238*12967Sgavin.maltby@oracle.com 		len = snprintf(NULL, 0, subj_fmt, hostname,
239*12967Sgavin.maltby@oracle.com 		    ev_info->ei_diagcode);
240*12967Sgavin.maltby@oracle.com 		subj = alloca(len + 1);
241*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
242*12967Sgavin.maltby@oracle.com 		(void) snprintf(subj, len + 1, subj_fmt, hostname,
243*12967Sgavin.maltby@oracle.com 		    ev_info->ei_diagcode);
244*12967Sgavin.maltby@oracle.com 	} else if (is_smf_event) {
245*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
246*12967Sgavin.maltby@oracle.com 		len = snprintf(NULL, 0, subj_fmt, hostname, ev_info->ei_fmri,
247*12967Sgavin.maltby@oracle.com 		    ev_info->ei_from_state, ev_info->ei_to_state);
248*12967Sgavin.maltby@oracle.com 		subj = alloca(len + 1);
249*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
250*12967Sgavin.maltby@oracle.com 		(void) snprintf(subj, len + 1, subj_fmt, hostname,
251*12967Sgavin.maltby@oracle.com 		    ev_info->ei_fmri, ev_info->ei_from_state,
252*12967Sgavin.maltby@oracle.com 		    ev_info->ei_to_state);
253*12967Sgavin.maltby@oracle.com 	} else {
254*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
255*12967Sgavin.maltby@oracle.com 		len = snprintf(NULL, 0, subj_fmt, hostname);
256*12967Sgavin.maltby@oracle.com 		subj = alloca(len + 1);
257*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
258*12967Sgavin.maltby@oracle.com 		(void) snprintf(subj, len + 1, subj_fmt, hostname);
259*12967Sgavin.maltby@oracle.com 	}
260*12967Sgavin.maltby@oracle.com 
261*12967Sgavin.maltby@oracle.com 	/*
262*12967Sgavin.maltby@oracle.com 	 * Here we add some X-headers to our mail message for use by mail
263*12967Sgavin.maltby@oracle.com 	 * filtering agents.  We add headers for the following bits of event
264*12967Sgavin.maltby@oracle.com 	 * data for all events
265*12967Sgavin.maltby@oracle.com 	 *
266*12967Sgavin.maltby@oracle.com 	 * hostname
267*12967Sgavin.maltby@oracle.com 	 * msg id (diagcode)
268*12967Sgavin.maltby@oracle.com 	 * event class
269*12967Sgavin.maltby@oracle.com 	 * event severity
270*12967Sgavin.maltby@oracle.com 	 * event uuid
271*12967Sgavin.maltby@oracle.com 	 *
272*12967Sgavin.maltby@oracle.com 	 * For SMF transition events, we'll have the following add'l X-headers
273*12967Sgavin.maltby@oracle.com 	 *
274*12967Sgavin.maltby@oracle.com 	 * from-state
275*12967Sgavin.maltby@oracle.com 	 * to-state
276*12967Sgavin.maltby@oracle.com 	 * service fmri
277*12967Sgavin.maltby@oracle.com 	 *
278*12967Sgavin.maltby@oracle.com 	 * We follow the X-headers with standard Reply-To and Subject headers.
279*12967Sgavin.maltby@oracle.com 	 */
280*12967Sgavin.maltby@oracle.com 	if (is_fm_event) {
281*12967Sgavin.maltby@oracle.com 		len = snprintf(NULL, 0, "%s: %s\n%s: %s\n%s: %s\n%s: %s\n"
282*12967Sgavin.maltby@oracle.com 		    "%s: %s\nReply-To: %s\nSubject: %s\n\n", XHDR_HOSTNAME,
283*12967Sgavin.maltby@oracle.com 		    hostname, XHDR_CLASS, ev_info->ei_class, XHDR_UUID,
284*12967Sgavin.maltby@oracle.com 		    ev_info->ei_uuid, XHDR_MSGID, ev_info->ei_diagcode,
285*12967Sgavin.maltby@oracle.com 		    XHDR_SEVERITY, ev_info->ei_severity, eprefs->ep_reply_to,
286*12967Sgavin.maltby@oracle.com 		    subj);
287*12967Sgavin.maltby@oracle.com 
288*12967Sgavin.maltby@oracle.com 		*headers = calloc(len + 1, sizeof (char));
289*12967Sgavin.maltby@oracle.com 
290*12967Sgavin.maltby@oracle.com 		(void) snprintf(*headers, len + 1, "%s: %s\n%s: %s\n%s: %s\n"
291*12967Sgavin.maltby@oracle.com 		    "%s: %s\n%s: %s\nReply-To: %s\nSubject: %s\n\n",
292*12967Sgavin.maltby@oracle.com 		    XHDR_HOSTNAME, hostname, XHDR_CLASS, ev_info->ei_class,
293*12967Sgavin.maltby@oracle.com 		    XHDR_UUID, ev_info->ei_uuid, XHDR_MSGID,
294*12967Sgavin.maltby@oracle.com 		    ev_info->ei_diagcode, XHDR_SEVERITY, ev_info->ei_severity,
295*12967Sgavin.maltby@oracle.com 		    eprefs->ep_reply_to, subj);
296*12967Sgavin.maltby@oracle.com 	} else if (is_smf_event) {
297*12967Sgavin.maltby@oracle.com 		len = snprintf(NULL, 0, "%s: %s\n%s: %s\n%s: %s\n%s: %s\n"
298*12967Sgavin.maltby@oracle.com 		    "%s: %s\n%s: %s\n%s: %s\nReply-To: %s\n"
299*12967Sgavin.maltby@oracle.com 		    "Subject: %s\n\n", XHDR_HOSTNAME, hostname, XHDR_CLASS,
300*12967Sgavin.maltby@oracle.com 		    ev_info->ei_class, XHDR_MSGID, ev_info->ei_diagcode,
301*12967Sgavin.maltby@oracle.com 		    XHDR_SEVERITY, ev_info->ei_severity, XHDR_FMRI,
302*12967Sgavin.maltby@oracle.com 		    ev_info->ei_fmri, XHDR_FROM_STATE, ev_info->ei_from_state,
303*12967Sgavin.maltby@oracle.com 		    XHDR_TO_STATE, ev_info->ei_to_state, eprefs->ep_reply_to,
304*12967Sgavin.maltby@oracle.com 		    subj);
305*12967Sgavin.maltby@oracle.com 
306*12967Sgavin.maltby@oracle.com 		*headers = calloc(len + 1, sizeof (char));
307*12967Sgavin.maltby@oracle.com 
308*12967Sgavin.maltby@oracle.com 		(void) snprintf(*headers, len + 1, "%s: %s\n%s: %s\n%s: %s\n"
309*12967Sgavin.maltby@oracle.com 		    "%s: %s\n%s: %s\n%s: %s\n%s: %s\nReply-To: %s\n"
310*12967Sgavin.maltby@oracle.com 		    "Subject: %s\n\n", XHDR_HOSTNAME, hostname, XHDR_CLASS,
311*12967Sgavin.maltby@oracle.com 		    ev_info->ei_class, XHDR_MSGID, ev_info->ei_diagcode,
312*12967Sgavin.maltby@oracle.com 		    XHDR_SEVERITY, ev_info->ei_severity, XHDR_FMRI,
313*12967Sgavin.maltby@oracle.com 		    ev_info->ei_fmri, XHDR_FROM_STATE, ev_info->ei_from_state,
314*12967Sgavin.maltby@oracle.com 		    XHDR_TO_STATE, ev_info->ei_to_state, eprefs->ep_reply_to,
315*12967Sgavin.maltby@oracle.com 		    subj);
316*12967Sgavin.maltby@oracle.com 	} else {
317*12967Sgavin.maltby@oracle.com 		len = snprintf(NULL, 0, "%s: %s\n%s: %s\n%s: %s\n%s: %s\n"
318*12967Sgavin.maltby@oracle.com 		    "Reply-To: %s\nSubject: %s\n\n", XHDR_HOSTNAME,
319*12967Sgavin.maltby@oracle.com 		    hostname, XHDR_CLASS, ev_info->ei_class, XHDR_MSGID,
320*12967Sgavin.maltby@oracle.com 		    ev_info->ei_diagcode, XHDR_SEVERITY, ev_info->ei_severity,
321*12967Sgavin.maltby@oracle.com 		    eprefs->ep_reply_to, subj);
322*12967Sgavin.maltby@oracle.com 
323*12967Sgavin.maltby@oracle.com 		*headers = calloc(len + 1, sizeof (char));
324*12967Sgavin.maltby@oracle.com 
325*12967Sgavin.maltby@oracle.com 		(void) snprintf(*headers, len + 1, "%s: %s\n%s: %s\n%s: %s\n"
326*12967Sgavin.maltby@oracle.com 		    "%s: %s\nReply-To: %s\nSubject: %s\n\n",
327*12967Sgavin.maltby@oracle.com 		    XHDR_HOSTNAME, hostname, XHDR_CLASS, ev_info->ei_class,
328*12967Sgavin.maltby@oracle.com 		    XHDR_MSGID, ev_info->ei_diagcode, XHDR_SEVERITY,
329*12967Sgavin.maltby@oracle.com 		    ev_info->ei_severity, eprefs->ep_reply_to, subj);
330*12967Sgavin.maltby@oracle.com 	}
331*12967Sgavin.maltby@oracle.com 	return (0);
332*12967Sgavin.maltby@oracle.com }
333*12967Sgavin.maltby@oracle.com 
334*12967Sgavin.maltby@oracle.com static void
send_email(nd_hdl_t * nhdl,const char * headers,const char * body,const char * recip)335*12967Sgavin.maltby@oracle.com send_email(nd_hdl_t *nhdl, const char *headers, const char *body,
336*12967Sgavin.maltby@oracle.com     const char *recip)
337*12967Sgavin.maltby@oracle.com {
338*12967Sgavin.maltby@oracle.com 	FILE *mp;
339*12967Sgavin.maltby@oracle.com 	char sm_cli[PATH_MAX];
340*12967Sgavin.maltby@oracle.com 
341*12967Sgavin.maltby@oracle.com 	/*
342*12967Sgavin.maltby@oracle.com 	 * Open a pipe to sendmail and pump out the email message
343*12967Sgavin.maltby@oracle.com 	 */
344*12967Sgavin.maltby@oracle.com 	(void) snprintf(sm_cli, PATH_MAX, "%s -t %s", SENDMAIL, recip);
345*12967Sgavin.maltby@oracle.com 
346*12967Sgavin.maltby@oracle.com 	nd_debug(nhdl, "Sending email notification to %s", recip);
347*12967Sgavin.maltby@oracle.com 	if ((mp = popen(sm_cli, "w")) == NULL) {
348*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to open pipe to %s (%s)", SENDMAIL,
349*12967Sgavin.maltby@oracle.com 		    strerror(errno));
350*12967Sgavin.maltby@oracle.com 		return;
351*12967Sgavin.maltby@oracle.com 	}
352*12967Sgavin.maltby@oracle.com 	if (fprintf(mp, "%s", headers) < 0)
353*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to write to pipe (%s)", strerror(errno));
354*12967Sgavin.maltby@oracle.com 
355*12967Sgavin.maltby@oracle.com 	if (fprintf(mp, "%s\n.\n", body) < 0)
356*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to write to pipe (%s)",
357*12967Sgavin.maltby@oracle.com 		    strerror(errno));
358*12967Sgavin.maltby@oracle.com 
359*12967Sgavin.maltby@oracle.com 	(void) pclose(mp);
360*12967Sgavin.maltby@oracle.com }
361*12967Sgavin.maltby@oracle.com 
362*12967Sgavin.maltby@oracle.com static void
send_email_template(nd_hdl_t * nhdl,nd_ev_info_t * ev_info,email_pref_t * eprefs)363*12967Sgavin.maltby@oracle.com send_email_template(nd_hdl_t *nhdl, nd_ev_info_t *ev_info, email_pref_t *eprefs)
364*12967Sgavin.maltby@oracle.com {
365*12967Sgavin.maltby@oracle.com 	char *msg, *headers;
366*12967Sgavin.maltby@oracle.com 
367*12967Sgavin.maltby@oracle.com 	if (build_headers(nhdl, ev_info, eprefs, &headers) != 0)
368*12967Sgavin.maltby@oracle.com 		return;
369*12967Sgavin.maltby@oracle.com 
370*12967Sgavin.maltby@oracle.com 	/*
371*12967Sgavin.maltby@oracle.com 	 * If the user specified a message body template, then we pass it
372*12967Sgavin.maltby@oracle.com 	 * through a private interface in libfmd_msg, which will return a string
373*12967Sgavin.maltby@oracle.com 	 * with any expansion tokens decoded.
374*12967Sgavin.maltby@oracle.com 	 */
375*12967Sgavin.maltby@oracle.com 	if ((msg = fmd_msg_decode_tokens(ev_info->ei_payload,
376*12967Sgavin.maltby@oracle.com 	    eprefs->ep_template, ev_info->ei_url)) == NULL) {
377*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to parse msg template");
378*12967Sgavin.maltby@oracle.com 		free(headers);
379*12967Sgavin.maltby@oracle.com 		return;
380*12967Sgavin.maltby@oracle.com 	}
381*12967Sgavin.maltby@oracle.com 	for (int i = 0; i < eprefs->ep_num_recips; i++)
382*12967Sgavin.maltby@oracle.com 		send_email(nhdl, headers, msg, eprefs->ep_recips[i]);
383*12967Sgavin.maltby@oracle.com 
384*12967Sgavin.maltby@oracle.com 	free(msg);
385*12967Sgavin.maltby@oracle.com 	free(headers);
386*12967Sgavin.maltby@oracle.com }
387*12967Sgavin.maltby@oracle.com 
388*12967Sgavin.maltby@oracle.com static int
get_email_prefs(nd_hdl_t * nhdl,fmev_t ev,email_pref_t ** eprefs)389*12967Sgavin.maltby@oracle.com get_email_prefs(nd_hdl_t *nhdl, fmev_t ev, email_pref_t **eprefs)
390*12967Sgavin.maltby@oracle.com {
391*12967Sgavin.maltby@oracle.com 	nvlist_t **p_nvl = NULL;
392*12967Sgavin.maltby@oracle.com 	email_pref_t *ep;
393*12967Sgavin.maltby@oracle.com 	uint_t npref, tn1 = 0, tn2 = 0;
394*12967Sgavin.maltby@oracle.com 	char **tmparr1, **tmparr2;
395*12967Sgavin.maltby@oracle.com 	int r, ret = -1;
396*12967Sgavin.maltby@oracle.com 
397*12967Sgavin.maltby@oracle.com 	r = nd_get_notify_prefs(nhdl, "smtp", ev, &p_nvl, &npref);
398*12967Sgavin.maltby@oracle.com 	if (r == SCF_ERROR_NOT_FOUND) {
399*12967Sgavin.maltby@oracle.com 		/*
400*12967Sgavin.maltby@oracle.com 		 * No email notification preferences specified for this type of
401*12967Sgavin.maltby@oracle.com 		 * event, so we're done
402*12967Sgavin.maltby@oracle.com 		 */
403*12967Sgavin.maltby@oracle.com 		return (-1);
404*12967Sgavin.maltby@oracle.com 	} else if (r != 0) {
405*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to retrieve notification preferences "
406*12967Sgavin.maltby@oracle.com 		    "for this event");
407*12967Sgavin.maltby@oracle.com 		return (-1);
408*12967Sgavin.maltby@oracle.com 	}
409*12967Sgavin.maltby@oracle.com 
410*12967Sgavin.maltby@oracle.com 	if ((ep = malloc(sizeof (email_pref_t))) == NULL) {
411*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to allocate space for email preferences "
412*12967Sgavin.maltby@oracle.com 		    "(%s)", strerror(errno));
413*12967Sgavin.maltby@oracle.com 		goto eprefs_done;
414*12967Sgavin.maltby@oracle.com 	}
415*12967Sgavin.maltby@oracle.com 	(void) memset(ep, 0, sizeof (email_pref_t));
416*12967Sgavin.maltby@oracle.com 
417*12967Sgavin.maltby@oracle.com 	/*
418*12967Sgavin.maltby@oracle.com 	 * For SMF state transition events, pref_nvl may contain two sets of
419*12967Sgavin.maltby@oracle.com 	 * preferences, which will have to be merged.
420*12967Sgavin.maltby@oracle.com 	 *
421*12967Sgavin.maltby@oracle.com 	 * The "smtp" nvlist can contain up to four members:
422*12967Sgavin.maltby@oracle.com 	 *
423*12967Sgavin.maltby@oracle.com 	 * "active"	- boolean - used to toggle notfications
424*12967Sgavin.maltby@oracle.com 	 * "to"		- a string array of email recipients
425*12967Sgavin.maltby@oracle.com 	 * "reply-to"	- a string array containing the reply-to addresses
426*12967Sgavin.maltby@oracle.com 	 *		- this is optional and defaults to root@localhost
427*12967Sgavin.maltby@oracle.com 	 * "msg_template" - the pathname of a user-supplied message body
428*12967Sgavin.maltby@oracle.com 	 *		template
429*12967Sgavin.maltby@oracle.com 	 *
430*12967Sgavin.maltby@oracle.com 	 * In the case that we have two sets of preferences, we will merge them
431*12967Sgavin.maltby@oracle.com 	 * using the following rules:
432*12967Sgavin.maltby@oracle.com 	 *
433*12967Sgavin.maltby@oracle.com 	 * "active" will be set to true, if it is true in either set
434*12967Sgavin.maltby@oracle.com 	 *
435*12967Sgavin.maltby@oracle.com 	 * The "reply-to" and "to" lists will be merged, with duplicate email
436*12967Sgavin.maltby@oracle.com 	 * addresses removed.
437*12967Sgavin.maltby@oracle.com 	 */
438*12967Sgavin.maltby@oracle.com 	if (npref == 2) {
439*12967Sgavin.maltby@oracle.com 		boolean_t *act1, *act2;
440*12967Sgavin.maltby@oracle.com 		char **arr1, **arr2, **strarr, **reparr1, **reparr2;
441*12967Sgavin.maltby@oracle.com 		uint_t n1, n2, arrsz, repsz;
442*12967Sgavin.maltby@oracle.com 
443*12967Sgavin.maltby@oracle.com 		r = nvlist_lookup_boolean_array(p_nvl[0], "active", &act1, &n1);
444*12967Sgavin.maltby@oracle.com 		r += nvlist_lookup_boolean_array(p_nvl[1], "active", &act2,
445*12967Sgavin.maltby@oracle.com 		    &n2);
446*12967Sgavin.maltby@oracle.com 		r += nvlist_lookup_string_array(p_nvl[0], "to", &arr1, &n1);
447*12967Sgavin.maltby@oracle.com 		r += nvlist_lookup_string_array(p_nvl[1], "to", &arr2, &n2);
448*12967Sgavin.maltby@oracle.com 
449*12967Sgavin.maltby@oracle.com 		if (r != 0) {
450*12967Sgavin.maltby@oracle.com 			nd_error(nhdl, "Malformed email notification "
451*12967Sgavin.maltby@oracle.com 			    "preferences");
452*12967Sgavin.maltby@oracle.com 			nd_dump_nvlist(nhdl, p_nvl[0]);
453*12967Sgavin.maltby@oracle.com 			nd_dump_nvlist(nhdl, p_nvl[1]);
454*12967Sgavin.maltby@oracle.com 			goto eprefs_done;
455*12967Sgavin.maltby@oracle.com 		} else if (!act1[0] && !act2[0]) {
456*12967Sgavin.maltby@oracle.com 			nd_debug(nhdl, "Email notification is disabled");
457*12967Sgavin.maltby@oracle.com 			goto eprefs_done;
458*12967Sgavin.maltby@oracle.com 		}
459*12967Sgavin.maltby@oracle.com 
460*12967Sgavin.maltby@oracle.com 		if (nd_split_list(nhdl, arr1[0], ",", &tmparr1, &tn1) != 0 ||
461*12967Sgavin.maltby@oracle.com 		    nd_split_list(nhdl, arr2[0], ",", &tmparr2, &tn2) != 0) {
462*12967Sgavin.maltby@oracle.com 			nd_error(nhdl, "Error parsing \"to\" lists");
463*12967Sgavin.maltby@oracle.com 			nd_dump_nvlist(nhdl, p_nvl[0]);
464*12967Sgavin.maltby@oracle.com 			nd_dump_nvlist(nhdl, p_nvl[1]);
465*12967Sgavin.maltby@oracle.com 			goto eprefs_done;
466*12967Sgavin.maltby@oracle.com 		}
467*12967Sgavin.maltby@oracle.com 
468*12967Sgavin.maltby@oracle.com 		if ((ep->ep_num_recips = nd_merge_strarray(nhdl, tmparr1, tn1,
469*12967Sgavin.maltby@oracle.com 		    tmparr2, tn2, &ep->ep_recips)) < 0) {
470*12967Sgavin.maltby@oracle.com 			nd_error(nhdl, "Error merging email recipient lists");
471*12967Sgavin.maltby@oracle.com 			goto eprefs_done;
472*12967Sgavin.maltby@oracle.com 		}
473*12967Sgavin.maltby@oracle.com 
474*12967Sgavin.maltby@oracle.com 		r = nvlist_lookup_string_array(p_nvl[0], "reply-to", &arr1,
475*12967Sgavin.maltby@oracle.com 		    &n1);
476*12967Sgavin.maltby@oracle.com 		r += nvlist_lookup_string_array(p_nvl[1], "reply-to", &arr2,
477*12967Sgavin.maltby@oracle.com 		    &n2);
478*12967Sgavin.maltby@oracle.com 		repsz = n1 = n2 = 0;
479*12967Sgavin.maltby@oracle.com 		if (!r &&
480*12967Sgavin.maltby@oracle.com 		    nd_split_list(nhdl, arr1[0], ",", &reparr1, &n1) != 0 ||
481*12967Sgavin.maltby@oracle.com 		    nd_split_list(nhdl, arr2[0], ",", &reparr2, &n2) != 0 ||
482*12967Sgavin.maltby@oracle.com 		    (repsz = nd_merge_strarray(nhdl, tmparr1, n1, tmparr2, n2,
483*12967Sgavin.maltby@oracle.com 		    &strarr)) != 0 ||
484*12967Sgavin.maltby@oracle.com 		    nd_join_strarray(nhdl, strarr, repsz, &ep->ep_reply_to)
485*12967Sgavin.maltby@oracle.com 		    != 0) {
486*12967Sgavin.maltby@oracle.com 
487*12967Sgavin.maltby@oracle.com 			ep->ep_reply_to = strdup("root@localhost");
488*12967Sgavin.maltby@oracle.com 		}
489*12967Sgavin.maltby@oracle.com 		if (n1)
490*12967Sgavin.maltby@oracle.com 			nd_free_strarray(reparr1, n1);
491*12967Sgavin.maltby@oracle.com 		if (n2)
492*12967Sgavin.maltby@oracle.com 			nd_free_strarray(reparr2, n2);
493*12967Sgavin.maltby@oracle.com 		if (repsz > 0)
494*12967Sgavin.maltby@oracle.com 			nd_free_strarray(strarr, repsz);
495*12967Sgavin.maltby@oracle.com 
496*12967Sgavin.maltby@oracle.com 		if (nvlist_lookup_string_array(p_nvl[0], "msg_template",
497*12967Sgavin.maltby@oracle.com 		    &strarr, &arrsz) == 0)
498*12967Sgavin.maltby@oracle.com 			ep->ep_template_path = strdup(strarr[0]);
499*12967Sgavin.maltby@oracle.com 	} else {
500*12967Sgavin.maltby@oracle.com 		char **strarr, **tmparr;
501*12967Sgavin.maltby@oracle.com 		uint_t arrsz;
502*12967Sgavin.maltby@oracle.com 		boolean_t *active;
503*12967Sgavin.maltby@oracle.com 
504*12967Sgavin.maltby@oracle.com 		/*
505*12967Sgavin.maltby@oracle.com 		 * Both the "active" and "to" notification preferences are
506*12967Sgavin.maltby@oracle.com 		 * required, so if we have trouble looking either of these up
507*12967Sgavin.maltby@oracle.com 		 * we return an error.  We will also return an error if "active"
508*12967Sgavin.maltby@oracle.com 		 * is set to false.  Returning an error will cause us to not
509*12967Sgavin.maltby@oracle.com 		 * send a notification for this event.
510*12967Sgavin.maltby@oracle.com 		 */
511*12967Sgavin.maltby@oracle.com 		r = nvlist_lookup_boolean_array(p_nvl[0], "active", &active,
512*12967Sgavin.maltby@oracle.com 		    &arrsz);
513*12967Sgavin.maltby@oracle.com 		r += nvlist_lookup_string_array(p_nvl[0], "to", &strarr,
514*12967Sgavin.maltby@oracle.com 		    &arrsz);
515*12967Sgavin.maltby@oracle.com 
516*12967Sgavin.maltby@oracle.com 		if (r != 0) {
517*12967Sgavin.maltby@oracle.com 			nd_error(nhdl, "Malformed email notification "
518*12967Sgavin.maltby@oracle.com 			    "preferences");
519*12967Sgavin.maltby@oracle.com 			nd_dump_nvlist(nhdl, p_nvl[0]);
520*12967Sgavin.maltby@oracle.com 			goto eprefs_done;
521*12967Sgavin.maltby@oracle.com 		} else if (!active[0]) {
522*12967Sgavin.maltby@oracle.com 			nd_debug(nhdl, "Email notification is disabled");
523*12967Sgavin.maltby@oracle.com 			goto eprefs_done;
524*12967Sgavin.maltby@oracle.com 		}
525*12967Sgavin.maltby@oracle.com 
526*12967Sgavin.maltby@oracle.com 		if (nd_split_list(nhdl, strarr[0], ",", &tmparr, &arrsz)
527*12967Sgavin.maltby@oracle.com 		    != 0) {
528*12967Sgavin.maltby@oracle.com 			nd_error(nhdl, "Error parsing \"to\" list");
529*12967Sgavin.maltby@oracle.com 			goto eprefs_done;
530*12967Sgavin.maltby@oracle.com 		}
531*12967Sgavin.maltby@oracle.com 		ep->ep_num_recips = arrsz;
532*12967Sgavin.maltby@oracle.com 		ep->ep_recips = tmparr;
533*12967Sgavin.maltby@oracle.com 
534*12967Sgavin.maltby@oracle.com 		if (nvlist_lookup_string_array(p_nvl[0], "msg_template",
535*12967Sgavin.maltby@oracle.com 		    &strarr, &arrsz) == 0)
536*12967Sgavin.maltby@oracle.com 			ep->ep_template_path = strdup(strarr[0]);
537*12967Sgavin.maltby@oracle.com 
538*12967Sgavin.maltby@oracle.com 		if (nvlist_lookup_string_array(p_nvl[0], "reply-to", &strarr,
539*12967Sgavin.maltby@oracle.com 		    &arrsz) == 0)
540*12967Sgavin.maltby@oracle.com 			ep->ep_reply_to = strdup(strarr[0]);
541*12967Sgavin.maltby@oracle.com 		else
542*12967Sgavin.maltby@oracle.com 			ep->ep_reply_to = strdup("root@localhost");
543*12967Sgavin.maltby@oracle.com 	}
544*12967Sgavin.maltby@oracle.com 	ret = 0;
545*12967Sgavin.maltby@oracle.com 	*eprefs = ep;
546*12967Sgavin.maltby@oracle.com eprefs_done:
547*12967Sgavin.maltby@oracle.com 	if (ret != 0) {
548*12967Sgavin.maltby@oracle.com 		if (ep->ep_recips)
549*12967Sgavin.maltby@oracle.com 			nd_free_strarray(ep->ep_recips, ep->ep_num_recips);
550*12967Sgavin.maltby@oracle.com 		if (ep->ep_reply_to)
551*12967Sgavin.maltby@oracle.com 			free(ep->ep_reply_to);
552*12967Sgavin.maltby@oracle.com 		free(ep);
553*12967Sgavin.maltby@oracle.com 	}
554*12967Sgavin.maltby@oracle.com 	if (tn1)
555*12967Sgavin.maltby@oracle.com 		nd_free_strarray(tmparr1, tn1);
556*12967Sgavin.maltby@oracle.com 	if (tn2)
557*12967Sgavin.maltby@oracle.com 		nd_free_strarray(tmparr2, tn2);
558*12967Sgavin.maltby@oracle.com 	nd_free_nvlarray(p_nvl, npref);
559*12967Sgavin.maltby@oracle.com 
560*12967Sgavin.maltby@oracle.com 	return (ret);
561*12967Sgavin.maltby@oracle.com }
562*12967Sgavin.maltby@oracle.com 
563*12967Sgavin.maltby@oracle.com /*ARGSUSED*/
564*12967Sgavin.maltby@oracle.com static void
irpt_cbfunc(fmev_t ev,const char * class,nvlist_t * nvl,void * arg)565*12967Sgavin.maltby@oracle.com irpt_cbfunc(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
566*12967Sgavin.maltby@oracle.com {
567*12967Sgavin.maltby@oracle.com 	char *body_fmt, *headers = NULL, *body = NULL, tstamp[32];
568*12967Sgavin.maltby@oracle.com 	struct tm ts;
569*12967Sgavin.maltby@oracle.com 	size_t len;
570*12967Sgavin.maltby@oracle.com 	nd_ev_info_t *ev_info = NULL;
571*12967Sgavin.maltby@oracle.com 	email_pref_t *eprefs;
572*12967Sgavin.maltby@oracle.com 
573*12967Sgavin.maltby@oracle.com 	nd_debug(nhdl, "Received event of class %s", class);
574*12967Sgavin.maltby@oracle.com 
575*12967Sgavin.maltby@oracle.com 	if (get_email_prefs(nhdl, ev, &eprefs) < 0)
576*12967Sgavin.maltby@oracle.com 		return;
577*12967Sgavin.maltby@oracle.com 
578*12967Sgavin.maltby@oracle.com 	if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
579*12967Sgavin.maltby@oracle.com 		goto irpt_done;
580*12967Sgavin.maltby@oracle.com 
581*12967Sgavin.maltby@oracle.com 	/*
582*12967Sgavin.maltby@oracle.com 	 * If the user specified a template, then we pass it through a script,
583*12967Sgavin.maltby@oracle.com 	 * which post-processes any expansion macros.  Then we attempt to read
584*12967Sgavin.maltby@oracle.com 	 * it in and then send the message.  Otherwise we carry on with the rest
585*12967Sgavin.maltby@oracle.com 	 * of this function which will contruct the message body from one of the
586*12967Sgavin.maltby@oracle.com 	 * default templates.
587*12967Sgavin.maltby@oracle.com 	 */
588*12967Sgavin.maltby@oracle.com 	if (eprefs->ep_template != NULL)
589*12967Sgavin.maltby@oracle.com 		free(eprefs->ep_template);
590*12967Sgavin.maltby@oracle.com 
591*12967Sgavin.maltby@oracle.com 	if (eprefs->ep_template_path != NULL &&
592*12967Sgavin.maltby@oracle.com 	    process_template(ev_info, eprefs) == 0) {
593*12967Sgavin.maltby@oracle.com 		send_email_template(nhdl, ev_info, eprefs);
594*12967Sgavin.maltby@oracle.com 		goto irpt_done;
595*12967Sgavin.maltby@oracle.com 	}
596*12967Sgavin.maltby@oracle.com 
597*12967Sgavin.maltby@oracle.com 	/*
598*12967Sgavin.maltby@oracle.com 	 * Fetch and format the event timestamp
599*12967Sgavin.maltby@oracle.com 	 */
600*12967Sgavin.maltby@oracle.com 	if (fmev_localtime(ev, &ts) == NULL) {
601*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Malformed event: failed to retrieve "
602*12967Sgavin.maltby@oracle.com 		    "timestamp");
603*12967Sgavin.maltby@oracle.com 		goto irpt_done;
604*12967Sgavin.maltby@oracle.com 	}
605*12967Sgavin.maltby@oracle.com 	(void) strftime(tstamp, sizeof (tstamp), NULL, &ts);
606*12967Sgavin.maltby@oracle.com 
607*12967Sgavin.maltby@oracle.com 	/*
608*12967Sgavin.maltby@oracle.com 	 * We have two message body templates to choose from.  One for SMF
609*12967Sgavin.maltby@oracle.com 	 * service transition events and a generic one for any other
610*12967Sgavin.maltby@oracle.com 	 * uncommitted ireport.
611*12967Sgavin.maltby@oracle.com 	 */
612*12967Sgavin.maltby@oracle.com 	if (strncmp(class, "ireport.os.smf", 14) == 0) {
613*12967Sgavin.maltby@oracle.com 		/*
614*12967Sgavin.maltby@oracle.com 		 * For SMF state transition events we have a standard message
615*12967Sgavin.maltby@oracle.com 		 * template that we fill in based on the payload of the event.
616*12967Sgavin.maltby@oracle.com 		 */
617*12967Sgavin.maltby@oracle.com 		if ((body_fmt = fmd_msg_gettext_key(nhdl->nh_msghdl, NULL,
618*12967Sgavin.maltby@oracle.com 		    FMNOTIFY_MSG_DOMAIN, SMF_MSG_TEMPLATE)) == NULL) {
619*12967Sgavin.maltby@oracle.com 			nd_error(nhdl, "Failed to format message body");
620*12967Sgavin.maltby@oracle.com 			goto irpt_done;
621*12967Sgavin.maltby@oracle.com 		}
622*12967Sgavin.maltby@oracle.com 
623*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
624*12967Sgavin.maltby@oracle.com 		len = snprintf(NULL, 0, body_fmt, hostname, tstamp,
625*12967Sgavin.maltby@oracle.com 		    ev_info->ei_fmri, ev_info->ei_from_state,
626*12967Sgavin.maltby@oracle.com 		    ev_info->ei_to_state, ev_info->ei_descr,
627*12967Sgavin.maltby@oracle.com 		    ev_info->ei_reason);
628*12967Sgavin.maltby@oracle.com 		body = calloc(len, sizeof (char));
629*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
630*12967Sgavin.maltby@oracle.com 		(void) snprintf(body, len, body_fmt, hostname, tstamp,
631*12967Sgavin.maltby@oracle.com 		    ev_info->ei_fmri, ev_info->ei_from_state,
632*12967Sgavin.maltby@oracle.com 		    ev_info->ei_to_state, ev_info->ei_descr,
633*12967Sgavin.maltby@oracle.com 		    ev_info->ei_reason);
634*12967Sgavin.maltby@oracle.com 	} else {
635*12967Sgavin.maltby@oracle.com 		if ((body_fmt = fmd_msg_gettext_key(nhdl->nh_msghdl, NULL,
636*12967Sgavin.maltby@oracle.com 		    FMNOTIFY_MSG_DOMAIN, IREPORT_MSG_TEMPLATE)) == NULL) {
637*12967Sgavin.maltby@oracle.com 			nd_error(nhdl, "Failed to format message body");
638*12967Sgavin.maltby@oracle.com 			goto irpt_done;
639*12967Sgavin.maltby@oracle.com 		}
640*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
641*12967Sgavin.maltby@oracle.com 		len = snprintf(NULL, 0, body_fmt, hostname, tstamp, class);
642*12967Sgavin.maltby@oracle.com 		body = calloc(len, sizeof (char));
643*12967Sgavin.maltby@oracle.com 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
644*12967Sgavin.maltby@oracle.com 		(void) snprintf(body, len, body_fmt, hostname, tstamp, class);
645*12967Sgavin.maltby@oracle.com 	}
646*12967Sgavin.maltby@oracle.com 
647*12967Sgavin.maltby@oracle.com 	if (build_headers(nhdl, ev_info, eprefs, &headers) != 0)
648*12967Sgavin.maltby@oracle.com 		goto irpt_done;
649*12967Sgavin.maltby@oracle.com 
650*12967Sgavin.maltby@oracle.com 	/*
651*12967Sgavin.maltby@oracle.com 	 * Everything is ready, so now we just iterate through the list of
652*12967Sgavin.maltby@oracle.com 	 * recipents, sending an email notification to each one.
653*12967Sgavin.maltby@oracle.com 	 */
654*12967Sgavin.maltby@oracle.com 	for (int i = 0; i < eprefs->ep_num_recips; i++)
655*12967Sgavin.maltby@oracle.com 		send_email(nhdl, headers, body, eprefs->ep_recips[i]);
656*12967Sgavin.maltby@oracle.com 
657*12967Sgavin.maltby@oracle.com irpt_done:
658*12967Sgavin.maltby@oracle.com 	free(headers);
659*12967Sgavin.maltby@oracle.com 	free(body);
660*12967Sgavin.maltby@oracle.com 	if (ev_info)
661*12967Sgavin.maltby@oracle.com 		nd_free_event_info(ev_info);
662*12967Sgavin.maltby@oracle.com 	if (eprefs->ep_recips)
663*12967Sgavin.maltby@oracle.com 		nd_free_strarray(eprefs->ep_recips, eprefs->ep_num_recips);
664*12967Sgavin.maltby@oracle.com 	if (eprefs->ep_reply_to)
665*12967Sgavin.maltby@oracle.com 		free(eprefs->ep_reply_to);
666*12967Sgavin.maltby@oracle.com 	free(eprefs);
667*12967Sgavin.maltby@oracle.com }
668*12967Sgavin.maltby@oracle.com 
669*12967Sgavin.maltby@oracle.com /*
670*12967Sgavin.maltby@oracle.com  * There is a lack of uniformity in how the various entries in our diagnosis
671*12967Sgavin.maltby@oracle.com  * are terminated.  Some end with one newline, others with two.  This makes the
672*12967Sgavin.maltby@oracle.com  * output look a bit ugly.  Therefore we postprocess the message before sending
673*12967Sgavin.maltby@oracle.com  * it, removing consecutive occurences of newlines.
674*12967Sgavin.maltby@oracle.com  */
675*12967Sgavin.maltby@oracle.com static void
postprocess_msg(char * msg)676*12967Sgavin.maltby@oracle.com postprocess_msg(char *msg)
677*12967Sgavin.maltby@oracle.com {
678*12967Sgavin.maltby@oracle.com 	int i = 0, j = 0;
679*12967Sgavin.maltby@oracle.com 	char *buf;
680*12967Sgavin.maltby@oracle.com 
681*12967Sgavin.maltby@oracle.com 	if ((buf = malloc(strlen(msg) + 1)) == NULL)
682*12967Sgavin.maltby@oracle.com 		return;
683*12967Sgavin.maltby@oracle.com 
684*12967Sgavin.maltby@oracle.com 	buf[j++] = msg[i++];
685*12967Sgavin.maltby@oracle.com 	for (i = 1; i < strlen(msg); i++) {
686*12967Sgavin.maltby@oracle.com 		if (!(msg[i] == '\n' && msg[i - 1] == '\n'))
687*12967Sgavin.maltby@oracle.com 			buf[j++] = msg[i];
688*12967Sgavin.maltby@oracle.com 	}
689*12967Sgavin.maltby@oracle.com 	buf[j] = '\0';
690*12967Sgavin.maltby@oracle.com 	(void) strncpy(msg, buf, j+1);
691*12967Sgavin.maltby@oracle.com 	free(buf);
692*12967Sgavin.maltby@oracle.com }
693*12967Sgavin.maltby@oracle.com 
694*12967Sgavin.maltby@oracle.com /*ARGSUSED*/
695*12967Sgavin.maltby@oracle.com static void
listev_cb(fmev_t ev,const char * class,nvlist_t * nvl,void * arg)696*12967Sgavin.maltby@oracle.com listev_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
697*12967Sgavin.maltby@oracle.com {
698*12967Sgavin.maltby@oracle.com 	char *body = NULL, *headers = NULL;
699*12967Sgavin.maltby@oracle.com 	nd_ev_info_t *ev_info = NULL;
700*12967Sgavin.maltby@oracle.com 	boolean_t domsg;
701*12967Sgavin.maltby@oracle.com 	email_pref_t *eprefs;
702*12967Sgavin.maltby@oracle.com 
703*12967Sgavin.maltby@oracle.com 	nd_debug(nhdl, "Received event of class %s", class);
704*12967Sgavin.maltby@oracle.com 
705*12967Sgavin.maltby@oracle.com 	if (get_email_prefs(nhdl, ev, &eprefs) < 0)
706*12967Sgavin.maltby@oracle.com 		return;
707*12967Sgavin.maltby@oracle.com 
708*12967Sgavin.maltby@oracle.com 	if (nd_get_event_info(nhdl, class, ev, &ev_info) != 0)
709*12967Sgavin.maltby@oracle.com 		goto listcb_done;
710*12967Sgavin.maltby@oracle.com 
711*12967Sgavin.maltby@oracle.com 	/*
712*12967Sgavin.maltby@oracle.com 	 * If the message payload member is set to 0, then it's an event we
713*12967Sgavin.maltby@oracle.com 	 * typically suppress messaging on, so we won't send an email for it.
714*12967Sgavin.maltby@oracle.com 	 */
715*12967Sgavin.maltby@oracle.com 	if (nvlist_lookup_boolean_value(ev_info->ei_payload, FM_SUSPECT_MESSAGE,
716*12967Sgavin.maltby@oracle.com 	    &domsg) == 0 && !domsg) {
717*12967Sgavin.maltby@oracle.com 		nd_debug(nhdl, "Messaging suppressed for this event");
718*12967Sgavin.maltby@oracle.com 		goto listcb_done;
719*12967Sgavin.maltby@oracle.com 	}
720*12967Sgavin.maltby@oracle.com 
721*12967Sgavin.maltby@oracle.com 	/*
722*12967Sgavin.maltby@oracle.com 	 * If the user specified a template, then we pass it through a script,
723*12967Sgavin.maltby@oracle.com 	 * which post-processes any expansion macros.  Then we attempt to read
724*12967Sgavin.maltby@oracle.com 	 * it in and then send the message.  Otherwise we carry on with the rest
725*12967Sgavin.maltby@oracle.com 	 * of this function which will contruct the message body from one of the
726*12967Sgavin.maltby@oracle.com 	 * default templates.
727*12967Sgavin.maltby@oracle.com 	 */
728*12967Sgavin.maltby@oracle.com 	if (eprefs->ep_template != NULL)
729*12967Sgavin.maltby@oracle.com 		free(eprefs->ep_template);
730*12967Sgavin.maltby@oracle.com 
731*12967Sgavin.maltby@oracle.com 	if (eprefs->ep_template_path != NULL &&
732*12967Sgavin.maltby@oracle.com 	    process_template(ev_info, eprefs) == 0) {
733*12967Sgavin.maltby@oracle.com 		send_email_template(nhdl, ev_info, eprefs);
734*12967Sgavin.maltby@oracle.com 		goto listcb_done;
735*12967Sgavin.maltby@oracle.com 	}
736*12967Sgavin.maltby@oracle.com 
737*12967Sgavin.maltby@oracle.com 	/*
738*12967Sgavin.maltby@oracle.com 	 * Format the message body
739*12967Sgavin.maltby@oracle.com 	 *
740*12967Sgavin.maltby@oracle.com 	 * For FMA list.* events we use the same message that the
741*12967Sgavin.maltby@oracle.com 	 * syslog-msgs agent would emit as the message body
742*12967Sgavin.maltby@oracle.com 	 *
743*12967Sgavin.maltby@oracle.com 	 */
744*12967Sgavin.maltby@oracle.com 	if ((body = fmd_msg_gettext_nv(nhdl->nh_msghdl, NULL,
745*12967Sgavin.maltby@oracle.com 	    ev_info->ei_payload)) == NULL) {
746*12967Sgavin.maltby@oracle.com 		nd_error(nhdl, "Failed to format message body");
747*12967Sgavin.maltby@oracle.com 		nd_dump_nvlist(nhdl, ev_info->ei_payload);
748*12967Sgavin.maltby@oracle.com 		goto listcb_done;
749*12967Sgavin.maltby@oracle.com 	}
750*12967Sgavin.maltby@oracle.com 	postprocess_msg(body);
751*12967Sgavin.maltby@oracle.com 
752*12967Sgavin.maltby@oracle.com 	if (build_headers(nhdl, ev_info, eprefs, &headers) != 0)
753*12967Sgavin.maltby@oracle.com 		goto listcb_done;
754*12967Sgavin.maltby@oracle.com 
755*12967Sgavin.maltby@oracle.com 	/*
756*12967Sgavin.maltby@oracle.com 	 * Everything is ready, so now we just iterate through the list of
757*12967Sgavin.maltby@oracle.com 	 * recipents, sending an email notification to each one.
758*12967Sgavin.maltby@oracle.com 	 */
759*12967Sgavin.maltby@oracle.com 	for (int i = 0; i < eprefs->ep_num_recips; i++)
760*12967Sgavin.maltby@oracle.com 		send_email(nhdl, headers, body, eprefs->ep_recips[i]);
761*12967Sgavin.maltby@oracle.com 
762*12967Sgavin.maltby@oracle.com listcb_done:
763*12967Sgavin.maltby@oracle.com 	free(headers);
764*12967Sgavin.maltby@oracle.com 	free(body);
765*12967Sgavin.maltby@oracle.com 	if (ev_info)
766*12967Sgavin.maltby@oracle.com 		nd_free_event_info(ev_info);
767*12967Sgavin.maltby@oracle.com 	if (eprefs->ep_recips)
768*12967Sgavin.maltby@oracle.com 		nd_free_strarray(eprefs->ep_recips, eprefs->ep_num_recips);
769*12967Sgavin.maltby@oracle.com 	if (eprefs->ep_reply_to)
770*12967Sgavin.maltby@oracle.com 		free(eprefs->ep_reply_to);
771*12967Sgavin.maltby@oracle.com 	free(eprefs);
772*12967Sgavin.maltby@oracle.com }
773*12967Sgavin.maltby@oracle.com 
774*12967Sgavin.maltby@oracle.com int
main(int argc,char * argv[])775*12967Sgavin.maltby@oracle.com main(int argc, char *argv[])
776*12967Sgavin.maltby@oracle.com {
777*12967Sgavin.maltby@oracle.com 	struct rlimit rlim;
778*12967Sgavin.maltby@oracle.com 	struct sigaction act;
779*12967Sgavin.maltby@oracle.com 	sigset_t set;
780*12967Sgavin.maltby@oracle.com 	char c;
781*12967Sgavin.maltby@oracle.com 	boolean_t run_fg = B_FALSE;
782*12967Sgavin.maltby@oracle.com 
783*12967Sgavin.maltby@oracle.com 	if ((nhdl = malloc(sizeof (nd_hdl_t))) == NULL) {
784*12967Sgavin.maltby@oracle.com 		(void) fprintf(stderr, "Failed to allocate space for notifyd "
785*12967Sgavin.maltby@oracle.com 		    "handle (%s)", strerror(errno));
786*12967Sgavin.maltby@oracle.com 		return (1);
787*12967Sgavin.maltby@oracle.com 	}
788*12967Sgavin.maltby@oracle.com 	(void) memset(nhdl, 0, sizeof (nd_hdl_t));
789*12967Sgavin.maltby@oracle.com 
790*12967Sgavin.maltby@oracle.com 	nhdl->nh_keep_running = B_TRUE;
791*12967Sgavin.maltby@oracle.com 	nhdl->nh_log_fd = stderr;
792*12967Sgavin.maltby@oracle.com 	nhdl->nh_pname = argv[0];
793*12967Sgavin.maltby@oracle.com 
794*12967Sgavin.maltby@oracle.com 	get_svc_config();
795*12967Sgavin.maltby@oracle.com 
796*12967Sgavin.maltby@oracle.com 	/*
797*12967Sgavin.maltby@oracle.com 	 * In the case where we get started outside of SMF, args passed on the
798*12967Sgavin.maltby@oracle.com 	 * command line override SMF property setting
799*12967Sgavin.maltby@oracle.com 	 */
800*12967Sgavin.maltby@oracle.com 	while (optind < argc) {
801*12967Sgavin.maltby@oracle.com 		while ((c = getopt(argc, argv, optstr)) != -1) {
802*12967Sgavin.maltby@oracle.com 			switch (c) {
803*12967Sgavin.maltby@oracle.com 			case 'd':
804*12967Sgavin.maltby@oracle.com 				nhdl->nh_debug = B_TRUE;
805*12967Sgavin.maltby@oracle.com 				break;
806*12967Sgavin.maltby@oracle.com 			case 'f':
807*12967Sgavin.maltby@oracle.com 				run_fg = B_TRUE;
808*12967Sgavin.maltby@oracle.com 				break;
809*12967Sgavin.maltby@oracle.com 			case 'R':
810*12967Sgavin.maltby@oracle.com 				nhdl->nh_rootdir = strdup(optarg);
811*12967Sgavin.maltby@oracle.com 				break;
812*12967Sgavin.maltby@oracle.com 			default:
813*12967Sgavin.maltby@oracle.com 				free(nhdl);
814*12967Sgavin.maltby@oracle.com 				return (usage(nhdl->nh_pname));
815*12967Sgavin.maltby@oracle.com 			}
816*12967Sgavin.maltby@oracle.com 		}
817*12967Sgavin.maltby@oracle.com 	}
818*12967Sgavin.maltby@oracle.com 
819*12967Sgavin.maltby@oracle.com 	/*
820*12967Sgavin.maltby@oracle.com 	 * Set up a signal handler for SIGTERM (and SIGINT if we'll
821*12967Sgavin.maltby@oracle.com 	 * be running in the foreground) to ensure sure we get a chance to exit
822*12967Sgavin.maltby@oracle.com 	 * in an orderly fashion.  We also catch SIGHUP, which will be sent to
823*12967Sgavin.maltby@oracle.com 	 * us by SMF if the service is refreshed.
824*12967Sgavin.maltby@oracle.com 	 */
825*12967Sgavin.maltby@oracle.com 	(void) sigfillset(&set);
826*12967Sgavin.maltby@oracle.com 	(void) sigfillset(&act.sa_mask);
827*12967Sgavin.maltby@oracle.com 	act.sa_handler = nd_sighandler;
828*12967Sgavin.maltby@oracle.com 	act.sa_flags = 0;
829*12967Sgavin.maltby@oracle.com 
830*12967Sgavin.maltby@oracle.com 	(void) sigaction(SIGTERM, &act, NULL);
831*12967Sgavin.maltby@oracle.com 	(void) sigdelset(&set, SIGTERM);
832*12967Sgavin.maltby@oracle.com 	(void) sigaction(SIGHUP, &act, NULL);
833*12967Sgavin.maltby@oracle.com 	(void) sigdelset(&set, SIGHUP);
834*12967Sgavin.maltby@oracle.com 
835*12967Sgavin.maltby@oracle.com 	if (run_fg) {
836*12967Sgavin.maltby@oracle.com 		(void) sigaction(SIGINT, &act, NULL);
837*12967Sgavin.maltby@oracle.com 		(void) sigdelset(&set, SIGINT);
838*12967Sgavin.maltby@oracle.com 	} else
839*12967Sgavin.maltby@oracle.com 		nd_daemonize(nhdl);
840*12967Sgavin.maltby@oracle.com 
841*12967Sgavin.maltby@oracle.com 	rlim.rlim_cur = RLIM_INFINITY;
842*12967Sgavin.maltby@oracle.com 	rlim.rlim_max = RLIM_INFINITY;
843*12967Sgavin.maltby@oracle.com 	(void) setrlimit(RLIMIT_CORE, &rlim);
844*12967Sgavin.maltby@oracle.com 
845*12967Sgavin.maltby@oracle.com 	/*
846*12967Sgavin.maltby@oracle.com 	 * We need to be root to initialize our libfmevent handle (because that
847*12967Sgavin.maltby@oracle.com 	 * involves reading/writing to /dev/sysevent), so we do this before
848*12967Sgavin.maltby@oracle.com 	 * calling __init_daemon_priv.
849*12967Sgavin.maltby@oracle.com 	 */
850*12967Sgavin.maltby@oracle.com 	nhdl->nh_evhdl = fmev_shdl_init(LIBFMEVENT_VERSION_2, NULL, NULL, NULL);
851*12967Sgavin.maltby@oracle.com 	if (nhdl->nh_evhdl == NULL) {
852*12967Sgavin.maltby@oracle.com 		(void) sleep(5);
853*12967Sgavin.maltby@oracle.com 		nd_abort(nhdl, "failed to initialize libfmevent: %s",
854*12967Sgavin.maltby@oracle.com 		    fmev_strerror(fmev_errno));
855*12967Sgavin.maltby@oracle.com 	}
856*12967Sgavin.maltby@oracle.com 
857*12967Sgavin.maltby@oracle.com 	/*
858*12967Sgavin.maltby@oracle.com 	 * If we're in the global zone, reset all of our privilege sets to
859*12967Sgavin.maltby@oracle.com 	 * the minimum set of required privileges.  Since we've already
860*12967Sgavin.maltby@oracle.com 	 * initialized our libmevent handle, we no no longer need to run as
861*12967Sgavin.maltby@oracle.com 	 * root, so we change our uid/gid to noaccess (60002).
862*12967Sgavin.maltby@oracle.com 	 *
863*12967Sgavin.maltby@oracle.com 	 * __init_daemon_priv will also set the process core path for us
864*12967Sgavin.maltby@oracle.com 	 *
865*12967Sgavin.maltby@oracle.com 	 */
866*12967Sgavin.maltby@oracle.com 	if (getzoneid() == GLOBAL_ZONEID)
867*12967Sgavin.maltby@oracle.com 		if (__init_daemon_priv(
868*12967Sgavin.maltby@oracle.com 		    PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS,
869*12967Sgavin.maltby@oracle.com 		    60002, 60002, PRIV_PROC_SETID, NULL) != 0)
870*12967Sgavin.maltby@oracle.com 			nd_abort(nhdl, "additional privileges required to run");
871*12967Sgavin.maltby@oracle.com 
872*12967Sgavin.maltby@oracle.com 	nhdl->nh_msghdl = fmd_msg_init(nhdl->nh_rootdir, FMD_MSG_VERSION);
873*12967Sgavin.maltby@oracle.com 	if (nhdl->nh_msghdl == NULL)
874*12967Sgavin.maltby@oracle.com 		nd_abort(nhdl, "failed to initialize libfmd_msg");
875*12967Sgavin.maltby@oracle.com 
876*12967Sgavin.maltby@oracle.com 	(void) gethostname(hostname, MAXHOSTNAMELEN + 1);
877*12967Sgavin.maltby@oracle.com 	/*
878*12967Sgavin.maltby@oracle.com 	 * Set up our event subscriptions.  We subscribe to everything and then
879*12967Sgavin.maltby@oracle.com 	 * consult libscf when we receive an event to determine whether to send
880*12967Sgavin.maltby@oracle.com 	 * an email notification.
881*12967Sgavin.maltby@oracle.com 	 */
882*12967Sgavin.maltby@oracle.com 	nd_debug(nhdl, "Subscribing to ireport.* events");
883*12967Sgavin.maltby@oracle.com 	if (fmev_shdl_subscribe(nhdl->nh_evhdl, "ireport.*", irpt_cbfunc,
884*12967Sgavin.maltby@oracle.com 	    NULL) != FMEV_SUCCESS) {
885*12967Sgavin.maltby@oracle.com 		nd_abort(nhdl, "fmev_shdl_subscribe failed: %s",
886*12967Sgavin.maltby@oracle.com 		    fmev_strerror(fmev_errno));
887*12967Sgavin.maltby@oracle.com 	}
888*12967Sgavin.maltby@oracle.com 
889*12967Sgavin.maltby@oracle.com 	nd_debug(nhdl, "Subscribing to list.* events");
890*12967Sgavin.maltby@oracle.com 	if (fmev_shdl_subscribe(nhdl->nh_evhdl, "list.*", listev_cb,
891*12967Sgavin.maltby@oracle.com 	    NULL) != FMEV_SUCCESS) {
892*12967Sgavin.maltby@oracle.com 		nd_abort(nhdl, "fmev_shdl_subscribe failed: %s",
893*12967Sgavin.maltby@oracle.com 		    fmev_strerror(fmev_errno));
894*12967Sgavin.maltby@oracle.com 	}
895*12967Sgavin.maltby@oracle.com 
896*12967Sgavin.maltby@oracle.com 	/*
897*12967Sgavin.maltby@oracle.com 	 * We run until someone kills us
898*12967Sgavin.maltby@oracle.com 	 */
899*12967Sgavin.maltby@oracle.com 	while (nhdl->nh_keep_running)
900*12967Sgavin.maltby@oracle.com 		(void) sigsuspend(&set);
901*12967Sgavin.maltby@oracle.com 
902*12967Sgavin.maltby@oracle.com 	free(nhdl->nh_rootdir);
903*12967Sgavin.maltby@oracle.com 	free(nhdl);
904*12967Sgavin.maltby@oracle.com 
905*12967Sgavin.maltby@oracle.com 	return (0);
906*12967Sgavin.maltby@oracle.com }
907