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