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