# # 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 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2020 Joyent, Inc. TESTPROG = kwarndtest PROG= ktkt_warnd MANIFEST= ktkt_warn.xml KWARNDOBJS = kwarnd.o kwarnd_svc.o kwarnd_proc.o kwarnd_generic.o kwarnd_send.o KWARNTOBJS = kwarndtest.o G_OBJS = kwarnd_xdr.o OBJS = $(KWARNDOBJS) $(KWARNTOBJS) $(G_OBJS) SRCS = $(OBJS:.o=.c) RSRC = kwarnd_xdr.c kwarnd_svc.c kwarnd.h CLOBBERFILES += $(TESTPROG) include ../../Makefile.cmd include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 ROOTMANIFESTDIR= $(ROOTSVCNETWORKSECURITY) POFILE = $(PROG).po POFILES = generic.po CPPFLAGS += -D_REENTRANT CERRWARN += -Wno-unused-variable CERRWARN += -Wno-unused-function CERRWARN += -Wno-implicit-function-declaration CERRWARN += -Wno-parentheses # not linted SMATCH=off CPPFLAGS += -I../../lib/gss_mechs/mech_krb5/include \ -I$(SRC)/lib/gss_mechs/mech_krb5 \ -I$(SRC)/lib/gss_mechs/mech_krb5/include \ -I$(SRC)/uts/common/gssapi/mechs/krb5/include ktkt_warnd : MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB) ktkt_warnd : LDFLAGS += $(KRUNPATH) $(MAPFILES:%=-Wl,-M%) ktkt_warnd : LDLIBS += -lnsl LDFLAGS += $(KRUNPATH) LDLIBS += $(KMECHLIB) .KEEP_STATE: all: $(PROG) $(TESTPROG) $(PROG): $(G_OBJS) $(KWARNDOBJS) $$(MAPFILES) $(LINK.c) $(KWARNDOBJS) $(G_OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) # the client entry points (kwarn_*_warning) are now avail in mech_krb5.so $(TESTPROG): $(KWARNTOBJS) $(LINK.c) $(KWARNTOBJS) -o $@ $(LDLIBS) $(POST_PROCESS) # Hammerhead: pre-generated (rpcgen + GNU cpp truncation bug) # kwarnd.h, kwarnd_svc.c, kwarnd_xdr.c are now committed source files. $(OBJS): kwarnd.h # note that nightly depends on having all of the derived # .c files built here on 'make install', even though this # module doesn't use all of those files. install: $(KRB5LIBPROG) $(RSRC) $(ROOTMANIFEST) check: $(CHKMANIFEST) clean: $(RM) $(OBJS) @# Hammerhead: do not delete pre-generated $(RSRC) include ../../Makefile.targ #additional dependencies $(LIBRARY) : $(OBJS) $(DYNLIB) : $(PICS) FRC: $(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ generic.po: FRC $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Usermode daemon which is responsible for sending kerberos credentials * expiration warnings to the user, syslog or snmp (eventually), depending * on how it is configured through /etc/krb5/warn.conf. * the code in this file was borrowed from gssd.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kwarnd.h" #define MAXTHREADS 64 int kwarnd_debug = 0; /* enable debugging printfs */ extern void kwarnprog_1(struct svc_req *, register SVCXPRT *); static void usage(void); static void detachfromtty(void); extern int svc_create_local_service(void (*) (), ulong_t, ulong_t, char *, char *); extern void kwarnd_check_warning_list(void); extern bool_t loadConfigFile(void); /* following declarations needed in rpcgen-generated code */ int _rpcpmstart = 0; /* Started by a port monitor ? */ int _rpcfdtype; /* Whether Stream or Datagram ? */ int _rpcsvcdirty; /* Still serving ? */ mutex_t _svcstate_lock = ERRORCHECKMUTEX; char myhostname[MAXHOSTNAMELEN] = {0}; char progname[MAXNAMELEN] = {0}; int main(int argc, char **argv) { SVCXPRT *transp; extern int optind; int c; char mname[FMNAMESZ + 1]; int rpc_svc_mode = RPC_SVC_MT_AUTO; /* set locale and domain for internationalization */ setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif textdomain(TEXT_DOMAIN); (void) strlcpy(progname, basename(argv[0]), sizeof (progname)); /* * Take special note that "getuid()" is called here. This call is used * rather that app_krb5_user_uid(), to ensure ktkt_warnd(8) is running * as root. */ #ifdef DEBUG (void) setuid(0); /* DEBUG: set ruid to root */ #endif /* DEBUG */ if (getuid()) { (void) fprintf(stderr, gettext("[%s] must be run as root\n"), argv[0]); #ifdef DEBUG (void) fprintf(stderr, gettext(" warning only\n")); #else /* !DEBUG */ exit(1); #endif /* DEBUG */ } while ((c = getopt(argc, argv, "d")) != -1) switch (c) { case 'd': /* turn on debugging */ kwarnd_debug = 1; break; default: usage(); } if (optind != argc) { usage(); } (void) gethostname(myhostname, sizeof (myhostname)); /* * Started by inetd if name of module just below stream * head is either a sockmod or timod. */ if (!ioctl(0, I_LOOK, mname) && ((strcmp(mname, "sockmod") == 0) || (strcmp(mname, "timod") == 0))) { char *netid; struct netconfig *nconf; openlog("kwarnd", LOG_PID, LOG_DAEMON); if ((netid = getenv("NLSPROVIDER")) == NULL) { netid = "ticotsord"; } if ((nconf = getnetconfigent(netid)) == NULL) { syslog(LOG_ERR, gettext("cannot get transport info")); exit(1); } if (strcmp(mname, "sockmod") == 0) { if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { syslog(LOG_ERR, gettext("could not get the " "right module")); exit(1); } } /* XXX - is nconf even needed here? */ if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { syslog(LOG_ERR, gettext("cannot create server handle")); exit(1); } /* * We use a NULL nconf because KWARNPROG has already been * registered with rpcbind. */ if (!svc_reg(transp, KWARNPROG, KWARNVERS, kwarnprog_1, NULL)) { syslog(LOG_ERR, gettext("unable to register " "(KWARNPROG, KWARNVERS)")); exit(1); } if (nconf) freenetconfigent(nconf); } else { if (!kwarnd_debug) detachfromtty(); openlog("kwarnd", LOG_PID, LOG_DAEMON); if (svc_create_local_service(kwarnprog_1, KWARNPROG, KWARNVERS, "netpath", "kwarnd") == 0) { syslog(LOG_ERR, gettext("unable to create service")); exit(1); } } if (kwarnd_debug) { fprintf(stderr, gettext("kwarnd start: \n")); } (void) signal(SIGCHLD, SIG_IGN); if (thr_create(NULL, 0, (void *(*)(void *))kwarnd_check_warning_list, NULL, THR_DETACHED | THR_DAEMON | THR_NEW_LWP, NULL)) { syslog(LOG_ERR, gettext("unable to create cache_cleanup thread")); exit(1); } if (!loadConfigFile()) { syslog(LOG_ERR, gettext("could not read config file\n")); exit(1); } if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { syslog(LOG_ERR, gettext("unable to set automatic MT mode")); exit(1); } svc_run(); abort(); /*NOTREACHED*/ #ifdef lint return (1); #endif } static void usage(void) { (void) fprintf(stderr, gettext("usage: %s [-d]\n"), progname); exit(1); } /* * detach from tty */ static void detachfromtty(void) { switch (fork()) { case -1: perror(gettext("kwarnd: can not fork")); exit(1); /*NOTREACHED*/ case 0: break; default: exit(0); } /* * Close existing file descriptors, open "/dev/null" as * standard input, output, and error, and detach from * controlling terminal. */ closefrom(0); (void) open("/dev/null", O_RDONLY); (void) open("/dev/null", O_WRONLY); (void) dup(1); (void) setsid(); } /*ARGSUSED*/ int kwarnprog_1_freeresult(SVCXPRT *transport, xdrproc_t xdr_res, caddr_t res) { xdr_free(xdr_res, res); return (1); } /* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _KWARND_H_RPCGEN #define _KWARND_H_RPCGEN #include #ifndef _KERNEL #include #include #endif /* !_KERNEL */ /* * Copyright 1990-2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * RPC protocol information for kwarnd, the usermode daemon that * assists kinit, kdestroy with kwarnapi. It is kwarnd that executes all * kwarnapi calls and sends credential cache expiration warning messages. * * File generated from kwarnd.x */ #include #include #include #include typedef char *WARNING_NAME_T; typedef u_int OM_UINT32; struct kwarn_add_warning_arg { WARNING_NAME_T warning_name; long cred_exp_time; }; typedef struct kwarn_add_warning_arg kwarn_add_warning_arg; struct kwarn_add_warning_res { OM_UINT32 status; }; typedef struct kwarn_add_warning_res kwarn_add_warning_res; struct kwarn_del_warning_arg { WARNING_NAME_T warning_name; }; typedef struct kwarn_del_warning_arg kwarn_del_warning_arg; struct kwarn_del_warning_res { OM_UINT32 status; }; typedef struct kwarn_del_warning_res kwarn_del_warning_res; #define KWARNPROG 100134 #define KWARNVERS 1 #define KWARN_ADD_WARNING 1 extern enum clnt_stat kwarn_add_warning_1(); extern bool_t kwarn_add_warning_1_svc(); #define KWARN_DEL_WARNING 2 extern enum clnt_stat kwarn_del_warning_1(); extern bool_t kwarn_del_warning_1_svc(); extern int kwarnprog_1_freeresult(); /* the xdr functions */ extern bool_t xdr_WARNING_NAME_T(); extern bool_t xdr_OM_UINT32(); extern bool_t xdr_kwarn_add_warning_arg(); extern bool_t xdr_kwarn_add_warning_res(); extern bool_t xdr_kwarn_del_warning_arg(); extern bool_t xdr_kwarn_del_warning_res(); #endif /* !_KWARND_H_RPCGEN */ %/* % * Copyright 1990-2002 Sun Microsystems, Inc. All rights reserved. % * Use is subject to license terms. % */ % %/* % * RPC protocol information for kwarnd, the usermode daemon that % * assists kinit, kdestroy with kwarnapi. It is kwarnd that executes all % * kwarnapi calls and sends credential cache expiration warning messages. % * % * File generated from kwarnd.x % */ % % %#include %#include %#include %#include % /* * These are the definitions for the interface to KWARND. */ #define MAX_PRINCIPAL_LEN 128 typedef string WARNING_NAME_T; typedef unsigned int OM_UINT32; struct kwarn_add_warning_arg { WARNING_NAME_T warning_name; long cred_exp_time; /* time in secs after epoch */ }; struct kwarn_add_warning_res { OM_UINT32 status; /* status of kwarn call */ }; struct kwarn_del_warning_arg { WARNING_NAME_T warning_name; }; struct kwarn_del_warning_res { OM_UINT32 status; /* status of kwarn call */ }; /* * The server accepts requests only from the loopback address. * Unix authentication is used, and the port must be in the reserved range. */ program KWARNPROG { version KWARNVERS { /* * Called by the client to add a cred expiration warning */ kwarn_add_warning_res KWARN_ADD_WARNING(kwarn_add_warning_arg) = 1; /* * Called by the client to delete a cred expiration warning */ kwarn_del_warning_res KWARN_DEL_WARNING(kwarn_del_warning_arg) = 2; } = 1; } = 100134; /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * stub module for kwarnd. */ #include #include #include "kwarnd.h" #include #include #include #include #include #include #include #include #include #include extern CLIENT *getkwarnd_handle(void); extern void resetkwarnd_handle(void); OM_UINT32 kwarn_add_warning(WARNING_NAME_T warning_name, int cred_exp_time) { kwarn_add_warning_arg args; kwarn_add_warning_res res; enum clnt_stat ret; boolean_t first = TRUE; CLIENT *clnt; /* check the input/output parameters */ if (warning_name == NULL || cred_exp_time == 0) return (1); rebind: /* get the client handle to kwarnd */ if ((clnt = getkwarnd_handle()) == NULL) { /* * Let app output if an error occurs but we'll syslog to * DEBUG to get error details if needed. */ syslog(LOG_DEBUG, "%s", clnt_spcreateerror("getkwarnd_handle")); return (1); } /* set the rpc parameters */ args.cred_exp_time = cred_exp_time; args.warning_name = warning_name; /* call the remote procedure */ memset(&res, 0, sizeof (res)); ret = kwarn_add_warning_1(&args, &res, clnt); if (ret != RPC_SUCCESS) { /* * Could have timed out due to the process restarting for * various reasons. Should attempt to rebind in the case * process is actually running. */ if (ret == RPC_TIMEDOUT && first) { resetkwarnd_handle(); first = FALSE; goto rebind; } return (1); } /* nothing to free */ return (res.status); } OM_UINT32 kwarn_del_warning(WARNING_NAME_T warning_name) { kwarn_del_warning_arg args; kwarn_del_warning_res res; enum clnt_stat ret; boolean_t first = TRUE; CLIENT *clnt; /* check the output parameters */ if (warning_name == NULL) return (1); rebind: /* get the client GSSD handle */ if ((clnt = getkwarnd_handle()) == NULL) { /* * Let app output if an error occurs but we'll syslog to * DEBUG to get error details if needed. */ syslog(LOG_DEBUG, "%s", clnt_spcreateerror("getkwarnd_handle")); return (1); } /* set the input parameters */ args.warning_name = warning_name; /* call the remote procedure */ memset(&res, 0, sizeof (res)); ret = kwarn_del_warning_1(&args, &res, clnt); if (ret != RPC_SUCCESS) { /* * Could have timed out due to the process restarting for * various reasons. Should attempt to rebind in the case * process is actually running. */ if (ret == RPC_TIMEDOUT && first) { resetkwarnd_handle(); first = FALSE; goto rebind; } return (1); } /* nothing to free */ return (res.status); } /* * Copyright (c) 1988-1999 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include extern int __rpc_negotiate_uid(int); /* * The highest level interface for server creation. * Copied from svc_generic.c and cmd/keyserv/key_generic.c, but adapted * to work only for TPI_CLTS semantics, and to be called only once * from kwarnd.c. Returns 1 (interface created) on success and 0 * (no interfaces created) on failure. */ int svc_create_local_service(void (*dispatch) (), /* Dispatch function */ u_long prognum, /* Program number */ u_long versnum, /* Version number */ char *nettype, /* Networktype token */ char *servname) /* name of the srvc */ { int num = 0; SVCXPRT *xprt; struct netconfig *nconf; struct t_bind *bind_addr; void *net; int fd; struct nd_hostserv ns; struct nd_addrlist *nas; if ((net = __rpc_setconf(nettype)) == 0) { (void) syslog(LOG_ERR, gettext("svc_create: could not read netconfig database")); return (0); } while (nconf = __rpc_getconf(net)) { if ((strcmp(nconf->nc_protofmly, NC_LOOPBACK)) || (nconf->nc_semantics != NC_TPI_COTS_ORD)) continue; if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) { (void) syslog(LOG_ERR, gettext("svc_create: %s: cannot open connection: %s"), nconf->nc_netid, t_errlist[t_errno]); break; } /* * Negotiate for returning the uid of the caller. * This should be done before enabling the endpoint for * service via t_bind() (called in svc_tli_create()) * so that requests to kwarnd contain the uid. */ if (__rpc_negotiate_uid(fd) != 0) { syslog(LOG_ERR, gettext("Could not negotiate for" " uid with loopback transport %s"), nconf->nc_netid); t_close(fd); break; } /* LINTED pointer alignment */ bind_addr = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); if ((bind_addr == NULL)) { (void) t_close(fd); (void) syslog(LOG_ERR, gettext("svc_create: t_alloc failed\n")); break; } ns.h_host = HOST_SELF; ns.h_serv = servname; if (!netdir_getbyname(nconf, &ns, &nas)) { /* Copy the address */ bind_addr->addr.len = nas->n_addrs->len; (void) memcpy(bind_addr->addr.buf, nas->n_addrs->buf, (int) nas->n_addrs->len); bind_addr->qlen = 8; netdir_free((char *) nas, ND_ADDRLIST); } else { (void) syslog(LOG_ERR, gettext("svc_create: no well known " "address for %s on %s\n"), servname, nconf->nc_netid); (void) t_free((char *) bind_addr, T_BIND); bind_addr = NULL; } xprt = svc_tli_create(fd, nconf, bind_addr, 0, 0); if (bind_addr) (void) t_free((char *) bind_addr, T_BIND); if (xprt == NULL) { (void) t_close(fd); (void) syslog(LOG_ERR, gettext("svc_create: svc_tli_create failed\n")); break; } else { (void) rpcb_unset(prognum, versnum, nconf); if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { (void) syslog(LOG_ERR, gettext("svc_create: cannot" " register %d vers %d on %s"), prognum, versnum, nconf->nc_netid); SVC_DESTROY(xprt); /* also t_closes fd */ break; } num = 1; break; } } __rpc_endconf(net); return (num); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* from kerbd_handle.c 1.3 92/01/29 SMI */ /* * kwarnd_handle.c, Interface to kwarnd * */ #include #include #include #include #include #include #include #include "kwarnd.h" #ifdef DEBUG #define dprt(msg) #else #define dprt(msg) #endif /* DEBUG */ CLIENT *kwarn_clnt; /* * Keep the handle cached. This call may be made quite often. */ CLIENT * getkwarnd_handle(void) { void *localhandle; struct netconfig *nconf; struct netconfig *tpconf; struct timeval wait_time; struct utsname u; static char *hostname; static bool_t first_time = TRUE; /* * Total timeout (in seconds) talking to kwarnd. */ #define TOTAL_TIMEOUT 5 if (kwarn_clnt) return (kwarn_clnt); if (!(localhandle = setnetconfig())) return (NULL); tpconf = NULL; if (first_time == TRUE) { if (uname(&u) == -1) { (void) endnetconfig(localhandle); return ((CLIENT *)NULL); } if ((hostname = strdup(u.nodename)) == (char *)NULL) { (void) endnetconfig(localhandle); return ((CLIENT *)NULL); } first_time = FALSE; } while (nconf = getnetconfig(localhandle)) { if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { if (nconf->nc_semantics == NC_TPI_COTS_ORD) { kwarn_clnt = clnt_tp_create(hostname, KWARNPROG, KWARNVERS, nconf); if (kwarn_clnt) { dprt("got COTS_ORD\n"); break; } } else { tpconf = nconf; } } } if ((kwarn_clnt == NULL) && (tpconf)) { /* Now, try the connection-oriented loopback transport */ kwarn_clnt = clnt_tp_create(hostname, KWARNPROG, KWARNVERS, tpconf); #ifdef DEBUG if (kwarn_clnt) { dprt("got COTS\n"); } #endif /* DEBUG */ } (void) endnetconfig(localhandle); /* * This bit of code uses an as yet unimplemented argument to * clnt_control(). CLSET_SVC_PRIV specifies that the underlying * loopback transport should be checked to ensure it is * connected to a process running as root. If so, the clnt_control() * call returns TRUE. If not, it returns FALSE. */ #ifdef CLSET_SVC_PRIV if (clnt_control(kwarn_clnt, CLSET_SVC_PRIV, NULL) != TRUE) { clnt_destroy(kwarn_clnt); kwarn_clnt = NULL; return (NULL); { #endif if (kwarn_clnt == NULL) return (NULL); kwarn_clnt->cl_auth = authsys_create("", getuid(), 0, 0, NULL); if (kwarn_clnt->cl_auth == NULL) { clnt_destroy(kwarn_clnt); kwarn_clnt = NULL; return (NULL); } wait_time.tv_sec = TOTAL_TIMEOUT; wait_time.tv_usec = 0; (void) clnt_control(kwarn_clnt, CLSET_TIMEOUT, (char *)&wait_time); return (kwarn_clnt); } void resetkwarnd_handle(void) { auth_destroy(kwarn_clnt->cl_auth); clnt_destroy(kwarn_clnt); kwarn_clnt = NULL; } /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * 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