/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * RPC server procedures for the usermode daemon kwarnd. */ #include #include #include #include #include #include #include #include #include "kwarnd.h" #include #include #include #include #include #include #include #include #include #include #include #include #include extern char progname[]; struct k5_data { krb5_context ctx; krb5_ccache cc; krb5_principal me; char *name; }; #define MAIL "mail" #define MAILPATH "/usr/bin/mail" #define DEFAULT_CONFIG "* terminal 30m" #define CONF_FILENAME "/etc/krb5/warn.conf" /* warn.conf info */ typedef struct config_entry_s { struct config_entry_s *next; int seconds_to_warn; char *principal; char *where_to; char *email; int renew; int log_success; int log_failure; } config_entry_list_t; static config_entry_list_t *config_entry_list; /* list of principals to be warned */ typedef struct cred_warning_list_s { struct cred_warning_list_s *next; WARNING_NAME_T warn_name; time_t cred_exp_time; time_t cred_warn_time; mutex_t cwm; } cred_warning_list_t; static cred_warning_list_t *cred_warning_list; static rwlock_t cred_lock = DEFAULTRWLOCK; static bool_t del_warning_pvt(char *); static config_entry_list_t * find_warning_info(char *); static bool_t parseConfigLine(char *buffer); extern int warn_send(char *, char *); extern int kwarnd_debug; cred_warning_list_t * find_cred_warning(WARNING_NAME_T warn_name) { cred_warning_list_t *cw; if (!cred_warning_list) return (NULL); for (cw = cred_warning_list; cw != NULL; cw = cw->next) { if (strcmp(warn_name, cw->warn_name) != 0) continue; return (cw); } return (NULL); } /* * add a principal to the principal warning list */ bool_t kwarn_add_warning_1_svc(kwarn_add_warning_arg *argp, kwarn_add_warning_res *res, struct svc_req *rqstp) { cred_warning_list_t *cred_warning; config_entry_list_t *config_entry; if (kwarnd_debug) { printf("kwarn_add_warning_1_svc start; cWlist=%p\n", cred_warning_list); printf("kwarn_add_warning_1_svc: principal %s", argp->warning_name); printf(" exp time: %d\n", argp->cred_exp_time); } /* * if there is no entry in the config file that matches the principal to * be added to the warning list, return true because we are not going to * send a warning for this principal. */ if ((config_entry = find_warning_info(argp->warning_name)) == NULL) { if (kwarnd_debug) printf( "kwarn_add_warning_1_svc find_warn_info: fails, cWlist=%p\n", cred_warning_list); return (TRUE); } /* * see if a warning has already been created for this principal, if so * update the warning time. */ rw_wrlock(&cred_lock); if (cred_warning = find_cred_warning(argp->warning_name)) { rw_unlock(&cred_lock); mutex_lock(&cred_warning->cwm); cred_warning->cred_exp_time = argp->cred_exp_time; cred_warning->cred_warn_time = argp->cred_exp_time - config_entry->seconds_to_warn; mutex_unlock(&cred_warning->cwm); } else { cred_warning = (cred_warning_list_t *)malloc( sizeof (*cred_warning_list)); if (cred_warning == NULL) { rw_unlock(&cred_lock); res->status = 1; return (FALSE); } (void) memset((char *)cred_warning, 0, sizeof (*cred_warning_list)); cred_warning->cred_exp_time = argp->cred_exp_time; cred_warning->cred_warn_time = argp->cred_exp_time - config_entry->seconds_to_warn; cred_warning->warn_name = strdup(argp->warning_name); if (cred_warning->warn_name == NULL) { free(cred_warning); rw_unlock(&cred_lock); res->status = 1; return (FALSE); } mutex_init(&cred_warning->cwm, USYNC_THREAD, NULL); cred_warning->next = cred_warning_list; cred_warning_list = cred_warning; rw_unlock(&cred_lock); } res->status = 0; if (kwarnd_debug) printf( "kwarn_add_warning_1_svc end: returns true; cWlist=%p\n", cred_warning_list); return (TRUE); } /* * delete a warning request for a given principal */ bool_t kwarn_del_warning_1_svc(kwarn_del_warning_arg *argp, kwarn_del_warning_res *res, struct svc_req *rqstp) { if (kwarnd_debug) printf(gettext("delete principal %s requested\n"), argp->warning_name); if (del_warning_pvt(argp->warning_name) == TRUE) { res->status = 0; if (kwarnd_debug) printf(gettext("delete principal %s completed\n"), argp->warning_name); return (TRUE); } else { res->status = 1; if (kwarnd_debug) printf(gettext("delete principal %s failed\n"), argp->warning_name); return (TRUE); } } static bool_t del_warning_pvt(char *warning_name) { cred_warning_list_t *cred_warning, *prev; rw_wrlock(&cred_lock); for (prev = NULL, cred_warning = cred_warning_list; cred_warning != NULL; prev = cred_warning, cred_warning = cred_warning->next) { if (strcmp(cred_warning->warn_name, warning_name) == 0) { if (!prev) cred_warning_list = cred_warning->next; else prev->next = cred_warning->next; free(cred_warning->warn_name); free(cred_warning); rw_unlock(&cred_lock); return (TRUE); } } rw_unlock(&cred_lock); return (FALSE); } /* * load the warn.conf file into the config_entry list. */ bool_t loadConfigFile(void) { char buffer[BUFSIZ]; FILE *cfgfile; bool_t retval = TRUE; if ((cfgfile = fopen(CONF_FILENAME, "r")) == NULL) { syslog(LOG_ERR, gettext( "could not open config file \"%s\"\n"), CONF_FILENAME); syslog(LOG_ERR, gettext( "using default options \"%s\"\n"), DEFAULT_CONFIG); retval = parseConfigLine(DEFAULT_CONFIG); } else { (void) memset(buffer, 0, sizeof (buffer)); while ((fgets(buffer, BUFSIZ, cfgfile) != NULL) && (retval == TRUE)) retval = parseConfigLine(buffer); fclose(cfgfile); } return (retval); } /* * Return TRUE if we get a valid opt and update flags appro. */ static bool_t cmp_renew_opts(char *opt, int *log_success, /* out */ int *log_failure) /* out */ { if (strncasecmp(opt, "log", sizeof ("log")) == 0) { *log_success = *log_failure = 1; } else if (strncasecmp(opt, "log-success", sizeof ("log-success")) == 0) { *log_success = 1; } else if (strncasecmp(opt, "log-failure", sizeof ("log-failure")) == 0) { *log_failure = 1; } else { if (kwarnd_debug) printf("cmp_renew_opts: renew bad opt=`%s'\n", opt ? opt : "null"); return (FALSE); } return (TRUE); } /* * Make the config_entry item for the config_entry_list, based on * buffer. The formats are * * [renew[:]] syslog|terminal