xref: /onnv-gate/usr/src/cmd/krb5/kwarn/kwarnd_proc.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate /*
9*0Sstevel@tonic-gate  *  RPC server procedures for the usermode daemon kwarnd.
10*0Sstevel@tonic-gate  */
11*0Sstevel@tonic-gate 
12*0Sstevel@tonic-gate #include <stdio.h>
13*0Sstevel@tonic-gate #include <unistd.h>
14*0Sstevel@tonic-gate #include <pwd.h>
15*0Sstevel@tonic-gate #include <grp.h>
16*0Sstevel@tonic-gate #include <strings.h>
17*0Sstevel@tonic-gate #include <string.h>
18*0Sstevel@tonic-gate #include <sys/param.h>
19*0Sstevel@tonic-gate #include <sys/syslog.h>
20*0Sstevel@tonic-gate #include "kwarnd.h"
21*0Sstevel@tonic-gate #include <rpc/rpc.h>
22*0Sstevel@tonic-gate #include <stdlib.h>
23*0Sstevel@tonic-gate #include <syslog.h>
24*0Sstevel@tonic-gate #include <poll.h>
25*0Sstevel@tonic-gate #include <utmpx.h>
26*0Sstevel@tonic-gate #include <pwd.h>
27*0Sstevel@tonic-gate #include <strings.h>
28*0Sstevel@tonic-gate #include <ctype.h>
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #include <k5-int.h>
31*0Sstevel@tonic-gate #include <profile/prof_int.h>
32*0Sstevel@tonic-gate #include <com_err.h>
33*0Sstevel@tonic-gate #include <libintl.h>
34*0Sstevel@tonic-gate #include <krb5.h>
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate struct k5_data
37*0Sstevel@tonic-gate {
38*0Sstevel@tonic-gate 	krb5_context ctx;
39*0Sstevel@tonic-gate 	krb5_ccache cc;
40*0Sstevel@tonic-gate 	krb5_principal me;
41*0Sstevel@tonic-gate 	char *name;
42*0Sstevel@tonic-gate };
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #define	MAIL		"mail"
46*0Sstevel@tonic-gate #define	MAILPATH	"/usr/bin/mail"
47*0Sstevel@tonic-gate #define	DEFAULT_CONFIG	"* terminal 30m"
48*0Sstevel@tonic-gate #define	CONF_FILENAME	"/etc/krb5/warn.conf"
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate /* warn.conf info */
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate typedef struct config_entry_s {
53*0Sstevel@tonic-gate 	struct config_entry_s		*next;
54*0Sstevel@tonic-gate 	int				seconds_to_warn;
55*0Sstevel@tonic-gate 	char				*principal;
56*0Sstevel@tonic-gate 	char				*where_to;
57*0Sstevel@tonic-gate 	char				*email;
58*0Sstevel@tonic-gate 	int				renew;
59*0Sstevel@tonic-gate 	int				log_success;
60*0Sstevel@tonic-gate 	int				log_failure;
61*0Sstevel@tonic-gate } config_entry_list_t;
62*0Sstevel@tonic-gate static config_entry_list_t		*config_entry_list;
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate /* list of principals to be warned */
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate typedef struct cred_warning_list_s {
67*0Sstevel@tonic-gate 	struct cred_warning_list_s 	*next;
68*0Sstevel@tonic-gate 	WARNING_NAME_T			warn_name;
69*0Sstevel@tonic-gate 	time_t				cred_exp_time;
70*0Sstevel@tonic-gate 	time_t				cred_warn_time;
71*0Sstevel@tonic-gate 	mutex_t				cwm;
72*0Sstevel@tonic-gate } cred_warning_list_t;
73*0Sstevel@tonic-gate static cred_warning_list_t		*cred_warning_list;
74*0Sstevel@tonic-gate static rwlock_t				cred_lock = DEFAULTRWLOCK;
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate static bool_t
77*0Sstevel@tonic-gate del_warning_pvt(char *);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate static config_entry_list_t *
80*0Sstevel@tonic-gate find_warning_info(char *);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate static bool_t
83*0Sstevel@tonic-gate parseConfigLine(char *buffer);
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate extern
86*0Sstevel@tonic-gate warn_send(char *, char *);
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate extern int kwarnd_debug;
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate cred_warning_list_t *
91*0Sstevel@tonic-gate find_cred_warning(WARNING_NAME_T warn_name)
92*0Sstevel@tonic-gate {
93*0Sstevel@tonic-gate 	cred_warning_list_t	*cw;
94*0Sstevel@tonic-gate 	if (!cred_warning_list)
95*0Sstevel@tonic-gate 		return (NULL);
96*0Sstevel@tonic-gate 	for (cw = cred_warning_list; cw != NULL; cw = cw->next) {
97*0Sstevel@tonic-gate 		if (strcmp(warn_name, cw->warn_name) != 0)
98*0Sstevel@tonic-gate 			continue;
99*0Sstevel@tonic-gate 		return (cw);
100*0Sstevel@tonic-gate 	}
101*0Sstevel@tonic-gate 	return (NULL);
102*0Sstevel@tonic-gate }
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate /*
105*0Sstevel@tonic-gate  * add a principal to the principal warning list
106*0Sstevel@tonic-gate  */
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate bool_t
109*0Sstevel@tonic-gate kwarn_add_warning_1_svc(kwarn_add_warning_arg *argp,
110*0Sstevel@tonic-gate 			kwarn_add_warning_res *res,
111*0Sstevel@tonic-gate 			struct svc_req *rqstp)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	cred_warning_list_t	*cred_warning;
114*0Sstevel@tonic-gate 	config_entry_list_t *config_entry;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	if (kwarnd_debug) {
117*0Sstevel@tonic-gate 		printf("kwarn_add_warning_1_svc start; cWlist=%p\n",
118*0Sstevel@tonic-gate 		    cred_warning_list);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 		printf("kwarn_add_warning_1_svc: principal %s",
121*0Sstevel@tonic-gate 		    argp->warning_name);
122*0Sstevel@tonic-gate 		printf(" exp time: %d\n", argp->cred_exp_time);
123*0Sstevel@tonic-gate 	}
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate /*
126*0Sstevel@tonic-gate  *  if there is no entry in the config file that matches the principal to
127*0Sstevel@tonic-gate  *  be added to the warning list, return true because we are not going to
128*0Sstevel@tonic-gate  *  send a warning for this principal.
129*0Sstevel@tonic-gate  */
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	if ((config_entry = find_warning_info(argp->warning_name)) == NULL) {
132*0Sstevel@tonic-gate 		if (kwarnd_debug)
133*0Sstevel@tonic-gate 			printf(
134*0Sstevel@tonic-gate 		"kwarn_add_warning_1_svc find_warn_info: fails, cWlist=%p\n",
135*0Sstevel@tonic-gate 				cred_warning_list);
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 		return (TRUE);
138*0Sstevel@tonic-gate 	}
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate /*
141*0Sstevel@tonic-gate  * see if a warning has already been created for this principal, if so
142*0Sstevel@tonic-gate  * update the warning time.
143*0Sstevel@tonic-gate  */
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	rw_wrlock(&cred_lock);
146*0Sstevel@tonic-gate 	if (cred_warning = find_cred_warning(argp->warning_name)) {
147*0Sstevel@tonic-gate 		rw_unlock(&cred_lock);
148*0Sstevel@tonic-gate 		mutex_lock(&cred_warning->cwm);
149*0Sstevel@tonic-gate 		cred_warning->cred_exp_time = argp->cred_exp_time;
150*0Sstevel@tonic-gate 		cred_warning->cred_warn_time = argp->cred_exp_time
151*0Sstevel@tonic-gate 			- config_entry->seconds_to_warn;
152*0Sstevel@tonic-gate 		mutex_unlock(&cred_warning->cwm);
153*0Sstevel@tonic-gate 	} else {
154*0Sstevel@tonic-gate 		cred_warning = (cred_warning_list_t *)malloc(
155*0Sstevel@tonic-gate 				sizeof (*cred_warning_list));
156*0Sstevel@tonic-gate 		if (cred_warning == NULL) {
157*0Sstevel@tonic-gate 			rw_unlock(&cred_lock);
158*0Sstevel@tonic-gate 			res->status = 1;
159*0Sstevel@tonic-gate 			return (FALSE);
160*0Sstevel@tonic-gate 		}
161*0Sstevel@tonic-gate 		(void) memset((char *)cred_warning, 0,
162*0Sstevel@tonic-gate 			    sizeof (*cred_warning_list));
163*0Sstevel@tonic-gate 		cred_warning->cred_exp_time = argp->cred_exp_time;
164*0Sstevel@tonic-gate 		cred_warning->cred_warn_time = argp->cred_exp_time
165*0Sstevel@tonic-gate 			- config_entry->seconds_to_warn;
166*0Sstevel@tonic-gate 		cred_warning->warn_name = strdup(argp->warning_name);
167*0Sstevel@tonic-gate 		if (cred_warning->warn_name == NULL) {
168*0Sstevel@tonic-gate 			free(cred_warning);
169*0Sstevel@tonic-gate 			rw_unlock(&cred_lock);
170*0Sstevel@tonic-gate 			res->status = 1;
171*0Sstevel@tonic-gate 			return (FALSE);
172*0Sstevel@tonic-gate 		}
173*0Sstevel@tonic-gate 		mutex_init(&cred_warning->cwm,  USYNC_THREAD, NULL);
174*0Sstevel@tonic-gate 		cred_warning->next = cred_warning_list;
175*0Sstevel@tonic-gate 		cred_warning_list = cred_warning;
176*0Sstevel@tonic-gate 		rw_unlock(&cred_lock);
177*0Sstevel@tonic-gate 	}
178*0Sstevel@tonic-gate 	res->status = 0;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	if (kwarnd_debug)
181*0Sstevel@tonic-gate 		printf(
182*0Sstevel@tonic-gate 		"kwarn_add_warning_1_svc end: returns true; cWlist=%p\n",
183*0Sstevel@tonic-gate 		cred_warning_list);
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	return (TRUE);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate /*
189*0Sstevel@tonic-gate  * delete a warning request for a given principal
190*0Sstevel@tonic-gate  */
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate bool_t
193*0Sstevel@tonic-gate kwarn_del_warning_1_svc(kwarn_del_warning_arg *argp,
194*0Sstevel@tonic-gate 			kwarn_del_warning_res *res,
195*0Sstevel@tonic-gate 			struct svc_req *rqstp)
196*0Sstevel@tonic-gate {
197*0Sstevel@tonic-gate 	if (kwarnd_debug)
198*0Sstevel@tonic-gate 		printf(gettext("delete principal %s requested\n"),
199*0Sstevel@tonic-gate 		    argp->warning_name);
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	if (del_warning_pvt(argp->warning_name) == TRUE) {
202*0Sstevel@tonic-gate 		res->status = 0;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 		if (kwarnd_debug)
205*0Sstevel@tonic-gate 			printf(gettext("delete principal %s completed\n"),
206*0Sstevel@tonic-gate 			    argp->warning_name);
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 		return (TRUE);
209*0Sstevel@tonic-gate 	} else {
210*0Sstevel@tonic-gate 		res->status = 1;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 		if (kwarnd_debug)
213*0Sstevel@tonic-gate 			printf(gettext("delete principal %s failed\n"),
214*0Sstevel@tonic-gate 				argp->warning_name);
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 		return (TRUE);
217*0Sstevel@tonic-gate 	}
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate static bool_t
221*0Sstevel@tonic-gate del_warning_pvt(char *warning_name)
222*0Sstevel@tonic-gate {
223*0Sstevel@tonic-gate 	cred_warning_list_t	*cred_warning, *prev;
224*0Sstevel@tonic-gate 	rw_wrlock(&cred_lock);
225*0Sstevel@tonic-gate 	for (prev = NULL, cred_warning = cred_warning_list;
226*0Sstevel@tonic-gate 		cred_warning != NULL; prev = cred_warning,
227*0Sstevel@tonic-gate 		cred_warning = cred_warning->next) {
228*0Sstevel@tonic-gate 		if (strcmp(cred_warning->warn_name, warning_name) == 0) {
229*0Sstevel@tonic-gate 			if (!prev)
230*0Sstevel@tonic-gate 				cred_warning_list = cred_warning->next;
231*0Sstevel@tonic-gate 			else
232*0Sstevel@tonic-gate 				prev->next = cred_warning->next;
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 			free(cred_warning->warn_name);
235*0Sstevel@tonic-gate 			free(cred_warning);
236*0Sstevel@tonic-gate 			rw_unlock(&cred_lock);
237*0Sstevel@tonic-gate 			return (TRUE);
238*0Sstevel@tonic-gate 		}
239*0Sstevel@tonic-gate 	}
240*0Sstevel@tonic-gate 	rw_unlock(&cred_lock);
241*0Sstevel@tonic-gate 	return (FALSE);
242*0Sstevel@tonic-gate }
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate /*
245*0Sstevel@tonic-gate  * load the warn.conf file into the config_entry list.
246*0Sstevel@tonic-gate  */
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate bool_t
249*0Sstevel@tonic-gate loadConfigFile(void)
250*0Sstevel@tonic-gate {
251*0Sstevel@tonic-gate 	char	buffer[BUFSIZ];
252*0Sstevel@tonic-gate 	FILE	*cfgfile;
253*0Sstevel@tonic-gate 	bool_t	retval = TRUE;
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	if ((cfgfile = fopen(CONF_FILENAME, "r")) == NULL) {
256*0Sstevel@tonic-gate 		syslog(LOG_ERR, gettext(
257*0Sstevel@tonic-gate 			"could not open config file \"%s\"\n"),
258*0Sstevel@tonic-gate 			CONF_FILENAME);
259*0Sstevel@tonic-gate 		syslog(LOG_ERR, gettext(
260*0Sstevel@tonic-gate 			"using default options \"%s\"\n"),
261*0Sstevel@tonic-gate 			DEFAULT_CONFIG);
262*0Sstevel@tonic-gate 		retval = parseConfigLine(DEFAULT_CONFIG);
263*0Sstevel@tonic-gate 	} else {
264*0Sstevel@tonic-gate 		(void) memset(buffer, 0, sizeof (buffer));
265*0Sstevel@tonic-gate 		while ((fgets(buffer, BUFSIZ, cfgfile) != NULL) &&
266*0Sstevel@tonic-gate 			(retval == TRUE))
267*0Sstevel@tonic-gate 			retval = parseConfigLine(buffer);
268*0Sstevel@tonic-gate 		fclose(cfgfile);
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 	return (retval);
271*0Sstevel@tonic-gate }
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate /*
274*0Sstevel@tonic-gate  * Return TRUE if we get a valid opt and update flags appro.
275*0Sstevel@tonic-gate  */
276*0Sstevel@tonic-gate static bool_t
277*0Sstevel@tonic-gate cmp_renew_opts(char *opt,
278*0Sstevel@tonic-gate 	    int *log_success, /* out */
279*0Sstevel@tonic-gate 	    int *log_failure) /* out */
280*0Sstevel@tonic-gate {
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if (strncasecmp(opt, "log",
283*0Sstevel@tonic-gate 			sizeof ("log")) == 0) {
284*0Sstevel@tonic-gate 		*log_success = *log_failure = 1;
285*0Sstevel@tonic-gate 	} else if (strncasecmp(opt, "log-success",
286*0Sstevel@tonic-gate 			    sizeof ("log-success")) == 0) {
287*0Sstevel@tonic-gate 		*log_success = 1;
288*0Sstevel@tonic-gate 	} else if (strncasecmp(opt, "log-failure",
289*0Sstevel@tonic-gate 			    sizeof ("log-failure")) == 0) {
290*0Sstevel@tonic-gate 		*log_failure = 1;
291*0Sstevel@tonic-gate 	} else {
292*0Sstevel@tonic-gate 		if (kwarnd_debug)
293*0Sstevel@tonic-gate 			printf("cmp_renew_opts: renew bad opt=`%s'\n",
294*0Sstevel@tonic-gate 			    opt ? opt : "null");
295*0Sstevel@tonic-gate 		return (FALSE);
296*0Sstevel@tonic-gate 	}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	return (TRUE);
299*0Sstevel@tonic-gate }
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate /*
302*0Sstevel@tonic-gate  * Make the config_entry item for the config_entry_list, based on
303*0Sstevel@tonic-gate  * buffer.  The formats are
304*0Sstevel@tonic-gate  *
305*0Sstevel@tonic-gate  *    <principal> [renew[:<opt1,...optN>]] syslog|terminal <time>
306*0Sstevel@tonic-gate  *    <principal> [renew[:<opt1,...optN>]] mail <time> <e-mail address>
307*0Sstevel@tonic-gate  *
308*0Sstevel@tonic-gate  * where renew opts will be:
309*0Sstevel@tonic-gate  *
310*0Sstevel@tonic-gate  *     log-success
311*0Sstevel@tonic-gate  *		- Log the result of the renew attempt on success using
312*0Sstevel@tonic-gate  *		  the specified method (syslog|terminal|mail)
313*0Sstevel@tonic-gate  *
314*0Sstevel@tonic-gate  *      log-failure
315*0Sstevel@tonic-gate  *		- Log the result of the renew attempt on failure using
316*0Sstevel@tonic-gate  *		  the specified method (syslog|terminal|mail)
317*0Sstevel@tonic-gate  *
318*0Sstevel@tonic-gate  *      log
319*0Sstevel@tonic-gate  *               - Same as specifing both log-failure and log-success
320*0Sstevel@tonic-gate  *
321*0Sstevel@tonic-gate  *		  Note if no log options are given, there will be no logging.
322*0Sstevel@tonic-gate  *
323*0Sstevel@tonic-gate  */
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate static bool_t
326*0Sstevel@tonic-gate parseConfigLine(char *buffer)
327*0Sstevel@tonic-gate {
328*0Sstevel@tonic-gate 	char *principal, *send_to, *emailid, *ends, *tm;
329*0Sstevel@tonic-gate 	char			*exptime;
330*0Sstevel@tonic-gate 	int			time_mode;
331*0Sstevel@tonic-gate 	time_t			etime;
332*0Sstevel@tonic-gate 	config_entry_list_t	*config_entry;
333*0Sstevel@tonic-gate 	int renew = 0;
334*0Sstevel@tonic-gate 	int log_success = 0;
335*0Sstevel@tonic-gate 	int log_failure = 0;
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	/* ignore comments */
338*0Sstevel@tonic-gate 	if (*buffer == '#')
339*0Sstevel@tonic-gate 		return (TRUE);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	if (kwarnd_debug)
342*0Sstevel@tonic-gate 		printf("parseconf: buffer=%s", buffer);
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	/* find end of principal */
345*0Sstevel@tonic-gate 	principal = buffer;
346*0Sstevel@tonic-gate 	for (send_to = buffer; *send_to && !isspace(*send_to);
347*0Sstevel@tonic-gate 		send_to++);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	/* find first non whitespace after principal (start of send_to) */
350*0Sstevel@tonic-gate 	if (*send_to) {
351*0Sstevel@tonic-gate 		*send_to = '\0';
352*0Sstevel@tonic-gate 		send_to++;
353*0Sstevel@tonic-gate 		while (*send_to && isspace(*send_to))
354*0Sstevel@tonic-gate 			send_to++;
355*0Sstevel@tonic-gate 	}
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	/* if no send_to, continue, bad entry */
358*0Sstevel@tonic-gate 	if (! *send_to)
359*0Sstevel@tonic-gate 		return (TRUE);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	/* find end of send_to */
362*0Sstevel@tonic-gate 	for (ends = send_to; *ends && !isspace(*ends);
363*0Sstevel@tonic-gate 		ends++);
364*0Sstevel@tonic-gate 	if (*ends)
365*0Sstevel@tonic-gate 		*ends = '\0';
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	if (strchr(send_to, ':')) {
369*0Sstevel@tonic-gate 		/* we've got renew opts */
370*0Sstevel@tonic-gate 		char *st = NULL, *op = NULL;
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 		op = strdup(send_to);
373*0Sstevel@tonic-gate 		if (!op)
374*0Sstevel@tonic-gate 			return (FALSE);
375*0Sstevel@tonic-gate 		st = strchr(op, ':');
376*0Sstevel@tonic-gate 		*st = '\0';
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 		if (strncasecmp(op, "renew", sizeof ("renew")) == 0) {
379*0Sstevel@tonic-gate 			renew = 1;
380*0Sstevel@tonic-gate 		} else {
381*0Sstevel@tonic-gate 			free(op);
382*0Sstevel@tonic-gate 			/* got a ':' but not preceeded w/renew, badent, skip */
383*0Sstevel@tonic-gate 			if (kwarnd_debug)
384*0Sstevel@tonic-gate 				printf("parseconf: colon badent, skip\n");
385*0Sstevel@tonic-gate 			return (TRUE);
386*0Sstevel@tonic-gate 		}
387*0Sstevel@tonic-gate 		free(op);
388*0Sstevel@tonic-gate 		op = NULL;
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 		st++;
391*0Sstevel@tonic-gate 		if (!st || !*st || isspace(*st)) {
392*0Sstevel@tonic-gate 			if (kwarnd_debug)
393*0Sstevel@tonic-gate 				printf("parseconf: st badent, skip\n");
394*0Sstevel@tonic-gate 			/* bad ent, skip */
395*0Sstevel@tonic-gate 			return (TRUE);
396*0Sstevel@tonic-gate 		}
397*0Sstevel@tonic-gate 		if (renew && strchr(st, ',')) {
398*0Sstevel@tonic-gate 			while (1) {
399*0Sstevel@tonic-gate 				/* loop thru comma seperated list-o-opts */
400*0Sstevel@tonic-gate 				char *comma = NULL, *c = NULL, *l = NULL;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 				if (st && (comma = strchr(st, ','))) {
403*0Sstevel@tonic-gate 					l = strdup(st);
404*0Sstevel@tonic-gate 					if (!l)
405*0Sstevel@tonic-gate 						return (FALSE);
406*0Sstevel@tonic-gate 					c = strchr(l, ',');
407*0Sstevel@tonic-gate 					*c = '\0';
408*0Sstevel@tonic-gate 					if (!cmp_renew_opts(l, &log_success,
409*0Sstevel@tonic-gate 							    &log_failure)) {
410*0Sstevel@tonic-gate 						free(l);
411*0Sstevel@tonic-gate 						/* badent, skip */
412*0Sstevel@tonic-gate 						return (TRUE);
413*0Sstevel@tonic-gate 					}
414*0Sstevel@tonic-gate 					free(l);
415*0Sstevel@tonic-gate 					l = NULL;
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 					st = comma;
418*0Sstevel@tonic-gate 					st++;
419*0Sstevel@tonic-gate 				} else {
420*0Sstevel@tonic-gate 					if (st) {
421*0Sstevel@tonic-gate 						if (!cmp_renew_opts(st,
422*0Sstevel@tonic-gate 							    &log_success,
423*0Sstevel@tonic-gate 							    &log_failure)) {
424*0Sstevel@tonic-gate 							/* badent, skip */
425*0Sstevel@tonic-gate 							return (TRUE);
426*0Sstevel@tonic-gate 						}
427*0Sstevel@tonic-gate 					}
428*0Sstevel@tonic-gate 					break;
429*0Sstevel@tonic-gate 				}
430*0Sstevel@tonic-gate 			} /* while */
431*0Sstevel@tonic-gate 		} else if (st) {
432*0Sstevel@tonic-gate 			/* we just have one opt */
433*0Sstevel@tonic-gate 			if (!cmp_renew_opts(st, &log_success, &log_failure)) {
434*0Sstevel@tonic-gate 				/* badent, skip */
435*0Sstevel@tonic-gate 				return (TRUE);
436*0Sstevel@tonic-gate 			}
437*0Sstevel@tonic-gate 		}
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 		/* if send_to is "renew", note it and refind send_to */
440*0Sstevel@tonic-gate 	} else if (strncasecmp(send_to, "renew",
441*0Sstevel@tonic-gate 			    sizeof ("renew")) == 0) {
442*0Sstevel@tonic-gate 		renew = 1;
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	}
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	if (kwarnd_debug) {
447*0Sstevel@tonic-gate 		printf("parseconf: renew=%d, log failure=%d, log success=%d\n",
448*0Sstevel@tonic-gate 		    renew, log_failure, log_success);
449*0Sstevel@tonic-gate 	}
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	if (renew) {
452*0Sstevel@tonic-gate 		/* find first non whitespace after send_to (start of exptime) */
453*0Sstevel@tonic-gate 		for (send_to = ends+1; *send_to && isspace(*send_to);
454*0Sstevel@tonic-gate 		    send_to++);
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 		/* if no send_to, continue, bad entry */
457*0Sstevel@tonic-gate 		if (! *send_to) {
458*0Sstevel@tonic-gate 			if (kwarnd_debug)
459*0Sstevel@tonic-gate 				printf("parseconf: no send_to, badent, skip\n");
460*0Sstevel@tonic-gate 			return (TRUE);
461*0Sstevel@tonic-gate 		}
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 		/* find end of send_to */
464*0Sstevel@tonic-gate 		for (ends = send_to; *ends && !isspace(*ends);
465*0Sstevel@tonic-gate 		    ends++);
466*0Sstevel@tonic-gate 		if (*ends)
467*0Sstevel@tonic-gate 			*ends = '\0';
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	/* find first non whitespace after send_to (start of exptime) */
472*0Sstevel@tonic-gate 	for (exptime = ends+1; *exptime && isspace(*exptime);
473*0Sstevel@tonic-gate 		exptime++);
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	/* if no exptime, continue, bad entry */
476*0Sstevel@tonic-gate 	if (! *exptime) {
477*0Sstevel@tonic-gate 		if (kwarnd_debug)
478*0Sstevel@tonic-gate 			printf("parseconf: no exptime, badent, skip\n");
479*0Sstevel@tonic-gate 		return (TRUE);
480*0Sstevel@tonic-gate 	}
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	/* find end of exptime */
483*0Sstevel@tonic-gate 	for (ends = exptime; *ends && !isspace(*ends); ends++);
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	tm = ends - 1;
486*0Sstevel@tonic-gate 	if (*tm == 's')
487*0Sstevel@tonic-gate 		time_mode = 1;
488*0Sstevel@tonic-gate 	else if (*tm == 'm')
489*0Sstevel@tonic-gate 		time_mode = 2;
490*0Sstevel@tonic-gate 	else if (*tm == 'h')
491*0Sstevel@tonic-gate 		time_mode = 3;
492*0Sstevel@tonic-gate 	else
493*0Sstevel@tonic-gate 		time_mode = 1;
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	if (*tm)
496*0Sstevel@tonic-gate 		*tm = '\0';
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	if (kwarnd_debug) {
499*0Sstevel@tonic-gate 		printf("parseconf: send_to = '%s', exptime='%s'\n",
500*0Sstevel@tonic-gate 		    send_to, exptime);
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	/* find first non whitespace after exptime (start of emailid) */
504*0Sstevel@tonic-gate 	for (emailid = ends+1; *emailid && isspace(*emailid); emailid++);
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	/* find end of emailid */
507*0Sstevel@tonic-gate 	if (*emailid) {
508*0Sstevel@tonic-gate 		for (ends = emailid; *ends && !isspace(*ends);
509*0Sstevel@tonic-gate 			ends++);
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 		if (*ends)
512*0Sstevel@tonic-gate 			*ends = '\0';
513*0Sstevel@tonic-gate 	}
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	/* if send to mail and no mail address, bad entry */
516*0Sstevel@tonic-gate 	if ((strcmp(send_to, "mail") == 0) && (!*emailid)) {
517*0Sstevel@tonic-gate 		if (kwarnd_debug)
518*0Sstevel@tonic-gate 			printf("parseconf: returns true; no mail addr\n");
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 		syslog(LOG_ERR, gettext("missing mail address"
521*0Sstevel@tonic-gate 			" in config entry: \n%s %s %s "
522*0Sstevel@tonic-gate 			" cannot mail warning"), principal,
523*0Sstevel@tonic-gate 			send_to, exptime);
524*0Sstevel@tonic-gate 		return (TRUE);
525*0Sstevel@tonic-gate 	}
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	/* create an entry */
528*0Sstevel@tonic-gate 	config_entry = (config_entry_list_t *)
529*0Sstevel@tonic-gate 		malloc(sizeof (*config_entry_list));
530*0Sstevel@tonic-gate 	if (config_entry == NULL)
531*0Sstevel@tonic-gate 		return (FALSE);
532*0Sstevel@tonic-gate 	(void) memset(config_entry, 0, sizeof (*config_entry_list));
533*0Sstevel@tonic-gate 	config_entry->principal = strdup(principal);
534*0Sstevel@tonic-gate 	if (config_entry->principal == NULL)
535*0Sstevel@tonic-gate 		return (FALSE);
536*0Sstevel@tonic-gate 	config_entry->where_to = strdup(send_to);
537*0Sstevel@tonic-gate 	if (config_entry->where_to == NULL)
538*0Sstevel@tonic-gate 		return (FALSE);
539*0Sstevel@tonic-gate 	etime = atol(exptime);
540*0Sstevel@tonic-gate 	if (time_mode == 1)
541*0Sstevel@tonic-gate 		config_entry->seconds_to_warn = etime;
542*0Sstevel@tonic-gate 	else if (time_mode == 2)
543*0Sstevel@tonic-gate 		config_entry->seconds_to_warn = etime * 60;
544*0Sstevel@tonic-gate 	else if (time_mode == 3)
545*0Sstevel@tonic-gate 		config_entry->seconds_to_warn = etime * 60 * 60;
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	if (*emailid) {
548*0Sstevel@tonic-gate 		config_entry->email = strdup(emailid);
549*0Sstevel@tonic-gate 		if (config_entry->email == NULL)
550*0Sstevel@tonic-gate 			return (FALSE);
551*0Sstevel@tonic-gate 	}
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 	config_entry->renew = renew;
554*0Sstevel@tonic-gate 	config_entry->log_success = log_success;
555*0Sstevel@tonic-gate 	config_entry->log_failure = log_failure;
556*0Sstevel@tonic-gate 	config_entry->next = config_entry_list;
557*0Sstevel@tonic-gate 	config_entry_list = config_entry;
558*0Sstevel@tonic-gate 	if (kwarnd_debug)
559*0Sstevel@tonic-gate 		printf("parseconf: returns true; celist=%p\n",
560*0Sstevel@tonic-gate 		    config_entry_list);
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	return (TRUE);
563*0Sstevel@tonic-gate }
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate /*
566*0Sstevel@tonic-gate  * find a specific warn.conf entry.
567*0Sstevel@tonic-gate  */
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate static config_entry_list_t *
570*0Sstevel@tonic-gate find_warning_info(char *principal)
571*0Sstevel@tonic-gate {
572*0Sstevel@tonic-gate 	config_entry_list_t	*config_entry;
573*0Sstevel@tonic-gate 	/* look for a specific entry */
574*0Sstevel@tonic-gate 	for (config_entry = config_entry_list; config_entry;
575*0Sstevel@tonic-gate 		config_entry = config_entry->next) {
576*0Sstevel@tonic-gate 		if (strcmp(config_entry->principal, principal) == 0) {
577*0Sstevel@tonic-gate 			return (config_entry);
578*0Sstevel@tonic-gate 		}
579*0Sstevel@tonic-gate 	}
580*0Sstevel@tonic-gate 	/* look for a wild card entry */
581*0Sstevel@tonic-gate 	for (config_entry = config_entry_list; config_entry;
582*0Sstevel@tonic-gate 		config_entry = config_entry->next) {
583*0Sstevel@tonic-gate 		if (strcmp(config_entry->principal, "*") == 0) {
584*0Sstevel@tonic-gate 			return (config_entry);
585*0Sstevel@tonic-gate 		}
586*0Sstevel@tonic-gate 	}
587*0Sstevel@tonic-gate 	/* nothing found */
588*0Sstevel@tonic-gate 	return (NULL);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate }
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate /*
593*0Sstevel@tonic-gate  * create a pipe, fork and exec a command,
594*0Sstevel@tonic-gate  */
595*0Sstevel@tonic-gate static FILE *
596*0Sstevel@tonic-gate safe_popen_w(char *path_to_cmd, char **argv)
597*0Sstevel@tonic-gate {
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 	int fd[2];
600*0Sstevel@tonic-gate 	FILE *fp;
601*0Sstevel@tonic-gate 	char *envp[2];
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	if (pipe(fd) == -1)
604*0Sstevel@tonic-gate 		return (NULL);
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	switch (fork()) {
608*0Sstevel@tonic-gate 	case -1:
609*0Sstevel@tonic-gate 		(void) close(fd[0]);
610*0Sstevel@tonic-gate 		(void) close(fd[1]);
611*0Sstevel@tonic-gate 		return (NULL);
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 	case 0:
614*0Sstevel@tonic-gate 		close(fd[1]);
615*0Sstevel@tonic-gate 		/* fd[0] is the end we read from */
616*0Sstevel@tonic-gate 		if (fd[0] != 0) {
617*0Sstevel@tonic-gate 			close(0);
618*0Sstevel@tonic-gate 			dup(fd[0]);
619*0Sstevel@tonic-gate 		}
620*0Sstevel@tonic-gate 		close(1);
621*0Sstevel@tonic-gate 		close(2);
622*0Sstevel@tonic-gate 		envp[0] = "PATH=/usr/bin";
623*0Sstevel@tonic-gate 		envp[1] = NULL;
624*0Sstevel@tonic-gate #ifdef	DEBUG
625*0Sstevel@tonic-gate 		{
626*0Sstevel@tonic-gate 			int fd;
627*0Sstevel@tonic-gate 			fd = open("/tmp/kwarn.out", O_WRONLY|O_TRUNC|O_CREAT,
628*0Sstevel@tonic-gate 				0666);
629*0Sstevel@tonic-gate 			if (fd != 1)
630*0Sstevel@tonic-gate 				dup(fd);
631*0Sstevel@tonic-gate 			if (fd != 2)
632*0Sstevel@tonic-gate 				dup(fd);
633*0Sstevel@tonic-gate 		}
634*0Sstevel@tonic-gate #endif
635*0Sstevel@tonic-gate 		(void) execve(path_to_cmd, argv, envp);
636*0Sstevel@tonic-gate 		syslog(LOG_ERR, "warnd: %m");
637*0Sstevel@tonic-gate 		_exit(1);
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	default:
640*0Sstevel@tonic-gate 		close(fd[0]);
641*0Sstevel@tonic-gate 		/* fd[1] is the end we write to */
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 		fp = fdopen(fd[1], "w");
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 		if (fp == NULL) {
646*0Sstevel@tonic-gate 			(void) close(fd[1]);
647*0Sstevel@tonic-gate 			return (NULL);
648*0Sstevel@tonic-gate 		}
649*0Sstevel@tonic-gate 		return (fp);
650*0Sstevel@tonic-gate 	}
651*0Sstevel@tonic-gate }
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate static uid_t gssd_uid;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate void
657*0Sstevel@tonic-gate set_warnd_uid(uid_t uid)
658*0Sstevel@tonic-gate {
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 	/*
661*0Sstevel@tonic-gate 	 * set the value of gssd_uid, so it can be retrieved when getuid()
662*0Sstevel@tonic-gate 	 * is called by the underlying mechanism libraries
663*0Sstevel@tonic-gate 	 */
664*0Sstevel@tonic-gate 	if (kwarnd_debug)
665*0Sstevel@tonic-gate 		printf("set_warnd_uid called with uid = %d\n", uid);
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	gssd_uid = uid;
668*0Sstevel@tonic-gate }
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate uid_t
671*0Sstevel@tonic-gate getuid(void)
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate {
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	/*
676*0Sstevel@tonic-gate 	 * return the value set when one of the gssd procedures was
677*0Sstevel@tonic-gate 	 * entered. This is the value of the uid under which the
678*0Sstevel@tonic-gate 	 * underlying mechanism library must operate in order to
679*0Sstevel@tonic-gate 	 * get the user's credentials. This call is necessary since
680*0Sstevel@tonic-gate 	 * gssd runs as root and credentials are many times stored
681*0Sstevel@tonic-gate 	 * in files and directories specific to the user
682*0Sstevel@tonic-gate 	 */
683*0Sstevel@tonic-gate 	if (kwarnd_debug)
684*0Sstevel@tonic-gate 		printf("getuid called and returning gsssd_uid = %d\n",
685*0Sstevel@tonic-gate 		    gssd_uid);
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	return (gssd_uid);
688*0Sstevel@tonic-gate }
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate static bool_t
692*0Sstevel@tonic-gate getpruid(char *pr, uid_t *uid)
693*0Sstevel@tonic-gate {
694*0Sstevel@tonic-gate 	char *rcp1 = NULL, *rcp2 = NULL, *rcp3 = NULL;
695*0Sstevel@tonic-gate 	struct passwd *pw;
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	rcp1 = strdup(pr);
698*0Sstevel@tonic-gate 	if (!rcp1)
699*0Sstevel@tonic-gate 		return (FALSE);
700*0Sstevel@tonic-gate 	rcp2 = strtok(rcp1, "@");
701*0Sstevel@tonic-gate 	rcp3 = strtok(rcp2, "/");
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 	if (rcp3) {
704*0Sstevel@tonic-gate 		pw = getpwnam(rcp3);
705*0Sstevel@tonic-gate 		*uid = pw->pw_uid;
706*0Sstevel@tonic-gate 		free(rcp1);
707*0Sstevel@tonic-gate 		return (TRUE);
708*0Sstevel@tonic-gate 	}
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 	free(rcp1);
711*0Sstevel@tonic-gate 	return (FALSE);
712*0Sstevel@tonic-gate }
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate static krb5_error_code
716*0Sstevel@tonic-gate renew_creds(
717*0Sstevel@tonic-gate 	char *princ,
718*0Sstevel@tonic-gate 	time_t *new_exp_time) /* out */
719*0Sstevel@tonic-gate {
720*0Sstevel@tonic-gate 	krb5_creds my_creds;
721*0Sstevel@tonic-gate 	krb5_error_code code = 0;
722*0Sstevel@tonic-gate 	struct k5_data k5;
723*0Sstevel@tonic-gate 	char *progname = "warnd";
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	uid_t saved_u = getuid();
726*0Sstevel@tonic-gate 	uid_t u;
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	if (kwarnd_debug)
729*0Sstevel@tonic-gate 		printf("renew start: uid=%d\n", getuid());
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	if (!getpruid(princ, &u)) {
732*0Sstevel@tonic-gate 		if (kwarnd_debug)
733*0Sstevel@tonic-gate 			printf("renew: getpruid failed, princ='%s'\n",
734*0Sstevel@tonic-gate 			    princ ? princ : "<null>");
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 		return (-1); /* better err num? */
737*0Sstevel@tonic-gate 	}
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 	set_warnd_uid(u);
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	(void) memset(&my_creds, 0, sizeof (my_creds));
742*0Sstevel@tonic-gate 	(void) memset(&k5, 0, sizeof (k5));
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	if (code = krb5_init_context(&k5.ctx)) {
745*0Sstevel@tonic-gate 		com_err(progname, code,
746*0Sstevel@tonic-gate 			gettext("while initializing Kerberos 5 library"));
747*0Sstevel@tonic-gate 		goto out;
748*0Sstevel@tonic-gate 	}
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	if ((code = krb5_cc_default(k5.ctx, &k5.cc))) {
751*0Sstevel@tonic-gate 		com_err(progname, code,
752*0Sstevel@tonic-gate 			gettext("while getting default ccache"));
753*0Sstevel@tonic-gate 		goto out;
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	}
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 	if ((code = krb5_parse_name(k5.ctx, princ,
758*0Sstevel@tonic-gate 				    &k5.me))) {
759*0Sstevel@tonic-gate 		com_err(progname, code, gettext("when parsing name %s"),
760*0Sstevel@tonic-gate 			princ);
761*0Sstevel@tonic-gate 		goto out;
762*0Sstevel@tonic-gate 	}
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	if ((code = krb5_get_renewed_creds(k5.ctx, &my_creds, k5.me, k5.cc,
765*0Sstevel@tonic-gate 					NULL))) {
766*0Sstevel@tonic-gate 		com_err(progname, code, gettext("while renewing creds"));
767*0Sstevel@tonic-gate 		goto out;
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	if (code = krb5_cc_initialize(k5.ctx, k5.cc, k5.me)) {
771*0Sstevel@tonic-gate 		com_err(progname, code, gettext("when initializing cache %s"),
772*0Sstevel@tonic-gate 			"defcc");
773*0Sstevel@tonic-gate 		goto out;
774*0Sstevel@tonic-gate 	}
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	if (code = krb5_cc_store_cred(k5.ctx, k5.cc, &my_creds)) {
777*0Sstevel@tonic-gate 		com_err(progname, code, gettext("while storing credentials"));
778*0Sstevel@tonic-gate 		goto out;
779*0Sstevel@tonic-gate 	}
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate 	/* "return" new expire time */
782*0Sstevel@tonic-gate 	*new_exp_time = my_creds.times.endtime;
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate out:
785*0Sstevel@tonic-gate 	krb5_free_cred_contents(k5.ctx, &my_creds);
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	if (k5.name)
788*0Sstevel@tonic-gate 		krb5_free_unparsed_name(k5.ctx, k5.name);
789*0Sstevel@tonic-gate 	if (k5.me)
790*0Sstevel@tonic-gate 		krb5_free_principal(k5.ctx, k5.me);
791*0Sstevel@tonic-gate 	if (k5.cc)
792*0Sstevel@tonic-gate 		krb5_cc_close(k5.ctx, k5.cc);
793*0Sstevel@tonic-gate 	if (k5.ctx)
794*0Sstevel@tonic-gate 		krb5_free_context(k5.ctx);
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	set_warnd_uid(saved_u);
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate 	if (kwarnd_debug)
799*0Sstevel@tonic-gate 		printf("renew end: code=%s, uid=%d\n", error_message(code),
800*0Sstevel@tonic-gate 		    getuid());
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 	return (code);
803*0Sstevel@tonic-gate }
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate static bool_t
806*0Sstevel@tonic-gate loggedon(char *name)
807*0Sstevel@tonic-gate {
808*0Sstevel@tonic-gate 	register struct utmpx *ubuf;
809*0Sstevel@tonic-gate 	char    *rcp1 = NULL, *rcp2 = NULL, *rcp3 = NULL;
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	/*
812*0Sstevel@tonic-gate 	 * strip any realm or instance from principal so we can match
813*0Sstevel@tonic-gate 	 * against unix userid.
814*0Sstevel@tonic-gate 	 */
815*0Sstevel@tonic-gate 	rcp1 = strdup(name);
816*0Sstevel@tonic-gate 	if (!rcp1)
817*0Sstevel@tonic-gate 		return (FALSE);
818*0Sstevel@tonic-gate 	rcp2 = strtok(rcp1, "@");
819*0Sstevel@tonic-gate 	rcp3 = strtok(rcp2, "/");
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	/*
822*0Sstevel@tonic-gate 	 * Scan through the "utmpx" file for the
823*0Sstevel@tonic-gate 	 * entry for the person we want to send to.
824*0Sstevel@tonic-gate 	 */
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate 	setutxent();
827*0Sstevel@tonic-gate 	while ((ubuf = getutxent()) != NULL) {
828*0Sstevel@tonic-gate 		if (ubuf->ut_type == USER_PROCESS) {
829*0Sstevel@tonic-gate 			if (strncmp(rcp3, ubuf->ut_user,
830*0Sstevel@tonic-gate 				    sizeof (ubuf->ut_user)) == 0) {
831*0Sstevel@tonic-gate 				free(rcp1);
832*0Sstevel@tonic-gate 				endutxent();
833*0Sstevel@tonic-gate 				return (TRUE);
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 			}
836*0Sstevel@tonic-gate 		}
837*0Sstevel@tonic-gate 	}
838*0Sstevel@tonic-gate 	free(rcp1);
839*0Sstevel@tonic-gate 	endutxent();
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate 	if (kwarnd_debug)
842*0Sstevel@tonic-gate 		printf("loggedon: returning false for user `%s'\n", rcp1);
843*0Sstevel@tonic-gate 
844*0Sstevel@tonic-gate 	return (FALSE);
845*0Sstevel@tonic-gate }
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate /*
848*0Sstevel@tonic-gate  * main loop to check the cred warning list and send the warnings
849*0Sstevel@tonic-gate  * the appropriate location based on warn.conf or auto-renew creds.
850*0Sstevel@tonic-gate  */
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate void
853*0Sstevel@tonic-gate kwarnd_check_warning_list(void)
854*0Sstevel@tonic-gate { /* func */
855*0Sstevel@tonic-gate 	cred_warning_list_t	*cw;  /* cred warning */
856*0Sstevel@tonic-gate 	config_entry_list_t	*ce;  /* config entry */
857*0Sstevel@tonic-gate 	time_t			now;
858*0Sstevel@tonic-gate 	int			minutes;
859*0Sstevel@tonic-gate 	char			buff[256];
860*0Sstevel@tonic-gate 	char			cmdline[256];
861*0Sstevel@tonic-gate 	FILE			*fp;
862*0Sstevel@tonic-gate 	char			*subj = "Kerberos credentials expiring";
863*0Sstevel@tonic-gate 	char			*renew_subj = "Kerberos credentials renewed";
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 	if (kwarnd_debug)
866*0Sstevel@tonic-gate 		printf("check list: start: getuid=%d, cw list=%p\n", getuid(),
867*0Sstevel@tonic-gate 			cred_warning_list);
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 	while (1) {
870*0Sstevel@tonic-gate 		(void) poll(NULL, NULL, 60000);
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 		for (cw = cred_warning_list;
873*0Sstevel@tonic-gate 			cw != NULL;
874*0Sstevel@tonic-gate 			cw = cw->next) {
875*0Sstevel@tonic-gate 			int send_msg = 0;
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 			time(&now);
878*0Sstevel@tonic-gate 			if (now >= cw->cred_warn_time) {
879*0Sstevel@tonic-gate 				int renew_attempted = 0;
880*0Sstevel@tonic-gate 				int renew_failed = 0;
881*0Sstevel@tonic-gate 				int renew_tooclose = 0;
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 				if (kwarnd_debug)
884*0Sstevel@tonic-gate 					printf("checklist: now >= warn_t\n");
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 				ce = find_warning_info(cw->warn_name);
887*0Sstevel@tonic-gate 				minutes = (cw->cred_exp_time -
888*0Sstevel@tonic-gate 					now + 59) / 60;
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate 				if (kwarnd_debug)
891*0Sstevel@tonic-gate 					printf("checklist: where_to=%s\n",
892*0Sstevel@tonic-gate 					    ce->where_to ?
893*0Sstevel@tonic-gate 					    ce->where_to : "null");
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 				if (ce->renew &&
896*0Sstevel@tonic-gate 				    loggedon(cw->warn_name)) {
897*0Sstevel@tonic-gate 					krb5_error_code code;
898*0Sstevel@tonic-gate 					time_t new_exp_time;
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate 					renew_attempted = 1;
901*0Sstevel@tonic-gate 					code = renew_creds(
902*0Sstevel@tonic-gate 						cw->warn_name,
903*0Sstevel@tonic-gate 						&new_exp_time);
904*0Sstevel@tonic-gate 					if (!code) {
905*0Sstevel@tonic-gate 						/* krb5 api renew success */
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 						/*
908*0Sstevel@tonic-gate 						 * So we had api success
909*0Sstevel@tonic-gate 						 * but the new exp time
910*0Sstevel@tonic-gate 						 * is same as current one
911*0Sstevel@tonic-gate 						 * so we are too close
912*0Sstevel@tonic-gate 						 * to Renewable_life time.
913*0Sstevel@tonic-gate 						 */
914*0Sstevel@tonic-gate 						if (cw->cred_exp_time
915*0Sstevel@tonic-gate 						    == new_exp_time) {
916*0Sstevel@tonic-gate 							renew_tooclose = 1;
917*0Sstevel@tonic-gate 							if (kwarnd_debug)
918*0Sstevel@tonic-gate 								printf(
919*0Sstevel@tonic-gate 		"checklist: new expire time same as old expire time\n");
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 							if (ce->log_failure) {
922*0Sstevel@tonic-gate 								send_msg = 1;
923*0Sstevel@tonic-gate 								snprintf(buff,
924*0Sstevel@tonic-gate 								sizeof (buff),
925*0Sstevel@tonic-gate 					gettext("%s:\r\nYour kerberos"
926*0Sstevel@tonic-gate 					" credentials have not been renewed"
927*0Sstevel@tonic-gate 					" (too close to Renewable_life).\r\n"
928*0Sstevel@tonic-gate 					"Please run kinit(1).\r\n"),
929*0Sstevel@tonic-gate 								cw->warn_name);
930*0Sstevel@tonic-gate 							}
931*0Sstevel@tonic-gate 						} else {
932*0Sstevel@tonic-gate 							/* update times */
933*0Sstevel@tonic-gate 							cw->cred_exp_time =
934*0Sstevel@tonic-gate 								new_exp_time;
935*0Sstevel@tonic-gate 							cw->cred_warn_time =
936*0Sstevel@tonic-gate 							    new_exp_time -
937*0Sstevel@tonic-gate 							    ce->seconds_to_warn;
938*0Sstevel@tonic-gate 						}
939*0Sstevel@tonic-gate 
940*0Sstevel@tonic-gate 						if (kwarnd_debug)
941*0Sstevel@tonic-gate 							printf(
942*0Sstevel@tonic-gate 						    "check list: new_w_t=%d\n",
943*0Sstevel@tonic-gate 						    cw->cred_warn_time);
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 						if (!renew_tooclose &&
946*0Sstevel@tonic-gate 						    ce->log_success) {
947*0Sstevel@tonic-gate 							if (kwarnd_debug)
948*0Sstevel@tonic-gate 								printf(
949*0Sstevel@tonic-gate 						"check list: log success\n");
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 							send_msg = 1;
952*0Sstevel@tonic-gate 							snprintf(buff,
953*0Sstevel@tonic-gate 								sizeof (buff),
954*0Sstevel@tonic-gate 						gettext("%s:\r\nYour kerberos"
955*0Sstevel@tonic-gate 					" credentials have been renewed.\r\n"),
956*0Sstevel@tonic-gate 								cw->warn_name);
957*0Sstevel@tonic-gate 						}
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 					}  /* !(code) */
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 					if (!renew_tooclose && code &&
962*0Sstevel@tonic-gate 					    ce->log_failure) {
963*0Sstevel@tonic-gate 						if (kwarnd_debug)
964*0Sstevel@tonic-gate 							printf(
965*0Sstevel@tonic-gate 						"check list: log FAIL\n");
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 						send_msg = 1;
968*0Sstevel@tonic-gate 						snprintf(buff,
969*0Sstevel@tonic-gate 							sizeof (buff),
970*0Sstevel@tonic-gate 					    gettext("%s:\r\nYour kerberos"
971*0Sstevel@tonic-gate 				" credentials failed to be renewed (%s).\r\n"),
972*0Sstevel@tonic-gate 							cw->warn_name,
973*0Sstevel@tonic-gate 							error_message(code));
974*0Sstevel@tonic-gate 					}
975*0Sstevel@tonic-gate 					renew_failed = code ? 1 : 0;
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate 				} else if (minutes > 0) {
978*0Sstevel@tonic-gate 					send_msg = 1;
979*0Sstevel@tonic-gate 					snprintf(buff, sizeof (buff),
980*0Sstevel@tonic-gate 					gettext("%s:\r\nyour kerberos"
981*0Sstevel@tonic-gate 					" credentials expire in less than"
982*0Sstevel@tonic-gate 					" %d minutes.\r\n"),
983*0Sstevel@tonic-gate 					cw->warn_name,
984*0Sstevel@tonic-gate 					minutes);
985*0Sstevel@tonic-gate 				} else {
986*0Sstevel@tonic-gate 					send_msg = 1;
987*0Sstevel@tonic-gate 					snprintf(buff, sizeof (buff),
988*0Sstevel@tonic-gate 					gettext("%s:\r\nyour kerberos"
989*0Sstevel@tonic-gate 					" credentials have expired.\r\n"),
990*0Sstevel@tonic-gate 					cw->warn_name);
991*0Sstevel@tonic-gate 				}
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 				if (kwarnd_debug)
994*0Sstevel@tonic-gate 					printf("checklist: send_msg=%d\n",
995*0Sstevel@tonic-gate 					    send_msg);
996*0Sstevel@tonic-gate 				if (!send_msg)
997*0Sstevel@tonic-gate 					goto del_warning;
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 				if (strncmp(ce->where_to,
1000*0Sstevel@tonic-gate 					    "mail", sizeof ("mail")) == 0) {
1001*0Sstevel@tonic-gate 					char *argv[3];
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 					argv[0] = MAIL;
1004*0Sstevel@tonic-gate 					(void) snprintf(cmdline,
1005*0Sstevel@tonic-gate 							sizeof (cmdline),
1006*0Sstevel@tonic-gate 							"%s",
1007*0Sstevel@tonic-gate 							ce->email);
1008*0Sstevel@tonic-gate 					argv[1] = cmdline;
1009*0Sstevel@tonic-gate 					argv[2] = NULL;
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 					fp = safe_popen_w(MAILPATH, argv);
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate 					if (fp) {
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate 						(void) fprintf(fp,
1016*0Sstevel@tonic-gate 						"To: %s\nSubject: %s\n\n%s\n",
1017*0Sstevel@tonic-gate 							    ce->email,
1018*0Sstevel@tonic-gate 							    renew_attempted
1019*0Sstevel@tonic-gate 							    ? renew_subj : subj,
1020*0Sstevel@tonic-gate 							    buff);
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate 					    fclose(fp);
1023*0Sstevel@tonic-gate 					} else {
1024*0Sstevel@tonic-gate 					    syslog(LOG_ERR,
1025*0Sstevel@tonic-gate 						gettext("could not fork "
1026*0Sstevel@tonic-gate 						"mail program to e-mail "
1027*0Sstevel@tonic-gate 						"warning to %s\n"),
1028*0Sstevel@tonic-gate 						cmdline);
1029*0Sstevel@tonic-gate 					}
1030*0Sstevel@tonic-gate 
1031*0Sstevel@tonic-gate 				} else if (strncmp(ce->where_to,
1032*0Sstevel@tonic-gate 						"terminal",
1033*0Sstevel@tonic-gate 						sizeof ("terminal")) == 0) {
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 					warn_send(cw->warn_name,
1036*0Sstevel@tonic-gate 						buff);
1037*0Sstevel@tonic-gate 
1038*0Sstevel@tonic-gate 				} else if (send_msg && strncmp(ce->where_to,
1039*0Sstevel@tonic-gate 							    "syslog",
1040*0Sstevel@tonic-gate 						sizeof ("syslog")) == 0) {
1041*0Sstevel@tonic-gate 					syslog(LOG_NOTICE|LOG_AUTH,
1042*0Sstevel@tonic-gate 					    "%s",
1043*0Sstevel@tonic-gate 					    buff);
1044*0Sstevel@tonic-gate #if 0
1045*0Sstevel@tonic-gate 				} else if (strncmp(ce->where_to,
1046*0Sstevel@tonic-gate 						"snmp",
1047*0Sstevel@tonic-gate 						sizeof ("snmp")) == 0) {
1048*0Sstevel@tonic-gate #endif
1049*0Sstevel@tonic-gate 				} else {
1050*0Sstevel@tonic-gate 					if (kwarnd_debug)
1051*0Sstevel@tonic-gate 						printf(
1052*0Sstevel@tonic-gate 						"unknown msg method=`%s'\n",
1053*0Sstevel@tonic-gate 						ce->where_to);
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate 					exit(1);
1056*0Sstevel@tonic-gate 				}
1057*0Sstevel@tonic-gate 
1058*0Sstevel@tonic-gate 			del_warning:
1059*0Sstevel@tonic-gate 				if (!renew_attempted || renew_failed ||
1060*0Sstevel@tonic-gate 				    renew_tooclose) {
1061*0Sstevel@tonic-gate 					if (del_warning_pvt(cw->warn_name)
1062*0Sstevel@tonic-gate 					    == TRUE) {
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 						if (kwarnd_debug)
1065*0Sstevel@tonic-gate 							printf(
1066*0Sstevel@tonic-gate 						"check list: del warn succ\n");
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 						break;
1069*0Sstevel@tonic-gate 					} else {
1070*0Sstevel@tonic-gate 						if (kwarnd_debug)
1071*0Sstevel@tonic-gate 							printf(
1072*0Sstevel@tonic-gate 						"could not delete warning\n");
1073*0Sstevel@tonic-gate 
1074*0Sstevel@tonic-gate 						syslog(LOG_ERR, gettext(
1075*0Sstevel@tonic-gate 						"could not delete warning"));
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate 						exit(1);
1078*0Sstevel@tonic-gate 					    }
1079*0Sstevel@tonic-gate 					}
1080*0Sstevel@tonic-gate 
1081*0Sstevel@tonic-gate 				} /* if (now) */
1082*0Sstevel@tonic-gate 		} /* for */
1083*0Sstevel@tonic-gate 	} /* while */
1084*0Sstevel@tonic-gate }  /* func */
1085