#
# 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
Kerberos V5 warning messages daemon
/*
* 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