xref: /onnv-gate/usr/src/cmd/krb5/kwarn/kwarnd_proc.c (revision 358:cf6c4bdc7385)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
70Sstevel@tonic-gate 
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate  *  RPC server procedures for the usermode daemon kwarnd.
100Sstevel@tonic-gate  */
110Sstevel@tonic-gate 
120Sstevel@tonic-gate #include <stdio.h>
130Sstevel@tonic-gate #include <unistd.h>
140Sstevel@tonic-gate #include <pwd.h>
150Sstevel@tonic-gate #include <grp.h>
160Sstevel@tonic-gate #include <strings.h>
170Sstevel@tonic-gate #include <string.h>
180Sstevel@tonic-gate #include <sys/param.h>
190Sstevel@tonic-gate #include <sys/syslog.h>
200Sstevel@tonic-gate #include "kwarnd.h"
210Sstevel@tonic-gate #include <rpc/rpc.h>
220Sstevel@tonic-gate #include <stdlib.h>
230Sstevel@tonic-gate #include <syslog.h>
240Sstevel@tonic-gate #include <poll.h>
250Sstevel@tonic-gate #include <utmpx.h>
260Sstevel@tonic-gate #include <pwd.h>
270Sstevel@tonic-gate #include <strings.h>
280Sstevel@tonic-gate #include <ctype.h>
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <k5-int.h>
310Sstevel@tonic-gate #include <profile/prof_int.h>
320Sstevel@tonic-gate #include <com_err.h>
330Sstevel@tonic-gate #include <libintl.h>
340Sstevel@tonic-gate #include <krb5.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate struct k5_data
370Sstevel@tonic-gate {
380Sstevel@tonic-gate 	krb5_context ctx;
390Sstevel@tonic-gate 	krb5_ccache cc;
400Sstevel@tonic-gate 	krb5_principal me;
410Sstevel@tonic-gate 	char *name;
420Sstevel@tonic-gate };
430Sstevel@tonic-gate 
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #define	MAIL		"mail"
460Sstevel@tonic-gate #define	MAILPATH	"/usr/bin/mail"
470Sstevel@tonic-gate #define	DEFAULT_CONFIG	"* terminal 30m"
480Sstevel@tonic-gate #define	CONF_FILENAME	"/etc/krb5/warn.conf"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /* warn.conf info */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate typedef struct config_entry_s {
530Sstevel@tonic-gate 	struct config_entry_s		*next;
540Sstevel@tonic-gate 	int				seconds_to_warn;
550Sstevel@tonic-gate 	char				*principal;
560Sstevel@tonic-gate 	char				*where_to;
570Sstevel@tonic-gate 	char				*email;
580Sstevel@tonic-gate 	int				renew;
590Sstevel@tonic-gate 	int				log_success;
600Sstevel@tonic-gate 	int				log_failure;
610Sstevel@tonic-gate } config_entry_list_t;
620Sstevel@tonic-gate static config_entry_list_t		*config_entry_list;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /* list of principals to be warned */
650Sstevel@tonic-gate 
660Sstevel@tonic-gate typedef struct cred_warning_list_s {
670Sstevel@tonic-gate 	struct cred_warning_list_s 	*next;
680Sstevel@tonic-gate 	WARNING_NAME_T			warn_name;
690Sstevel@tonic-gate 	time_t				cred_exp_time;
700Sstevel@tonic-gate 	time_t				cred_warn_time;
710Sstevel@tonic-gate 	mutex_t				cwm;
720Sstevel@tonic-gate } cred_warning_list_t;
730Sstevel@tonic-gate static cred_warning_list_t		*cred_warning_list;
740Sstevel@tonic-gate static rwlock_t				cred_lock = DEFAULTRWLOCK;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static bool_t
770Sstevel@tonic-gate del_warning_pvt(char *);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate static config_entry_list_t *
800Sstevel@tonic-gate find_warning_info(char *);
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static bool_t
830Sstevel@tonic-gate parseConfigLine(char *buffer);
840Sstevel@tonic-gate 
85*358Sgtb extern int warn_send(char *, char *);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate extern int kwarnd_debug;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate cred_warning_list_t *
900Sstevel@tonic-gate find_cred_warning(WARNING_NAME_T warn_name)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	cred_warning_list_t	*cw;
930Sstevel@tonic-gate 	if (!cred_warning_list)
940Sstevel@tonic-gate 		return (NULL);
950Sstevel@tonic-gate 	for (cw = cred_warning_list; cw != NULL; cw = cw->next) {
960Sstevel@tonic-gate 		if (strcmp(warn_name, cw->warn_name) != 0)
970Sstevel@tonic-gate 			continue;
980Sstevel@tonic-gate 		return (cw);
990Sstevel@tonic-gate 	}
1000Sstevel@tonic-gate 	return (NULL);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate  * add a principal to the principal warning list
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate bool_t
1080Sstevel@tonic-gate kwarn_add_warning_1_svc(kwarn_add_warning_arg *argp,
1090Sstevel@tonic-gate 			kwarn_add_warning_res *res,
1100Sstevel@tonic-gate 			struct svc_req *rqstp)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	cred_warning_list_t	*cred_warning;
1130Sstevel@tonic-gate 	config_entry_list_t *config_entry;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if (kwarnd_debug) {
1160Sstevel@tonic-gate 		printf("kwarn_add_warning_1_svc start; cWlist=%p\n",
1170Sstevel@tonic-gate 		    cred_warning_list);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 		printf("kwarn_add_warning_1_svc: principal %s",
1200Sstevel@tonic-gate 		    argp->warning_name);
1210Sstevel@tonic-gate 		printf(" exp time: %d\n", argp->cred_exp_time);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  *  if there is no entry in the config file that matches the principal to
1260Sstevel@tonic-gate  *  be added to the warning list, return true because we are not going to
1270Sstevel@tonic-gate  *  send a warning for this principal.
1280Sstevel@tonic-gate  */
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	if ((config_entry = find_warning_info(argp->warning_name)) == NULL) {
1310Sstevel@tonic-gate 		if (kwarnd_debug)
1320Sstevel@tonic-gate 			printf(
1330Sstevel@tonic-gate 		"kwarn_add_warning_1_svc find_warn_info: fails, cWlist=%p\n",
1340Sstevel@tonic-gate 				cred_warning_list);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 		return (TRUE);
1370Sstevel@tonic-gate 	}
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate  * see if a warning has already been created for this principal, if so
1410Sstevel@tonic-gate  * update the warning time.
1420Sstevel@tonic-gate  */
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	rw_wrlock(&cred_lock);
1450Sstevel@tonic-gate 	if (cred_warning = find_cred_warning(argp->warning_name)) {
1460Sstevel@tonic-gate 		rw_unlock(&cred_lock);
1470Sstevel@tonic-gate 		mutex_lock(&cred_warning->cwm);
1480Sstevel@tonic-gate 		cred_warning->cred_exp_time = argp->cred_exp_time;
1490Sstevel@tonic-gate 		cred_warning->cred_warn_time = argp->cred_exp_time
1500Sstevel@tonic-gate 			- config_entry->seconds_to_warn;
1510Sstevel@tonic-gate 		mutex_unlock(&cred_warning->cwm);
1520Sstevel@tonic-gate 	} else {
1530Sstevel@tonic-gate 		cred_warning = (cred_warning_list_t *)malloc(
1540Sstevel@tonic-gate 				sizeof (*cred_warning_list));
1550Sstevel@tonic-gate 		if (cred_warning == NULL) {
1560Sstevel@tonic-gate 			rw_unlock(&cred_lock);
1570Sstevel@tonic-gate 			res->status = 1;
1580Sstevel@tonic-gate 			return (FALSE);
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 		(void) memset((char *)cred_warning, 0,
1610Sstevel@tonic-gate 			    sizeof (*cred_warning_list));
1620Sstevel@tonic-gate 		cred_warning->cred_exp_time = argp->cred_exp_time;
1630Sstevel@tonic-gate 		cred_warning->cred_warn_time = argp->cred_exp_time
1640Sstevel@tonic-gate 			- config_entry->seconds_to_warn;
1650Sstevel@tonic-gate 		cred_warning->warn_name = strdup(argp->warning_name);
1660Sstevel@tonic-gate 		if (cred_warning->warn_name == NULL) {
1670Sstevel@tonic-gate 			free(cred_warning);
1680Sstevel@tonic-gate 			rw_unlock(&cred_lock);
1690Sstevel@tonic-gate 			res->status = 1;
1700Sstevel@tonic-gate 			return (FALSE);
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 		mutex_init(&cred_warning->cwm,  USYNC_THREAD, NULL);
1730Sstevel@tonic-gate 		cred_warning->next = cred_warning_list;
1740Sstevel@tonic-gate 		cred_warning_list = cred_warning;
1750Sstevel@tonic-gate 		rw_unlock(&cred_lock);
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 	res->status = 0;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	if (kwarnd_debug)
1800Sstevel@tonic-gate 		printf(
1810Sstevel@tonic-gate 		"kwarn_add_warning_1_svc end: returns true; cWlist=%p\n",
1820Sstevel@tonic-gate 		cred_warning_list);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	return (TRUE);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * delete a warning request for a given principal
1890Sstevel@tonic-gate  */
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate bool_t
1920Sstevel@tonic-gate kwarn_del_warning_1_svc(kwarn_del_warning_arg *argp,
1930Sstevel@tonic-gate 			kwarn_del_warning_res *res,
1940Sstevel@tonic-gate 			struct svc_req *rqstp)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	if (kwarnd_debug)
1970Sstevel@tonic-gate 		printf(gettext("delete principal %s requested\n"),
1980Sstevel@tonic-gate 		    argp->warning_name);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	if (del_warning_pvt(argp->warning_name) == TRUE) {
2010Sstevel@tonic-gate 		res->status = 0;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 		if (kwarnd_debug)
2040Sstevel@tonic-gate 			printf(gettext("delete principal %s completed\n"),
2050Sstevel@tonic-gate 			    argp->warning_name);
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 		return (TRUE);
2080Sstevel@tonic-gate 	} else {
2090Sstevel@tonic-gate 		res->status = 1;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 		if (kwarnd_debug)
2120Sstevel@tonic-gate 			printf(gettext("delete principal %s failed\n"),
2130Sstevel@tonic-gate 				argp->warning_name);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 		return (TRUE);
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate static bool_t
2200Sstevel@tonic-gate del_warning_pvt(char *warning_name)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	cred_warning_list_t	*cred_warning, *prev;
2230Sstevel@tonic-gate 	rw_wrlock(&cred_lock);
2240Sstevel@tonic-gate 	for (prev = NULL, cred_warning = cred_warning_list;
2250Sstevel@tonic-gate 		cred_warning != NULL; prev = cred_warning,
2260Sstevel@tonic-gate 		cred_warning = cred_warning->next) {
2270Sstevel@tonic-gate 		if (strcmp(cred_warning->warn_name, warning_name) == 0) {
2280Sstevel@tonic-gate 			if (!prev)
2290Sstevel@tonic-gate 				cred_warning_list = cred_warning->next;
2300Sstevel@tonic-gate 			else
2310Sstevel@tonic-gate 				prev->next = cred_warning->next;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 			free(cred_warning->warn_name);
2340Sstevel@tonic-gate 			free(cred_warning);
2350Sstevel@tonic-gate 			rw_unlock(&cred_lock);
2360Sstevel@tonic-gate 			return (TRUE);
2370Sstevel@tonic-gate 		}
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 	rw_unlock(&cred_lock);
2400Sstevel@tonic-gate 	return (FALSE);
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate  * load the warn.conf file into the config_entry list.
2450Sstevel@tonic-gate  */
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate bool_t
2480Sstevel@tonic-gate loadConfigFile(void)
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate 	char	buffer[BUFSIZ];
2510Sstevel@tonic-gate 	FILE	*cfgfile;
2520Sstevel@tonic-gate 	bool_t	retval = TRUE;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	if ((cfgfile = fopen(CONF_FILENAME, "r")) == NULL) {
2550Sstevel@tonic-gate 		syslog(LOG_ERR, gettext(
2560Sstevel@tonic-gate 			"could not open config file \"%s\"\n"),
2570Sstevel@tonic-gate 			CONF_FILENAME);
2580Sstevel@tonic-gate 		syslog(LOG_ERR, gettext(
2590Sstevel@tonic-gate 			"using default options \"%s\"\n"),
2600Sstevel@tonic-gate 			DEFAULT_CONFIG);
2610Sstevel@tonic-gate 		retval = parseConfigLine(DEFAULT_CONFIG);
2620Sstevel@tonic-gate 	} else {
2630Sstevel@tonic-gate 		(void) memset(buffer, 0, sizeof (buffer));
2640Sstevel@tonic-gate 		while ((fgets(buffer, BUFSIZ, cfgfile) != NULL) &&
2650Sstevel@tonic-gate 			(retval == TRUE))
2660Sstevel@tonic-gate 			retval = parseConfigLine(buffer);
2670Sstevel@tonic-gate 		fclose(cfgfile);
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 	return (retval);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate  * Return TRUE if we get a valid opt and update flags appro.
2740Sstevel@tonic-gate  */
2750Sstevel@tonic-gate static bool_t
2760Sstevel@tonic-gate cmp_renew_opts(char *opt,
2770Sstevel@tonic-gate 	    int *log_success, /* out */
2780Sstevel@tonic-gate 	    int *log_failure) /* out */
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if (strncasecmp(opt, "log",
2820Sstevel@tonic-gate 			sizeof ("log")) == 0) {
2830Sstevel@tonic-gate 		*log_success = *log_failure = 1;
2840Sstevel@tonic-gate 	} else if (strncasecmp(opt, "log-success",
2850Sstevel@tonic-gate 			    sizeof ("log-success")) == 0) {
2860Sstevel@tonic-gate 		*log_success = 1;
2870Sstevel@tonic-gate 	} else if (strncasecmp(opt, "log-failure",
2880Sstevel@tonic-gate 			    sizeof ("log-failure")) == 0) {
2890Sstevel@tonic-gate 		*log_failure = 1;
2900Sstevel@tonic-gate 	} else {
2910Sstevel@tonic-gate 		if (kwarnd_debug)
2920Sstevel@tonic-gate 			printf("cmp_renew_opts: renew bad opt=`%s'\n",
2930Sstevel@tonic-gate 			    opt ? opt : "null");
2940Sstevel@tonic-gate 		return (FALSE);
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	return (TRUE);
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate /*
3010Sstevel@tonic-gate  * Make the config_entry item for the config_entry_list, based on
3020Sstevel@tonic-gate  * buffer.  The formats are
3030Sstevel@tonic-gate  *
3040Sstevel@tonic-gate  *    <principal> [renew[:<opt1,...optN>]] syslog|terminal <time>
3050Sstevel@tonic-gate  *    <principal> [renew[:<opt1,...optN>]] mail <time> <e-mail address>
3060Sstevel@tonic-gate  *
3070Sstevel@tonic-gate  * where renew opts will be:
3080Sstevel@tonic-gate  *
3090Sstevel@tonic-gate  *     log-success
3100Sstevel@tonic-gate  *		- Log the result of the renew attempt on success using
3110Sstevel@tonic-gate  *		  the specified method (syslog|terminal|mail)
3120Sstevel@tonic-gate  *
3130Sstevel@tonic-gate  *      log-failure
3140Sstevel@tonic-gate  *		- Log the result of the renew attempt on failure using
3150Sstevel@tonic-gate  *		  the specified method (syslog|terminal|mail)
3160Sstevel@tonic-gate  *
3170Sstevel@tonic-gate  *      log
3180Sstevel@tonic-gate  *               - Same as specifing both log-failure and log-success
3190Sstevel@tonic-gate  *
3200Sstevel@tonic-gate  *		  Note if no log options are given, there will be no logging.
3210Sstevel@tonic-gate  *
3220Sstevel@tonic-gate  */
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate static bool_t
3250Sstevel@tonic-gate parseConfigLine(char *buffer)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate 	char *principal, *send_to, *emailid, *ends, *tm;
3280Sstevel@tonic-gate 	char			*exptime;
3290Sstevel@tonic-gate 	int			time_mode;
3300Sstevel@tonic-gate 	time_t			etime;
3310Sstevel@tonic-gate 	config_entry_list_t	*config_entry;
3320Sstevel@tonic-gate 	int renew = 0;
3330Sstevel@tonic-gate 	int log_success = 0;
3340Sstevel@tonic-gate 	int log_failure = 0;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	/* ignore comments */
3370Sstevel@tonic-gate 	if (*buffer == '#')
3380Sstevel@tonic-gate 		return (TRUE);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	if (kwarnd_debug)
3410Sstevel@tonic-gate 		printf("parseconf: buffer=%s", buffer);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/* find end of principal */
3440Sstevel@tonic-gate 	principal = buffer;
3450Sstevel@tonic-gate 	for (send_to = buffer; *send_to && !isspace(*send_to);
3460Sstevel@tonic-gate 		send_to++);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	/* find first non whitespace after principal (start of send_to) */
3490Sstevel@tonic-gate 	if (*send_to) {
3500Sstevel@tonic-gate 		*send_to = '\0';
3510Sstevel@tonic-gate 		send_to++;
3520Sstevel@tonic-gate 		while (*send_to && isspace(*send_to))
3530Sstevel@tonic-gate 			send_to++;
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/* if no send_to, continue, bad entry */
3570Sstevel@tonic-gate 	if (! *send_to)
3580Sstevel@tonic-gate 		return (TRUE);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/* find end of send_to */
3610Sstevel@tonic-gate 	for (ends = send_to; *ends && !isspace(*ends);
3620Sstevel@tonic-gate 		ends++);
3630Sstevel@tonic-gate 	if (*ends)
3640Sstevel@tonic-gate 		*ends = '\0';
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	if (strchr(send_to, ':')) {
3680Sstevel@tonic-gate 		/* we've got renew opts */
3690Sstevel@tonic-gate 		char *st = NULL, *op = NULL;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 		op = strdup(send_to);
3720Sstevel@tonic-gate 		if (!op)
3730Sstevel@tonic-gate 			return (FALSE);
3740Sstevel@tonic-gate 		st = strchr(op, ':');
3750Sstevel@tonic-gate 		*st = '\0';
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 		if (strncasecmp(op, "renew", sizeof ("renew")) == 0) {
3780Sstevel@tonic-gate 			renew = 1;
3790Sstevel@tonic-gate 		} else {
3800Sstevel@tonic-gate 			free(op);
3810Sstevel@tonic-gate 			/* got a ':' but not preceeded w/renew, badent, skip */
3820Sstevel@tonic-gate 			if (kwarnd_debug)
3830Sstevel@tonic-gate 				printf("parseconf: colon badent, skip\n");
3840Sstevel@tonic-gate 			return (TRUE);
3850Sstevel@tonic-gate 		}
3860Sstevel@tonic-gate 		free(op);
3870Sstevel@tonic-gate 		op = NULL;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 		st++;
3900Sstevel@tonic-gate 		if (!st || !*st || isspace(*st)) {
3910Sstevel@tonic-gate 			if (kwarnd_debug)
3920Sstevel@tonic-gate 				printf("parseconf: st badent, skip\n");
3930Sstevel@tonic-gate 			/* bad ent, skip */
3940Sstevel@tonic-gate 			return (TRUE);
3950Sstevel@tonic-gate 		}
3960Sstevel@tonic-gate 		if (renew && strchr(st, ',')) {
3970Sstevel@tonic-gate 			while (1) {
3980Sstevel@tonic-gate 				/* loop thru comma seperated list-o-opts */
3990Sstevel@tonic-gate 				char *comma = NULL, *c = NULL, *l = NULL;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 				if (st && (comma = strchr(st, ','))) {
4020Sstevel@tonic-gate 					l = strdup(st);
4030Sstevel@tonic-gate 					if (!l)
4040Sstevel@tonic-gate 						return (FALSE);
4050Sstevel@tonic-gate 					c = strchr(l, ',');
4060Sstevel@tonic-gate 					*c = '\0';
4070Sstevel@tonic-gate 					if (!cmp_renew_opts(l, &log_success,
4080Sstevel@tonic-gate 							    &log_failure)) {
4090Sstevel@tonic-gate 						free(l);
4100Sstevel@tonic-gate 						/* badent, skip */
4110Sstevel@tonic-gate 						return (TRUE);
4120Sstevel@tonic-gate 					}
4130Sstevel@tonic-gate 					free(l);
4140Sstevel@tonic-gate 					l = NULL;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 					st = comma;
4170Sstevel@tonic-gate 					st++;
4180Sstevel@tonic-gate 				} else {
4190Sstevel@tonic-gate 					if (st) {
4200Sstevel@tonic-gate 						if (!cmp_renew_opts(st,
4210Sstevel@tonic-gate 							    &log_success,
4220Sstevel@tonic-gate 							    &log_failure)) {
4230Sstevel@tonic-gate 							/* badent, skip */
4240Sstevel@tonic-gate 							return (TRUE);
4250Sstevel@tonic-gate 						}
4260Sstevel@tonic-gate 					}
4270Sstevel@tonic-gate 					break;
4280Sstevel@tonic-gate 				}
4290Sstevel@tonic-gate 			} /* while */
4300Sstevel@tonic-gate 		} else if (st) {
4310Sstevel@tonic-gate 			/* we just have one opt */
4320Sstevel@tonic-gate 			if (!cmp_renew_opts(st, &log_success, &log_failure)) {
4330Sstevel@tonic-gate 				/* badent, skip */
4340Sstevel@tonic-gate 				return (TRUE);
4350Sstevel@tonic-gate 			}
4360Sstevel@tonic-gate 		}
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		/* if send_to is "renew", note it and refind send_to */
4390Sstevel@tonic-gate 	} else if (strncasecmp(send_to, "renew",
4400Sstevel@tonic-gate 			    sizeof ("renew")) == 0) {
4410Sstevel@tonic-gate 		renew = 1;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if (kwarnd_debug) {
4460Sstevel@tonic-gate 		printf("parseconf: renew=%d, log failure=%d, log success=%d\n",
4470Sstevel@tonic-gate 		    renew, log_failure, log_success);
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	if (renew) {
4510Sstevel@tonic-gate 		/* find first non whitespace after send_to (start of exptime) */
4520Sstevel@tonic-gate 		for (send_to = ends+1; *send_to && isspace(*send_to);
4530Sstevel@tonic-gate 		    send_to++);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		/* if no send_to, continue, bad entry */
4560Sstevel@tonic-gate 		if (! *send_to) {
4570Sstevel@tonic-gate 			if (kwarnd_debug)
4580Sstevel@tonic-gate 				printf("parseconf: no send_to, badent, skip\n");
4590Sstevel@tonic-gate 			return (TRUE);
4600Sstevel@tonic-gate 		}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		/* find end of send_to */
4630Sstevel@tonic-gate 		for (ends = send_to; *ends && !isspace(*ends);
4640Sstevel@tonic-gate 		    ends++);
4650Sstevel@tonic-gate 		if (*ends)
4660Sstevel@tonic-gate 			*ends = '\0';
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/* find first non whitespace after send_to (start of exptime) */
4710Sstevel@tonic-gate 	for (exptime = ends+1; *exptime && isspace(*exptime);
4720Sstevel@tonic-gate 		exptime++);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/* if no exptime, continue, bad entry */
4750Sstevel@tonic-gate 	if (! *exptime) {
4760Sstevel@tonic-gate 		if (kwarnd_debug)
4770Sstevel@tonic-gate 			printf("parseconf: no exptime, badent, skip\n");
4780Sstevel@tonic-gate 		return (TRUE);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	/* find end of exptime */
4820Sstevel@tonic-gate 	for (ends = exptime; *ends && !isspace(*ends); ends++);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	tm = ends - 1;
4850Sstevel@tonic-gate 	if (*tm == 's')
4860Sstevel@tonic-gate 		time_mode = 1;
4870Sstevel@tonic-gate 	else if (*tm == 'm')
4880Sstevel@tonic-gate 		time_mode = 2;
4890Sstevel@tonic-gate 	else if (*tm == 'h')
4900Sstevel@tonic-gate 		time_mode = 3;
4910Sstevel@tonic-gate 	else
4920Sstevel@tonic-gate 		time_mode = 1;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if (*tm)
4950Sstevel@tonic-gate 		*tm = '\0';
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	if (kwarnd_debug) {
4980Sstevel@tonic-gate 		printf("parseconf: send_to = '%s', exptime='%s'\n",
4990Sstevel@tonic-gate 		    send_to, exptime);
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	/* find first non whitespace after exptime (start of emailid) */
5030Sstevel@tonic-gate 	for (emailid = ends+1; *emailid && isspace(*emailid); emailid++);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/* find end of emailid */
5060Sstevel@tonic-gate 	if (*emailid) {
5070Sstevel@tonic-gate 		for (ends = emailid; *ends && !isspace(*ends);
5080Sstevel@tonic-gate 			ends++);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 		if (*ends)
5110Sstevel@tonic-gate 			*ends = '\0';
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	/* if send to mail and no mail address, bad entry */
5150Sstevel@tonic-gate 	if ((strcmp(send_to, "mail") == 0) && (!*emailid)) {
5160Sstevel@tonic-gate 		if (kwarnd_debug)
5170Sstevel@tonic-gate 			printf("parseconf: returns true; no mail addr\n");
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		syslog(LOG_ERR, gettext("missing mail address"
5200Sstevel@tonic-gate 			" in config entry: \n%s %s %s "
5210Sstevel@tonic-gate 			" cannot mail warning"), principal,
5220Sstevel@tonic-gate 			send_to, exptime);
5230Sstevel@tonic-gate 		return (TRUE);
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	/* create an entry */
5270Sstevel@tonic-gate 	config_entry = (config_entry_list_t *)
5280Sstevel@tonic-gate 		malloc(sizeof (*config_entry_list));
5290Sstevel@tonic-gate 	if (config_entry == NULL)
5300Sstevel@tonic-gate 		return (FALSE);
5310Sstevel@tonic-gate 	(void) memset(config_entry, 0, sizeof (*config_entry_list));
5320Sstevel@tonic-gate 	config_entry->principal = strdup(principal);
5330Sstevel@tonic-gate 	if (config_entry->principal == NULL)
5340Sstevel@tonic-gate 		return (FALSE);
5350Sstevel@tonic-gate 	config_entry->where_to = strdup(send_to);
5360Sstevel@tonic-gate 	if (config_entry->where_to == NULL)
5370Sstevel@tonic-gate 		return (FALSE);
5380Sstevel@tonic-gate 	etime = atol(exptime);
5390Sstevel@tonic-gate 	if (time_mode == 1)
5400Sstevel@tonic-gate 		config_entry->seconds_to_warn = etime;
5410Sstevel@tonic-gate 	else if (time_mode == 2)
5420Sstevel@tonic-gate 		config_entry->seconds_to_warn = etime * 60;
5430Sstevel@tonic-gate 	else if (time_mode == 3)
5440Sstevel@tonic-gate 		config_entry->seconds_to_warn = etime * 60 * 60;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	if (*emailid) {
5470Sstevel@tonic-gate 		config_entry->email = strdup(emailid);
5480Sstevel@tonic-gate 		if (config_entry->email == NULL)
5490Sstevel@tonic-gate 			return (FALSE);
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	config_entry->renew = renew;
5530Sstevel@tonic-gate 	config_entry->log_success = log_success;
5540Sstevel@tonic-gate 	config_entry->log_failure = log_failure;
5550Sstevel@tonic-gate 	config_entry->next = config_entry_list;
5560Sstevel@tonic-gate 	config_entry_list = config_entry;
5570Sstevel@tonic-gate 	if (kwarnd_debug)
5580Sstevel@tonic-gate 		printf("parseconf: returns true; celist=%p\n",
5590Sstevel@tonic-gate 		    config_entry_list);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	return (TRUE);
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate /*
5650Sstevel@tonic-gate  * find a specific warn.conf entry.
5660Sstevel@tonic-gate  */
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate static config_entry_list_t *
5690Sstevel@tonic-gate find_warning_info(char *principal)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate 	config_entry_list_t	*config_entry;
5720Sstevel@tonic-gate 	/* look for a specific entry */
5730Sstevel@tonic-gate 	for (config_entry = config_entry_list; config_entry;
5740Sstevel@tonic-gate 		config_entry = config_entry->next) {
5750Sstevel@tonic-gate 		if (strcmp(config_entry->principal, principal) == 0) {
5760Sstevel@tonic-gate 			return (config_entry);
5770Sstevel@tonic-gate 		}
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 	/* look for a wild card entry */
5800Sstevel@tonic-gate 	for (config_entry = config_entry_list; config_entry;
5810Sstevel@tonic-gate 		config_entry = config_entry->next) {
5820Sstevel@tonic-gate 		if (strcmp(config_entry->principal, "*") == 0) {
5830Sstevel@tonic-gate 			return (config_entry);
5840Sstevel@tonic-gate 		}
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 	/* nothing found */
5870Sstevel@tonic-gate 	return (NULL);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate  * create a pipe, fork and exec a command,
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate static FILE *
5950Sstevel@tonic-gate safe_popen_w(char *path_to_cmd, char **argv)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	int fd[2];
5990Sstevel@tonic-gate 	FILE *fp;
6000Sstevel@tonic-gate 	char *envp[2];
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	if (pipe(fd) == -1)
6030Sstevel@tonic-gate 		return (NULL);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	switch (fork()) {
6070Sstevel@tonic-gate 	case -1:
6080Sstevel@tonic-gate 		(void) close(fd[0]);
6090Sstevel@tonic-gate 		(void) close(fd[1]);
6100Sstevel@tonic-gate 		return (NULL);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	case 0:
6130Sstevel@tonic-gate 		close(fd[1]);
6140Sstevel@tonic-gate 		/* fd[0] is the end we read from */
6150Sstevel@tonic-gate 		if (fd[0] != 0) {
6160Sstevel@tonic-gate 			close(0);
6170Sstevel@tonic-gate 			dup(fd[0]);
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 		close(1);
6200Sstevel@tonic-gate 		close(2);
6210Sstevel@tonic-gate 		envp[0] = "PATH=/usr/bin";
6220Sstevel@tonic-gate 		envp[1] = NULL;
6230Sstevel@tonic-gate #ifdef	DEBUG
6240Sstevel@tonic-gate 		{
6250Sstevel@tonic-gate 			int fd;
6260Sstevel@tonic-gate 			fd = open("/tmp/kwarn.out", O_WRONLY|O_TRUNC|O_CREAT,
6270Sstevel@tonic-gate 				0666);
6280Sstevel@tonic-gate 			if (fd != 1)
6290Sstevel@tonic-gate 				dup(fd);
6300Sstevel@tonic-gate 			if (fd != 2)
6310Sstevel@tonic-gate 				dup(fd);
6320Sstevel@tonic-gate 		}
6330Sstevel@tonic-gate #endif
6340Sstevel@tonic-gate 		(void) execve(path_to_cmd, argv, envp);
6350Sstevel@tonic-gate 		syslog(LOG_ERR, "warnd: %m");
6360Sstevel@tonic-gate 		_exit(1);
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	default:
6390Sstevel@tonic-gate 		close(fd[0]);
6400Sstevel@tonic-gate 		/* fd[1] is the end we write to */
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		fp = fdopen(fd[1], "w");
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 		if (fp == NULL) {
6450Sstevel@tonic-gate 			(void) close(fd[1]);
6460Sstevel@tonic-gate 			return (NULL);
6470Sstevel@tonic-gate 		}
6480Sstevel@tonic-gate 		return (fp);
6490Sstevel@tonic-gate 	}
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate static uid_t gssd_uid;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate void
6560Sstevel@tonic-gate set_warnd_uid(uid_t uid)
6570Sstevel@tonic-gate {
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	/*
6600Sstevel@tonic-gate 	 * set the value of gssd_uid, so it can be retrieved when getuid()
6610Sstevel@tonic-gate 	 * is called by the underlying mechanism libraries
6620Sstevel@tonic-gate 	 */
6630Sstevel@tonic-gate 	if (kwarnd_debug)
6640Sstevel@tonic-gate 		printf("set_warnd_uid called with uid = %d\n", uid);
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	gssd_uid = uid;
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate uid_t
6700Sstevel@tonic-gate getuid(void)
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate {
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	/*
6750Sstevel@tonic-gate 	 * return the value set when one of the gssd procedures was
6760Sstevel@tonic-gate 	 * entered. This is the value of the uid under which the
6770Sstevel@tonic-gate 	 * underlying mechanism library must operate in order to
6780Sstevel@tonic-gate 	 * get the user's credentials. This call is necessary since
6790Sstevel@tonic-gate 	 * gssd runs as root and credentials are many times stored
6800Sstevel@tonic-gate 	 * in files and directories specific to the user
6810Sstevel@tonic-gate 	 */
6820Sstevel@tonic-gate 	if (kwarnd_debug)
6830Sstevel@tonic-gate 		printf("getuid called and returning gsssd_uid = %d\n",
6840Sstevel@tonic-gate 		    gssd_uid);
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	return (gssd_uid);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate static bool_t
6910Sstevel@tonic-gate getpruid(char *pr, uid_t *uid)
6920Sstevel@tonic-gate {
6930Sstevel@tonic-gate 	char *rcp1 = NULL, *rcp2 = NULL, *rcp3 = NULL;
6940Sstevel@tonic-gate 	struct passwd *pw;
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	rcp1 = strdup(pr);
6970Sstevel@tonic-gate 	if (!rcp1)
6980Sstevel@tonic-gate 		return (FALSE);
6990Sstevel@tonic-gate 	rcp2 = strtok(rcp1, "@");
7000Sstevel@tonic-gate 	rcp3 = strtok(rcp2, "/");
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	if (rcp3) {
7030Sstevel@tonic-gate 		pw = getpwnam(rcp3);
7040Sstevel@tonic-gate 		*uid = pw->pw_uid;
7050Sstevel@tonic-gate 		free(rcp1);
7060Sstevel@tonic-gate 		return (TRUE);
7070Sstevel@tonic-gate 	}
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	free(rcp1);
7100Sstevel@tonic-gate 	return (FALSE);
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate static krb5_error_code
7150Sstevel@tonic-gate renew_creds(
7160Sstevel@tonic-gate 	char *princ,
7170Sstevel@tonic-gate 	time_t *new_exp_time) /* out */
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	krb5_creds my_creds;
7200Sstevel@tonic-gate 	krb5_error_code code = 0;
7210Sstevel@tonic-gate 	struct k5_data k5;
7220Sstevel@tonic-gate 	char *progname = "warnd";
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	uid_t saved_u = getuid();
7250Sstevel@tonic-gate 	uid_t u;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	if (kwarnd_debug)
7280Sstevel@tonic-gate 		printf("renew start: uid=%d\n", getuid());
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	if (!getpruid(princ, &u)) {
7310Sstevel@tonic-gate 		if (kwarnd_debug)
7320Sstevel@tonic-gate 			printf("renew: getpruid failed, princ='%s'\n",
7330Sstevel@tonic-gate 			    princ ? princ : "<null>");
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 		return (-1); /* better err num? */
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	set_warnd_uid(u);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	(void) memset(&my_creds, 0, sizeof (my_creds));
7410Sstevel@tonic-gate 	(void) memset(&k5, 0, sizeof (k5));
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	if (code = krb5_init_context(&k5.ctx)) {
7440Sstevel@tonic-gate 		com_err(progname, code,
7450Sstevel@tonic-gate 			gettext("while initializing Kerberos 5 library"));
7460Sstevel@tonic-gate 		goto out;
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if ((code = krb5_cc_default(k5.ctx, &k5.cc))) {
7500Sstevel@tonic-gate 		com_err(progname, code,
7510Sstevel@tonic-gate 			gettext("while getting default ccache"));
7520Sstevel@tonic-gate 		goto out;
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	if ((code = krb5_parse_name(k5.ctx, princ,
7570Sstevel@tonic-gate 				    &k5.me))) {
7580Sstevel@tonic-gate 		com_err(progname, code, gettext("when parsing name %s"),
7590Sstevel@tonic-gate 			princ);
7600Sstevel@tonic-gate 		goto out;
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	if ((code = krb5_get_renewed_creds(k5.ctx, &my_creds, k5.me, k5.cc,
7640Sstevel@tonic-gate 					NULL))) {
7650Sstevel@tonic-gate 		com_err(progname, code, gettext("while renewing creds"));
7660Sstevel@tonic-gate 		goto out;
7670Sstevel@tonic-gate 	}
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	if (code = krb5_cc_initialize(k5.ctx, k5.cc, k5.me)) {
7700Sstevel@tonic-gate 		com_err(progname, code, gettext("when initializing cache %s"),
7710Sstevel@tonic-gate 			"defcc");
7720Sstevel@tonic-gate 		goto out;
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	if (code = krb5_cc_store_cred(k5.ctx, k5.cc, &my_creds)) {
7760Sstevel@tonic-gate 		com_err(progname, code, gettext("while storing credentials"));
7770Sstevel@tonic-gate 		goto out;
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	/* "return" new expire time */
7810Sstevel@tonic-gate 	*new_exp_time = my_creds.times.endtime;
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate out:
7840Sstevel@tonic-gate 	krb5_free_cred_contents(k5.ctx, &my_creds);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	if (k5.name)
7870Sstevel@tonic-gate 		krb5_free_unparsed_name(k5.ctx, k5.name);
7880Sstevel@tonic-gate 	if (k5.me)
7890Sstevel@tonic-gate 		krb5_free_principal(k5.ctx, k5.me);
7900Sstevel@tonic-gate 	if (k5.cc)
7910Sstevel@tonic-gate 		krb5_cc_close(k5.ctx, k5.cc);
7920Sstevel@tonic-gate 	if (k5.ctx)
7930Sstevel@tonic-gate 		krb5_free_context(k5.ctx);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	set_warnd_uid(saved_u);
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	if (kwarnd_debug)
7980Sstevel@tonic-gate 		printf("renew end: code=%s, uid=%d\n", error_message(code),
7990Sstevel@tonic-gate 		    getuid());
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	return (code);
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate static bool_t
8050Sstevel@tonic-gate loggedon(char *name)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	register struct utmpx *ubuf;
8080Sstevel@tonic-gate 	char    *rcp1 = NULL, *rcp2 = NULL, *rcp3 = NULL;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	/*
8110Sstevel@tonic-gate 	 * strip any realm or instance from principal so we can match
8120Sstevel@tonic-gate 	 * against unix userid.
8130Sstevel@tonic-gate 	 */
8140Sstevel@tonic-gate 	rcp1 = strdup(name);
8150Sstevel@tonic-gate 	if (!rcp1)
8160Sstevel@tonic-gate 		return (FALSE);
8170Sstevel@tonic-gate 	rcp2 = strtok(rcp1, "@");
8180Sstevel@tonic-gate 	rcp3 = strtok(rcp2, "/");
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * Scan through the "utmpx" file for the
8220Sstevel@tonic-gate 	 * entry for the person we want to send to.
8230Sstevel@tonic-gate 	 */
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	setutxent();
8260Sstevel@tonic-gate 	while ((ubuf = getutxent()) != NULL) {
8270Sstevel@tonic-gate 		if (ubuf->ut_type == USER_PROCESS) {
8280Sstevel@tonic-gate 			if (strncmp(rcp3, ubuf->ut_user,
8290Sstevel@tonic-gate 				    sizeof (ubuf->ut_user)) == 0) {
8300Sstevel@tonic-gate 				free(rcp1);
8310Sstevel@tonic-gate 				endutxent();
8320Sstevel@tonic-gate 				return (TRUE);
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 			}
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 	}
8370Sstevel@tonic-gate 	free(rcp1);
8380Sstevel@tonic-gate 	endutxent();
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	if (kwarnd_debug)
8410Sstevel@tonic-gate 		printf("loggedon: returning false for user `%s'\n", rcp1);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	return (FALSE);
8440Sstevel@tonic-gate }
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate /*
8470Sstevel@tonic-gate  * main loop to check the cred warning list and send the warnings
8480Sstevel@tonic-gate  * the appropriate location based on warn.conf or auto-renew creds.
8490Sstevel@tonic-gate  */
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate void
8520Sstevel@tonic-gate kwarnd_check_warning_list(void)
8530Sstevel@tonic-gate { /* func */
8540Sstevel@tonic-gate 	cred_warning_list_t	*cw;  /* cred warning */
8550Sstevel@tonic-gate 	config_entry_list_t	*ce;  /* config entry */
8560Sstevel@tonic-gate 	time_t			now;
8570Sstevel@tonic-gate 	int			minutes;
8580Sstevel@tonic-gate 	char			buff[256];
8590Sstevel@tonic-gate 	char			cmdline[256];
8600Sstevel@tonic-gate 	FILE			*fp;
8610Sstevel@tonic-gate 	char			*subj = "Kerberos credentials expiring";
8620Sstevel@tonic-gate 	char			*renew_subj = "Kerberos credentials renewed";
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	if (kwarnd_debug)
8650Sstevel@tonic-gate 		printf("check list: start: getuid=%d, cw list=%p\n", getuid(),
8660Sstevel@tonic-gate 			cred_warning_list);
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	while (1) {
8690Sstevel@tonic-gate 		(void) poll(NULL, NULL, 60000);
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 		for (cw = cred_warning_list;
8720Sstevel@tonic-gate 			cw != NULL;
8730Sstevel@tonic-gate 			cw = cw->next) {
8740Sstevel@tonic-gate 			int send_msg = 0;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 			time(&now);
8770Sstevel@tonic-gate 			if (now >= cw->cred_warn_time) {
8780Sstevel@tonic-gate 				int renew_attempted = 0;
8790Sstevel@tonic-gate 				int renew_failed = 0;
8800Sstevel@tonic-gate 				int renew_tooclose = 0;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 				if (kwarnd_debug)
8830Sstevel@tonic-gate 					printf("checklist: now >= warn_t\n");
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 				ce = find_warning_info(cw->warn_name);
8860Sstevel@tonic-gate 				minutes = (cw->cred_exp_time -
8870Sstevel@tonic-gate 					now + 59) / 60;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 				if (kwarnd_debug)
8900Sstevel@tonic-gate 					printf("checklist: where_to=%s\n",
8910Sstevel@tonic-gate 					    ce->where_to ?
8920Sstevel@tonic-gate 					    ce->where_to : "null");
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 				if (ce->renew &&
8950Sstevel@tonic-gate 				    loggedon(cw->warn_name)) {
8960Sstevel@tonic-gate 					krb5_error_code code;
8970Sstevel@tonic-gate 					time_t new_exp_time;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 					renew_attempted = 1;
9000Sstevel@tonic-gate 					code = renew_creds(
9010Sstevel@tonic-gate 						cw->warn_name,
9020Sstevel@tonic-gate 						&new_exp_time);
9030Sstevel@tonic-gate 					if (!code) {
9040Sstevel@tonic-gate 						/* krb5 api renew success */
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 						/*
9070Sstevel@tonic-gate 						 * So we had api success
9080Sstevel@tonic-gate 						 * but the new exp time
9090Sstevel@tonic-gate 						 * is same as current one
9100Sstevel@tonic-gate 						 * so we are too close
9110Sstevel@tonic-gate 						 * to Renewable_life time.
9120Sstevel@tonic-gate 						 */
9130Sstevel@tonic-gate 						if (cw->cred_exp_time
9140Sstevel@tonic-gate 						    == new_exp_time) {
9150Sstevel@tonic-gate 							renew_tooclose = 1;
9160Sstevel@tonic-gate 							if (kwarnd_debug)
9170Sstevel@tonic-gate 								printf(
9180Sstevel@tonic-gate 		"checklist: new expire time same as old expire time\n");
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 							if (ce->log_failure) {
9210Sstevel@tonic-gate 								send_msg = 1;
9220Sstevel@tonic-gate 								snprintf(buff,
9230Sstevel@tonic-gate 								sizeof (buff),
9240Sstevel@tonic-gate 					gettext("%s:\r\nYour kerberos"
9250Sstevel@tonic-gate 					" credentials have not been renewed"
9260Sstevel@tonic-gate 					" (too close to Renewable_life).\r\n"
9270Sstevel@tonic-gate 					"Please run kinit(1).\r\n"),
9280Sstevel@tonic-gate 								cw->warn_name);
9290Sstevel@tonic-gate 							}
9300Sstevel@tonic-gate 						} else {
9310Sstevel@tonic-gate 							/* update times */
9320Sstevel@tonic-gate 							cw->cred_exp_time =
9330Sstevel@tonic-gate 								new_exp_time;
9340Sstevel@tonic-gate 							cw->cred_warn_time =
9350Sstevel@tonic-gate 							    new_exp_time -
9360Sstevel@tonic-gate 							    ce->seconds_to_warn;
9370Sstevel@tonic-gate 						}
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 						if (kwarnd_debug)
9400Sstevel@tonic-gate 							printf(
9410Sstevel@tonic-gate 						    "check list: new_w_t=%d\n",
9420Sstevel@tonic-gate 						    cw->cred_warn_time);
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 						if (!renew_tooclose &&
9450Sstevel@tonic-gate 						    ce->log_success) {
9460Sstevel@tonic-gate 							if (kwarnd_debug)
9470Sstevel@tonic-gate 								printf(
9480Sstevel@tonic-gate 						"check list: log success\n");
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 							send_msg = 1;
9510Sstevel@tonic-gate 							snprintf(buff,
9520Sstevel@tonic-gate 								sizeof (buff),
9530Sstevel@tonic-gate 						gettext("%s:\r\nYour kerberos"
9540Sstevel@tonic-gate 					" credentials have been renewed.\r\n"),
9550Sstevel@tonic-gate 								cw->warn_name);
9560Sstevel@tonic-gate 						}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 					}  /* !(code) */
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 					if (!renew_tooclose && code &&
9610Sstevel@tonic-gate 					    ce->log_failure) {
9620Sstevel@tonic-gate 						if (kwarnd_debug)
9630Sstevel@tonic-gate 							printf(
9640Sstevel@tonic-gate 						"check list: log FAIL\n");
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 						send_msg = 1;
9670Sstevel@tonic-gate 						snprintf(buff,
9680Sstevel@tonic-gate 							sizeof (buff),
9690Sstevel@tonic-gate 					    gettext("%s:\r\nYour kerberos"
9700Sstevel@tonic-gate 				" credentials failed to be renewed (%s).\r\n"),
9710Sstevel@tonic-gate 							cw->warn_name,
9720Sstevel@tonic-gate 							error_message(code));
9730Sstevel@tonic-gate 					}
9740Sstevel@tonic-gate 					renew_failed = code ? 1 : 0;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 				} else if (minutes > 0) {
9770Sstevel@tonic-gate 					send_msg = 1;
9780Sstevel@tonic-gate 					snprintf(buff, sizeof (buff),
9790Sstevel@tonic-gate 					gettext("%s:\r\nyour kerberos"
9800Sstevel@tonic-gate 					" credentials expire in less than"
9810Sstevel@tonic-gate 					" %d minutes.\r\n"),
9820Sstevel@tonic-gate 					cw->warn_name,
9830Sstevel@tonic-gate 					minutes);
9840Sstevel@tonic-gate 				} else {
9850Sstevel@tonic-gate 					send_msg = 1;
9860Sstevel@tonic-gate 					snprintf(buff, sizeof (buff),
9870Sstevel@tonic-gate 					gettext("%s:\r\nyour kerberos"
9880Sstevel@tonic-gate 					" credentials have expired.\r\n"),
9890Sstevel@tonic-gate 					cw->warn_name);
9900Sstevel@tonic-gate 				}
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 				if (kwarnd_debug)
9930Sstevel@tonic-gate 					printf("checklist: send_msg=%d\n",
9940Sstevel@tonic-gate 					    send_msg);
9950Sstevel@tonic-gate 				if (!send_msg)
9960Sstevel@tonic-gate 					goto del_warning;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 				if (strncmp(ce->where_to,
9990Sstevel@tonic-gate 					    "mail", sizeof ("mail")) == 0) {
10000Sstevel@tonic-gate 					char *argv[3];
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 					argv[0] = MAIL;
10030Sstevel@tonic-gate 					(void) snprintf(cmdline,
10040Sstevel@tonic-gate 							sizeof (cmdline),
10050Sstevel@tonic-gate 							"%s",
10060Sstevel@tonic-gate 							ce->email);
10070Sstevel@tonic-gate 					argv[1] = cmdline;
10080Sstevel@tonic-gate 					argv[2] = NULL;
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 					fp = safe_popen_w(MAILPATH, argv);
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 					if (fp) {
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 						(void) fprintf(fp,
10150Sstevel@tonic-gate 						"To: %s\nSubject: %s\n\n%s\n",
10160Sstevel@tonic-gate 							    ce->email,
10170Sstevel@tonic-gate 							    renew_attempted
10180Sstevel@tonic-gate 							    ? renew_subj : subj,
10190Sstevel@tonic-gate 							    buff);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 					    fclose(fp);
10220Sstevel@tonic-gate 					} else {
10230Sstevel@tonic-gate 					    syslog(LOG_ERR,
10240Sstevel@tonic-gate 						gettext("could not fork "
10250Sstevel@tonic-gate 						"mail program to e-mail "
10260Sstevel@tonic-gate 						"warning to %s\n"),
10270Sstevel@tonic-gate 						cmdline);
10280Sstevel@tonic-gate 					}
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 				} else if (strncmp(ce->where_to,
10310Sstevel@tonic-gate 						"terminal",
10320Sstevel@tonic-gate 						sizeof ("terminal")) == 0) {
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 					warn_send(cw->warn_name,
10350Sstevel@tonic-gate 						buff);
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 				} else if (send_msg && strncmp(ce->where_to,
10380Sstevel@tonic-gate 							    "syslog",
10390Sstevel@tonic-gate 						sizeof ("syslog")) == 0) {
10400Sstevel@tonic-gate 					syslog(LOG_NOTICE|LOG_AUTH,
10410Sstevel@tonic-gate 					    "%s",
10420Sstevel@tonic-gate 					    buff);
10430Sstevel@tonic-gate #if 0
10440Sstevel@tonic-gate 				} else if (strncmp(ce->where_to,
10450Sstevel@tonic-gate 						"snmp",
10460Sstevel@tonic-gate 						sizeof ("snmp")) == 0) {
10470Sstevel@tonic-gate #endif
10480Sstevel@tonic-gate 				} else {
10490Sstevel@tonic-gate 					if (kwarnd_debug)
10500Sstevel@tonic-gate 						printf(
10510Sstevel@tonic-gate 						"unknown msg method=`%s'\n",
10520Sstevel@tonic-gate 						ce->where_to);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 					exit(1);
10550Sstevel@tonic-gate 				}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 			del_warning:
10580Sstevel@tonic-gate 				if (!renew_attempted || renew_failed ||
10590Sstevel@tonic-gate 				    renew_tooclose) {
10600Sstevel@tonic-gate 					if (del_warning_pvt(cw->warn_name)
10610Sstevel@tonic-gate 					    == TRUE) {
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 						if (kwarnd_debug)
10640Sstevel@tonic-gate 							printf(
10650Sstevel@tonic-gate 						"check list: del warn succ\n");
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 						break;
10680Sstevel@tonic-gate 					} else {
10690Sstevel@tonic-gate 						if (kwarnd_debug)
10700Sstevel@tonic-gate 							printf(
10710Sstevel@tonic-gate 						"could not delete warning\n");
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 						syslog(LOG_ERR, gettext(
10740Sstevel@tonic-gate 						"could not delete warning"));
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 						exit(1);
10770Sstevel@tonic-gate 					    }
10780Sstevel@tonic-gate 					}
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 				} /* if (now) */
10810Sstevel@tonic-gate 		} /* for */
10820Sstevel@tonic-gate 	} /* while */
10830Sstevel@tonic-gate }  /* func */
1084