[comp.mail.sendmail] program "authorise"

tjh@cel.uucp (tim howard) (06/04/90)

		Program "authorise" for use with "sendmail"
		===========================================

Introduction
============
Along with the Sendmail Configuration Package UK-2.1, in the "support"
directory, I received "authorise".  I have recently tried to use this
for the first time.  It did not appear to have the desired effect.
When called from "sendmail.cf" it is passed more parameters than the
original version of "authorise" used to determine the "to_addr"
( destination address ).  "authorise.c" has been modified to use one
of these additional parameters as its "to_addr".  The modified version
seems to give more meaningful results in this application.


The Application
===============
In order to modify the sendmail.cf file I used the UK-2.1 package by adding
",auth" to one line in "config.server2" ( Crosfield specific ) as follows :-

channel uucp file="randd.uucp.chn",ldomain="cel.uucp",sysname="server2",auth

This resulted in the following pair of lines ( split for this message ) in
"sendmail.cf" :-

Muucp, F=sFDMuh, S=23, R=23, M=300000,
        P=/usr/lib/authorise, A=authorise uucp $g $h /usr/bin/uux - -r -gA
	$h!rmail ($u)

The Analysis
============

"authorise.c" was modified to print the command line arguments to a file.  This
typically produced :-

Command line arguments ( argv ) are:- uucp cel.uucp!tjh stl /usr/bin/uux - -r
-gA stl!rmail (nowhere.co.uk!infoserver) 

From which it can be seen that the augument immediately after the "from_addr"
( who is sending ) is, in this case, the single word "stl", and that further
along the list is the longer "(nowhere.co.uk!infoserver)".  If the purpose
of running "authorise" is, for example, to prevent users sending to
info-servers then, although "stl" may be regarded as a valid "to_addr" the
system will not work as intended if left as it was.

The Fix
=======

The main "fix" is to use the 9th parameter rather than the 3rd as the "to_addr".
In addition, originally for debugging, a log file has been introduced.

Here is the source code ( 267 lines with not much after it except a plea for
comments ) :-

------------------------------------------------------------------------------

/*
 *  authorise  -  sendmail authorisation program
 *
 *	Given a channel name, sender address and recipient address or
 *	host, it matches these against entries in an authorisation
 *	file to see if permission is granted to send the mail.
 *
 *	If successful, the mailer interface is called; else the 
 *	appropriate error status is returned to sendmail.
 *
 *	Written by Jim Crammond.	<jac@ic.doc>	5/87
 *	major modifications Tim Howard / A Gray (cel)  June 90
 */
#include <stdio.h>
#include <sysexits.h>
#include <sys/types.h>			/* for ascii_timenow */
#include <sys/time.h> 			/* for ascii_timenow */

#define AUTHFILE	"/usr/lib/authorisations"

/*** #define DEBUG	***/
#define LOGGING
#define LOG_FILE		"/usr/spool/uucp/auth_debug"    /* addition TJH */

#define	CHANSIZE	64
#define	ADDRSIZE	256
#define LINESIZE	1024

char	a_chan[CHANSIZE];
char	a_from[ADDRSIZE];
char	a_to[ADDRSIZE];

char	*authfile = AUTHFILE;

char str[26];				/* for ascii_timenow */
char* ascii_timenow();			/* needed before a call to it */

int	negative = 0;

main(argc, argv)
int	argc;
char	*argv[];
{
	char	*progname, *channel;
	char	*from_addr, *to_addr;
	FILE	*afp, *fopen();
	FILE	*log_file;		/* addition TJH */
	char	line[LINESIZE];
	int	cnt, nfields,i;
	register char *p;
	char	*index();
	int	gotmatch = 0;
	extern int errno;

	progname  = *argv++;

#ifdef LOGGING
	if ((log_file = fopen(LOG_FILE, "a")) == NULL)
        {       printf("%s: warning: cannot open debug file\n",progname);
		exit(errno);
        }
	fprintf(log_file,"----------------------------------------------------------------------------\n");
	fprintf(log_file,"%s \n", ascii_timenow());
/*	fprintf(log_file,"Command line arguments ( argv ) are:- ");
 *	for(i=0;argv[i] != NULL;i++) fprintf(log_file,"%s ",argv[i]);
 *	fprintf(log_file,"\n");
 */
#endif LOGGING

	if (argv[0][0] == '-' && argv[0][1] == 'f')
	{	authfile = argv[1];
		argc -= 2;
		argv += 2;
	}

	if (argc < 4)
	{	printf("usage: %s [-f authfile] channel from to command [args]\n", progname);

#ifdef LOGGING 
                fclose(log_file);
#endif LOGGING 
		exit(EX_USAGE);
	}

	channel   = *argv++;
	from_addr = *argv++;
	to_addr   = *argv++;
	
/************ Major change at Crosfield Electronics Ltd ( cel ) follows *********
*
* when called from UK2.1 sendmail.cf the "to_addr" is not the next argument
* after the "from_addr"
* ( but the pointer does need to have been incremented )
* there will be 9 arguments ( no -f authfile ? ) and hence argc here will be 10
*
*/
if ( argc == 10 )
{
	to_addr   = argv[5];
}
/************ end of major change at "cel" *****************/

	if ((afp = fopen(authfile, "r")) == NULL)
	{	printf("warning: cannot open authorisation file\n");
		gotmatch = 1;
	}

	while (!gotmatch && fgets(line, sizeof(line), afp))
	{	cnt++;
		if ((p = index(line, '\n')) != NULL)
			*p = '\0';
		if ((p = index(line, '#')) != NULL)
			*p = '\0';
		
		for (p=line; *p == ' ' && *p == '\t'; p++)
			;

		if (*p == '\0')
			continue;

		nfields = sscanf(p, "%s %s %s", a_chan, a_from, a_to);

		if (nfields != 3)
		{	printf("warning: line %d ignored: \"%s\"\n", cnt, line);
			continue;
		}

		negative = 0;
		if (strcmp(channel, a_chan) == 0 &&
		    match(from_addr, a_from) && match(to_addr, a_to))
		{	if (negative > 0)
				gotmatch = -1;
			else
				gotmatch = 1;
		}

#ifdef DEBUG
	printf("%d: %s - %s\n", cnt, line,
			gotmatch ? "matched" : "no match");
#endif DEBUG
	}

#ifdef LOGGING
	fprintf(log_file,"%s %s line=%d ", progname, authfile, cnt );

	switch(gotmatch)
	{	case 1:
        		fprintf(log_file," authorised ");
		break;

		case 0:
			fprintf(log_file," denied_by_default " );
		break;

		default:
			fprintf(log_file," actively_denied " );
		break;
	}
	fprintf(log_file," %s %s \n",  from_addr, to_addr );

#endif LOGGING
	if (gotmatch <= 0)
	{	printf("%s: %s is not authorised to send to host/address %s\n",
			progname, from_addr, to_addr);
#ifdef LOGGING
		fclose(log_file);
#endif LOGGING
		exit(EX_NOPERM);
	}

#ifdef LOGGING
/*	fprintf(log_file,"About to try to execute ");
 *      for(i=0;argv[i] != NULL;i++) fprintf(log_file,"%s ",argv[i]);
 *      fprintf(log_file,"\n");
 */
	fclose(log_file);
#endif LOGGING

	execv(argv[0], argv);

	printf("%s: cannot exec %s\n", progname, argv[0]);
	exit(EX_UNAVAILABLE);
}


/*
 *  MATCH  --  match the strings s1 and s2.
 *		s2 can contain wildcards and lists
 */
match(s1, s2)
char	*s1, *s2;
{
	char	lbuf[ADDRSIZE];
	char	*rest, *lp;
	char	*index();

	if (*s2 == '\\')					/*  escape  */
	{	if (*s1 == *(s2+1) && match(s1+1, s2+2))
			return(1);
	}

	else if (*s2 == '*')					/*  wildcard  */
	{	if (match(s1, ++s2))
			return(1);

		while (*s1++)
		{	if (match(s1, s2))
				return(1);
		}
	}

	else if (*s2 == '{' && (rest = index(++s2, '}')))	/*  list  */
	{	rest++;
		lp = lbuf;

		while (s2 != rest)
		{	while (*s2 && *s2 != ',' && *s2 != '}')
				*lp++ = *s2++;
			strcpy(lp, rest);

			if (match(s1, lbuf))
				return(1);

			lp = lbuf;
			s2++;
		}
	}

	else if (*s2 == '^') 				/*  negative match  */
	{	if (match(s1, ++s2))
		{	negative++;
			return(1);
		}
	}

	else if (*s1 == *s2)					/*  literal  */
	{	if (*s1 == '\0')
			return(1);

		if (match(++s1, ++s2))
			return(1);
	}

	return(0);
}

/* --------------------------------------------------------------------- */

/* ASCII_TIMENOW  .. return a pointer to an ascii string containing the
                     current date and time in date(1) format 
		     
		     A. Gray 21/5/90 
*/

char* ascii_timenow()
{
	time_t stime,timenow;
	struct tm *ltime;
	int time();

	stime = time(0);            /* get current system time */
	ltime = localtime(&stime);  /* apply any local time offset inc DST */
	strcpy(str,asctime(ltime)); /* convert to a printable string */

	str[24] = '\0';       /* delete the newline that asctime puts on */
	return(str);
}



------------------------------------------------------------------------------


Comments please.


-- 
Tim Howard
Crosfield Electronics Ltd ( cel )
Voice 0442-230000 x 3406