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

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


#ifndef lint
static char rcsid_authorize_c[] = "$Header:authorize.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 includes the routines to authorize database modifications.
 * Currently, the password is stored in a file readable only by root in
 * the server's directory.
 */

#include	<pwd.h>
#include	<stdio.h>
#include	<strings.h>
#include	<sys/types.h>
#include	<machineio/vdconst.h>
#include	<ctype.h>
#include	"rvd_types.h"
#include	"ctl_pkt.h"
#include	"extern.h"
#ifdef	KERBEROS
#include	<krb.h>
#endif	KERBEROS


#define	PFILE		"/etc/rvd/rvdauthor" /* (don't want it too obvious) */
#define	ACLFILE		"/site/rvd/acl/" /* It's pretty obvious.	*/
#define ACLLEN		2*VD_CAPAB_LEN	 /* Length of file name string. */

char	op_passw[VD_CAPAB_LEN+1];	/* storage for operations password. */
char	op_aclfile[] = "/site/rvd/acl/OP.acl";	/* ops access list name. */

char	ad_passw[VD_CAPAB_LEN+1];	/* storage for admin password. */
char	ad_aclfile[] = "/site/rvd/acl/AD.acl";	/* admin access list name. */

char	sh_passw[VD_CAPAB_LEN+1];	/* storage for shutdown password. */
char	sh_aclfile[] = "/site/rvd/acl/SH.acl";	/* shutdown access list name. */


/* Called to initialize the authorization scheme.  This reads in the
 * three passwords, if possible.  If at least the operations password
 * can be read then auth_init returns TRUE, otherwise it returns FALSE.
 */
auth_init()
{
	register FILE	*pwf;		/* file descriptor */

	if ((pwf = fopen(PFILE, "r")) == NULL)
		return(FALSE);

	/* Read the operations password.  It is a failure if 
	 * the operations password does not exist.
	 */
	if (get_pass(op_passw, pwf) == FALSE) {
		(void)fclose(pwf);
		return(FALSE);
	}

	/* Read the administration password.
	 */
	if (get_pass(ad_passw, pwf) == FALSE) {
		(void)fclose(pwf);
		return(TRUE);
	}

	/* Read the shutdown password.
	 */
	(void)get_pass(sh_passw, pwf);

	(void)fclose(pwf);
	return(TRUE);
}



/* Return true iff the specified password matches either of the two
 * optional passwords, admin or shutdown, or matches the operations
 * password.  Consider it a match if there is no operations password.
 */
boolean
authorized(pass, ad_flag, sh_flag)
	char	*pass;			/* supplied password */
	boolean	ad_flag;		/* True => use admin password. */
	boolean	sh_flag;		/* True => use shutdown password. */
{
	if (ad_flag && ad_passw[0] != '\0' && (strcmp(ad_passw, pass) == 0))
		return(TRUE);
	if (sh_flag && sh_passw[0] != '\0' && (strcmp(sh_passw, pass) == 0))
		return(TRUE);

	if (op_passw[0] == '\0')		/* no password */
		return(TRUE);

	return(strcmp(op_passw, pass) == 0);
}

/* This routine returns true if it finds an entry in the password file.
 * Lines can be preceeded by '#' for comments, blank lines are skipped.
 */
boolean
get_pass(passw, pwf)
	char	*passw;
	FILE	*pwf;
{
	char	*cp;
	char	str[VD_CAPAB_LEN];
	char	line[4*VD_CAPAB_LEN];

	/* Loop until EOF or done.
	 */
	while (1) {
		/* Pick up the current line and substitute end
		 * of string for the newline, if any.
		 */
		if (fgets(line, 4*VD_CAPAB_LEN, pwf) == NULL)
			return(FALSE);
		if ((cp = rindex(line, '\n')) != NULL)
			*cp = '\0';
		if (line[0] == '\0')		/* Skip over blank lines. */
			continue;

		/* Parse the line into a string and 
		 * perform the parse-dependant action.
		 */
		
		switch (sscanf(line, "%s", str)) {

		    case 1:
			if (str[0] == '#')
				break;
			(void)strncpy(passw, str, VD_CAPAB_LEN);
			return(TRUE);

		    /* All done.  Get out of here.
		     */
		    case EOF:
		    default:
			return(FALSE);
		}
	}
}

/* Return true if the user is found on the operations list or on one
 * of the other privileged user lists specified by the flags.
 */
boolean
priv_user(name, ad_flag, sh_flag)
	char	*name;			/* user name */
	boolean	ad_flag;		/* True => use admin password. */
	boolean	sh_flag;		/* True => use shutdown password. */
{
	if (ismember(name, op_aclfile, FALSE))
		return(TRUE);
	if (ad_flag && ismember(name, ad_aclfile, FALSE))
		return(TRUE);
	if (sh_flag && ismember(name, sh_aclfile, FALSE))
		return(TRUE);
	return(FALSE);
}


/* Copy and canonicalize count characters from str1 to str2.
 * It returns a pointer to the end of the canonicalized string.
 * This routine canonicalizes NULL characters and is used only
 * for the Kerberos authenticator.
 */
char *
canon_copy(str1, str2, count)
	char	*str1;
	char	*str2;
	int	count;
{
	char	*cp1 = str1;
	char	*cp2 = str2;

	while (count-- > 0) {
		if (needesc(*cp1) || *cp1 == '\0')
			*cp2++ = '\\';
		*cp2++ = *cp1++;
	}
	return(cp2);
}


/* This routine appends an authenticator to the RVD control
 * message in sbuf.  It returns TRUE on success.
 *
 */
#ifdef	KERBEROS
boolean
get_auth(sbuf, server, myname, debug)
	char	*sbuf;		/* The RVD control buffer.     */
	char	*server;	/* The name of the RVD server. */
	char	*myname;	/* Name of this program. */
	boolean	debug;		/* Debug flag. */
{
	char	*cp;
	int	status;
	KTEXT_ST authent;
	char	realm[512];

	/* Get the Kerberos realm.
	 */
	if ((status = get_krbrlm(realm, 1)) != KSUCCESS) {
		if (debug)
			printf("%s: krb error was %s\n", 
				myname, krb_err_txt[status]);
		return(FALSE);
	}

	/* Create an authenticator.
	 */
	status = mk_ap_req(&authent,"rvdsrv",server,realm,NULL);
	if (status != KSUCCESS) {
		if (debug)
			printf("%s: krb error was %s\n", 
				myname, krb_err_txt[status]);
		return(FALSE);
	}

	/* Canonicalize and copy the authenticator to the end of
	 * the RVD control message with the field identifier, "auth=".
	 */
	cp = sbuf + strlen(sbuf);
	sprintf(cp, "auth=");
	cp += strlen(cp);
	cp = canon_copy(&authent, cp, authent.length + sizeof(int));
	*cp = '\n';
	return(TRUE);
}
#endif	KERBEROS
