/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:ctl_funs.c 12.0$ */
/* $ACIS:ctl_funs.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/rvd/server/RCS/ctl_funs.c,v $ */

#ifndef lint
static char *rcsid = "$Header:ctl_funs.c 12.0$";
#endif


#ifndef lint
static char rcsid_ctl_funs_c[] = "$Header:ctl_funs.c 12.0$";
#endif lint

/* Copyright 1984 by the Massachusetts Institute of Technology */
/* See permission and disclaimer notice in the file "notice.h" */
#include "notice.h"

/* This file contains the general-purpose server control functions: those 
 * handle displaying statistics, shutting down the server, etc.
 */

#include	<sys/types.h>
#include	<stdio.h>
#include	<netinet/in.h>

#include	"rvd_types.h"
#include	"logging.h"
#include	"ctl_msgs.h"
#include	"ctl_pkt.h"
#include	"extern.h"
#ifdef	KERBEROS
#include	<krb.h>
#endif	KERBEROS

static char	msg[512] = "";

/* Force a log of all externally-interesting statistics.
 */

/*ARGSUSED*/
ctl_lext(fhost, op, desc, nitem)

struct	sockaddr_in	*fhost;			/* foreign host requesting */
char	*op;					/* operation name */
struct	item	desc[];				/* arguments (none) */
int	nitem;					/* size of desc (zero) */
{
	char	*pw;
	char	*nonce;				/* nonce string */
	char	*uname;				/* Authenticated user name. */
	boolean	authent_ok;			/* Authenticator OK flag. */

	uname = NULL;
	authent_ok = FALSE;
	nonce = desc[ITM_LEXT_NONCE].it_val;
	if((pw = desc[ITM_LEXT_PASSW].it_val) == NULL)
		pw = "";

#ifdef	KERBEROS
    {
	KTEXT	authent;

	if ((authent = (struct ktext *)desc[ITM_LEXT_AUTH].it_val) != NULL) {
		uname = auth_to_user(authent, fhost->sin_addr);
		if (uname != NULL) {
			if (priv_user(uname, FALSE, FALSE))
				authent_ok = TRUE;
		} else {
			if (loglevel(LOG_CLIENT_ERROR)) {
				syslog(LOG_INFO, 
					"shutdown: authentication failed. (%s)",
					inet_ntoa(fhost->sin_addr));
			}
		}
	}
    }
#endif	KERBEROS

	if (!authent_ok) {
		if (!authorized(pw,FALSE,FALSE)) {
			if (loglevel(LOG_CLIENT_ERROR)) {
			    syslog(LOG_INFO,
			  "log external stats: unauthorized operation by %s,%s",
			  uname, inet_ntoa(fhost->sin_addr));
			}
			ctl_failure(fhost, op, nonce, "unauthorized operation");
			return;
		}
	}

	syslog(LOG_INFO, "%s", version_s1);
	syslog(LOG_INFO, "%s", version_s2);
	ctl_show();				/* show control stats */
	net_show();				/* show net stats */
	rw_show();				/* show read/write stats */
	ctl_success(fhost, op, nonce);
}


/* Force a log of all statistics.
 */

/*ARGSUSED*/
ctl_lall(fhost, op, desc, nitem)

struct	sockaddr_in	*fhost;			/* foreign host requesting */
char	*op;					/* operation name */
struct	item	desc[];				/* arguments (none) */
int	nitem;					/* size of desc (zero) */
{
	char	*pw;
	char	*nonce;				/* nonce string */
	char	*uname;				/* Authenticated user name. */
	boolean	authent_ok;			/* Authenticator OK flag. */

	uname = NULL;
	authent_ok = FALSE;
	nonce = desc[ITM_LALL_NONCE].it_val;
	if((pw = desc[ITM_LALL_PASSW].it_val) == NULL)
		pw = "";

#ifdef	KERBEROS
    {
	KTEXT	authent;

	if ((authent = (struct ktext *)desc[ITM_LEXT_AUTH].it_val) != NULL) {
		uname = auth_to_user(authent, fhost->sin_addr);
		if (uname != NULL) {
			if (priv_user(uname, FALSE, FALSE))
				authent_ok = TRUE;
		} else {
			if (loglevel(LOG_CLIENT_ERROR)) {
				syslog(LOG_INFO, 
					"shutdown: authentication failed. (%s)",
					inet_ntoa(fhost->sin_addr));
			}
		}
	}
    }
#endif	KERBEROS


	if (!authent_ok) {
		if (!authorized(pw, FALSE, FALSE)) {
			if (loglevel(LOG_CLIENT_ERROR)) {
				syslog(LOG_INFO, 
			    "log all statistics: unauthorized operation by %s",
			    inet_ntoa(fhost->sin_addr));
			}
			ctl_failure(fhost, op, nonce, "unauthorized operation");
			return;
		}
	}

	syslog(LOG_INFO, "%s", version_s1);
	syslog(LOG_INFO, "%s", version_s2);
	cn_show();				/* show conn. stats */
	ctl_show();				/* show control stats */
	net_show();				/* show net stats */
	pkt_show();				/* show packet stats */
	rw_show();				/* show read/write stats */
	spin_show();				/* show spin stats */
	ctl_success(fhost, op, nonce);
	rw_qlen_show();				/* show read/write queue */
						/* length statistics.    */
}


/* Truncate the log file.
 *
 * This doesn't do anything anymore.
 * It's just here for compatibility.
 */

/*ARGSUSED*/
ctl_ltrunc(fhost, op, desc, nitem)

struct	sockaddr_in	*fhost;			/* foreign host requesting */
char	*op;					/* operation name */
struct	item	desc[];				/* arguments (none) */
int	nitem;					/* size of desc (zero) */
{
	char	*pw;
	char	*nonce;				/* nonce string */

	nonce = desc[ITM_LTRUNC_NONCE].it_val;
	if((pw = desc[ITM_LTRUNC_PASSW].it_val) == NULL)
		pw = "";

	if(! authorized(pw,FALSE,FALSE)) {
		if (loglevel(LOG_CLIENT_ERROR)) {
			syslog(LOG_INFO,
				"log truncate: unauthorized operation by %s",
				inet_ntoa(fhost->sin_addr));
		}
		ctl_failure(fhost, op, nonce, "unauthorized operation");
		return;
	}

	if (loglevel(LOG_SPINS))
		syslog(LOG_INFO, "Truncation command received from %s",
		       inet_ntoa(fhost->sin_addr));

	ctl_success(fhost, op, nonce);
}


/* Change the error logging level.
 */

/*ARGSUSED*/
ctl_llev(fhost, op, desc, nitem)

struct	sockaddr_in	*fhost;			/* foreign host requesting */
char	*op;					/* operation name */
struct	item	desc[];				/* arguments (none) */
int	nitem;					/* size of desc (zero) */
{
	unsigned lev;				/* new log level */
	char	*pw;
	char	*nonce;				/* nonce string */
	char	*uname;				/* Authenticated user name. */
	boolean	authent_ok;			/* Authenticator OK flag. */

	uname = NULL;
	authent_ok = FALSE;
	nonce = desc[ITM_LLEV_NONCE].it_val;
	if((pw = desc[ITM_LLEV_PASSW].it_val) == NULL)
		pw = "";

	/* Make sure the given log level is a number.
	 */
	if (sscanf(desc[ITM_LLEV_LEV].it_val, "%d", &lev) != 1) {
		if (loglevel(LOG_CLIENT_ERROR))
			syslog(LOG_INFO,
			    "log level: invalid numeric field, (%s)",
			    inet_ntoa(fhost->sin_addr));
		ctl_failure(fhost, op, nonce, "invalid numeric field");
		return;
	}

#ifdef	KERBEROS
    {
	KTEXT	authent;

	if ((authent = (struct ktext *)desc[ITM_LLEV_AUTH].it_val) != NULL) {
		uname = auth_to_user(authent, fhost->sin_addr);
		if (uname != NULL) {
			if (priv_user(uname, TRUE, FALSE))
				authent_ok = TRUE;
		} else {
			if (loglevel(LOG_CLIENT_ERROR)) {
				syslog(LOG_INFO, 
				    "log level: authentication failed. (%s)",
				    inet_ntoa(fhost->sin_addr));
			}
		}
	}
    }
#endif	KERBEROS

	if (!authent_ok) {
		if (!authorized(pw,FALSE,FALSE)) {
			if (loglevel(LOG_CLIENT_ERROR)) {
			    syslog(LOG_INFO,
				"log level: unauthorized operation by %s,%s",
				uname, inet_ntoa(fhost->sin_addr));
			}
			ctl_failure(fhost, op, nonce, "unauthorized operation");
			return;
		}
	}

	if (loglevel(LOG_SPINS)) {
		if (authent_ok)
			syslog(LOG_INFO, 
			    "%s from host %s changed log level from %d to %d",
			    uname, inet_ntoa(fhost->sin_addr), log_flag, lev);
		else
			syslog(LOG_INFO, 
			    "host %s changed log level from %d to %d",
			    inet_ntoa(fhost->sin_addr), log_flag, lev);
	}

	log_flag = lev;
	ctl_success(fhost, op, nonce);
}


/* Shutdown the server.  Requires authorization.
 */

/*ARGSUSED*/
ctl_shut(fhost, op, desc, nitem)

struct	sockaddr_in	*fhost;			/* source host */
char	*op;					/* operation name */
register struct	item	desc[];			/* list of items */
int	nitem;					/* number of items (1) */
{
	char	*pw;
	char	*nonce;				/* nonce string */
	char	*uname;				/* Authenticated user name. */
	boolean	authent_ok;			/* Authenticator OK flag. */

	uname = NULL;
	authent_ok = FALSE;
	nonce = desc[ITM_SHUT_NONCE].it_val;
	if ((pw = desc[ITM_SHUT_PASSW].it_val) == NULL)
		pw = "";

#ifdef	KERBEROS
    {
	KTEXT	authent;

	if ((authent = (struct ktext *)desc[ITM_SHUT_AUTH].it_val) != NULL) {
		uname = auth_to_user(authent, fhost->sin_addr);
		if (uname != NULL) {
			if (priv_user(uname, FALSE, TRUE))
				authent_ok = TRUE;
		} else {
			if (loglevel(LOG_CLIENT_ERROR)) {
				syslog(LOG_INFO, 
					"shutdown: authentication failed. (%s)",
					inet_ntoa(fhost->sin_addr));
			}
		}
	}
    }
#endif	KERBEROS

	if (!authent_ok) {
		if (!authorized(pw,FALSE,TRUE)) {
			if (loglevel(LOG_CLIENT_ERROR)) {
			    syslog(LOG_INFO, 
				"shutdown: unauthorized operation by %s,%s",
				uname, inet_ntoa(fhost->sin_addr));
			}
			ctl_failure(fhost, op, nonce, "unauthorized operation");
			return;
		}
	}

	/* Print out user name if this was an authenticated shutdown.
	 */
	if (authent_ok)
		syslog(LOG_ALERT, "shutdown from host %s by %s",
				inet_ntoa(fhost->sin_addr), uname);
	else
		syslog(LOG_ALERT,
			"shutdown from host %s", inet_ntoa(fhost->sin_addr));

	cn_show();				/* show conn. stats */
	ctl_show();				/* show control stats */
	net_show();				/* show net stats */
	pkt_show();				/* show packet stats */
	rw_show();				/* show read/write stats */
	spin_show();				/* show spin stats */
	rw_qlen_show();				/* show read/write queue */
						/* length statistics.    */

	ctl_success(fhost, op, nonce);
	exit(1);
}

/* Set message.  Requires authorization.
 */

/*ARGSUSED*/
ctl_setm(fhost, op, desc, nitem)

	struct	sockaddr_in	*fhost;		/* source host */
	char	*op;				/* operation name */
	register struct	item	desc[];		/* list of items */
	int	nitem;				/* number of items (1) */
{
	char	*pw;				/* password. */
	char	*nonce;				/* nonce string */
	char	*uname;				/* Authenticated user name. */
	boolean	authent_ok;			/* Authenticator OK flag. */

	uname = NULL;
	authent_ok = FALSE;
	nonce = desc[ITM_SETM_NONCE].it_val;
	if ((pw = desc[ITM_SETM_PASSW].it_val) == NULL)
		pw = "";

#ifdef	KERBEROS
    {
	KTEXT	authent;

	if ((authent = (struct ktext *)desc[ITM_SETM_AUTH].it_val) != NULL  &&
	    (uname = auth_to_user(authent, fhost->sin_addr)) != NULL) {
		if (priv_user(uname, TRUE, FALSE))
			authent_ok = TRUE;
	}
    }
#endif	KERBEROS

	if (!authent_ok) {
		if (!authorized(pw, TRUE, FALSE)) {
			if (loglevel(LOG_CLIENT_ERROR)) {
			    syslog(LOG_INFO,
				"set message: unauthorized operation by %s",
				inet_ntoa(fhost->sin_addr));
			}
			ctl_failure(fhost, op, nonce, "unauthorized operation");
			return;
		}
	}

	if (desc[ITM_SETM_MESSAGE].it_val != NULL)
		(void)strcpy(msg, desc[ITM_SETM_MESSAGE].it_val);
	else
		msg[0] = '\0';

	if (loglevel(LOG_SPINS)) {
		if (uname != NULL) {
			syslog(LOG_INFO, "%s from %s changed message to:",
			       uname, inet_ntoa(fhost->sin_addr));
		} else {
			syslog(LOG_INFO, "%s changed message to:",
			       inet_ntoa(fhost->sin_addr));
		}
		syslog(LOG_INFO, "    %s", msg);
	}
	ctl_success(fhost, op, nonce);
}

/* Get message.  It only returns the message if one exists.
 */

/*ARGSUSED*/
ctl_getm(fhost, op, desc, nitem)

struct	sockaddr_in	*fhost;			/* source host */
char	*op;					/* operation name */
struct	item	desc[];				/* list of items */
int	nitem;					/* number of items (1) */
{
	char	replbuf[512];
	char	*cp;
	char	*nonce;				/* nonce string */

	csprintf(replbuf, "success=%s\n", op);
	cp = replbuf + strlen(replbuf);
		
	if ((nonce = desc[ITM_GETM_NONCE].it_val) != (char *)NULL) {
		sprintf(cp, "nonce=%s\n", nonce);
		cp = replbuf + strlen(replbuf);
	}
	if (msg[0] != NULL)
		csprintf(cp, "message=%s\n", msg);

	ctl_send(fhost, replbuf, strlen(replbuf));
}

/* Require authorization.  Read password file.
 */

/*ARGSUSED*/
ctl_rauth(fhost, op, desc, nitem)

struct	sockaddr_in	*fhost;			/* source host */
char	*op;					/* operation name */
struct	item	desc[];				/* list of items */
int	nitem;					/* number of items (1) */
{
	if (loglevel(LOG_SPINS))
		syslog(LOG_INFO, "authorization requested (%s)",
			inet_ntoa(fhost->sin_addr));
	(void) auth_init();
	++requests_enabled;
	ctl_success(fhost, op, desc[ITM_RAUTH_NONCE].it_val);
}


#ifdef	TEST_SERVER
/* Enter test mode */

static	int	test_mode = 0;
static	struct	in_addr	test_host;
static	char	spin_err_buf[512];
static	char	*spin_err_ptr;
static	char	read_err_buf[512];
static	char	*read_err_ptr;
static	char	write_err_buf[512];
static	char	*write_err_ptr;

/*ARGSUSED*/
ctl_tenter(fhost, op, desc, nitem)
struct	sockaddr_in	*fhost;			/* source host */
char	*op;					/* operation name */
struct	item	desc[];				/* list of items */
int	nitem;					/* number of items (1) */
{
	char	*nonce;				/* nonce string */

	nonce = desc[ITM_TENTER_NONCE].it_val;

	if(!authorized(desc[ITM_TENTER_PASSW].it_val,FALSE,FALSE)) {
		if (loglevel(LOG_CLIENT_ERROR))
			syslog(LOG_INFO, "Enter test mode: unauthorized operation by %s",
			  inet_ntoa(fhost->sin_addr));
		ctl_failure(fhost, op, nonce, "unauthorized operation");
		return;
	}
	if(test_mode) {
		if (loglevel(LOG_CLIENT_ERROR))
			syslog(LOG_INFO, "Enter test mode: already in test mode by %s",
			  inet_ntoa(fhost->sin_addr));
		ctl_failure(fhost, op, nonce, "Already in Test Mode");
		return;
	}

	if(desc[ITM_TENTER_SPIN_ERROR].it_val != NULL)
		spin_err_ptr =
			strcpy(spin_err_buf, desc[ITM_TENTER_SPIN_ERROR].it_val);
	if(desc[ITM_TENTER_READ_ERROR].it_val != NULL)
		read_err_ptr = 
			strcpy(read_err_buf, desc[ITM_TENTER_READ_ERROR].it_val);
	if(desc[ITM_TENTER_WRITE_ERROR].it_val != NULL)
		write_err_ptr = 
			strcpy(write_err_buf, desc[ITM_TENTER_WRITE_ERROR].it_val);

	test_host = fhost->sin_addr;
	test_mode = 1;

	ctl_success(fhost, op, nonce);
}

test_get_spin_err(fhost)
struct	in_addr	fhost;
{
char	*index();
int	error = 0;

	if(test_mode && spin_err_ptr && test_host.s_addr == fhost.s_addr) {
		sscanf(spin_err_ptr, "%d", &error);
		if((spin_err_ptr = index(spin_err_ptr, ',')) != 0)
			spin_err_ptr++;
	}
	return(error);
}

test_get_read_err(fhost)
struct	in_addr	fhost;
{
char	*index();
int	error = 0;

	if(test_mode && read_err_ptr && test_host.s_addr == fhost.s_addr) {
		sscanf(read_err_ptr, "%d", &error);
		if((read_err_ptr = index(read_err_ptr, ',')) != 0)
			read_err_ptr++;
	}
	return(error);
}

test_get_write_err(fhost)
struct	in_addr	fhost;
{
char	*index();
int	error = 0;

	if(test_mode && write_err_ptr && test_host.s_addr == fhost.s_addr) {
		sscanf(write_err_ptr, "%d", &error);
		if((write_err_ptr = index(write_err_ptr, ',')) != 0)
			write_err_ptr++;
	}
	return(error);
}


/* Exit test mode */

/*ARGSUSED*/
ctl_texit(fhost, op, desc, nitem)
struct	sockaddr_in	*fhost;			/* source host */
char	*op;					/* operation name */
struct	item	desc[];				/* list of items */
int	nitem;					/* number of items (1) */
{
	test_mode = 0;
	spin_err_ptr = 0;
	read_err_ptr = 0;
	write_err_ptr = 0;
	ctl_success(fhost, op, desc[ITM_TEXIT_NONCE].it_val);
}
#endif	TEST_SERVER
