idc@cs.hw.ac.uk (Ian Crorie) (01/25/89)
Sorry for the delay in getting UK-2.1 out but our pad has been performing its yoyo impersonation. ---------- cut here ---------- #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -d ./Support` then mkdir ./Support echo "mkdir ./Support" fi if `test ! -s ./Support/Makefile` then echo "Writing ./Support/Makefile" cat > ./Support/Makefile << '\Rogue\Monster\' # Support programs for UK-Sendmail 2.1 SRCS = authorise.c muucp.c rmail.c uumailclean.c warn.c \ distribute mail-news checkaddr SysV.sh BINS = authorise muucp rmail uumailclean DESTS = /usr/local/lib/authorise /usr/lib/uucp/muucp /bin/rmail \ /usr/lib/uucp/uumailclean /usr/local/lib/distribute \ /usr/lib/news/mail-news BINMODE=755 SHMODE =755 support: $(BINS) install: $(DESTS) /usr/lib/uucp/muucp: muucp cp muucp $@ && chmod $(BINMODE) $@ /usr/lib/uucp/uumailclean: uumailclean cp uumailclean $@ && chmod $(BINMODE) $@ /bin/rmail: rmail cp rmail $@ && chmod $(BINMODE) $@ /usr/local/lib/authorise: authorise cp authorise $@ && chmod $(SHMODE) $@ /usr/local/lib/distribute: distribute cp distribute $@ && chmod $(SHMODE) $@ /usr/lib/news/mail-news: mail-news cp mail-news $@ && chmod $(SHMODE) $@ uumailclean: uumailclean.c warn.o $(CC) $@.c warn.o -o $@ $(CFLAGS) $(LDFLAGS) convert: SysV.sh cd ..; sh Support/SysV.sh clean: rm -f *.o $(BINS) \Rogue\Monster\ else echo "Will not over-write ./Support/Makefile" fi chmod 444 ./Support/Makefile if [ `wc -c < ./Support/Makefile` -ne 976 ] then echo 'Got' `wc -c < ./Support/Makefile` ', Expected ' 976 fi if `test ! -s ./Support/SysV.sh` then echo "Writing ./Support/SysV.sh" cat > ./Support/SysV.sh << '\Rogue\Monster\' #!/bin/sh # # This shell script converts the BSD dependent parts of the main shell # scripts into something suitable for SystemV. # # This must be run in the top level directory of the sendmail package. # for i in Config Dombuild Chnbuild do if [ ! -f $i ] then echo $i non-existent exit 1 fi if [ ! -f $i.bsd ] then mv $i $i.bsd fi done # The top level make file sed -e 's/echo -n/echo/' -e 's/\.\.\."/...\\c"/' Config.bsd > Config # The channel make file sed -e "s;fmt | sed;nroff | sed -e '/^$/d' -e;" Chnbuild.bsd > Chnbuild # The domain make file sed -e "s;tail -r \(...S12\);pr -t -n \1 | sort -r | sed 's/^......//';" \ -e "s;fmt | sed;nroff | sed -e '/^$/d' -e;" Dombuild.bsd > Dombuild \Rogue\Monster\ else echo "Will not over-write ./Support/SysV.sh" fi chmod 444 ./Support/SysV.sh if [ `wc -c < ./Support/SysV.sh` -ne 723 ] then echo 'Got' `wc -c < ./Support/SysV.sh` ', Expected ' 723 fi if `test ! -s ./Support/authorise.c` then echo "Writing ./Support/authorise.c" cat > ./Support/authorise.c << '\Rogue\Monster\' /* * 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 */ #include <stdio.h> #include <sysexits.h> #define AUTHFILE "/usr/lib/authorisations" #define CHANSIZE 64 #define ADDRSIZE 256 #define LINESIZE 1024 char a_chan[CHANSIZE]; char a_from[ADDRSIZE]; char a_to[ADDRSIZE]; char *authfile = AUTHFILE; int negative = 0; main(argc, argv) int argc; char *argv[]; { char *progname, *channel; char *from_addr, *to_addr; FILE *afp, *fopen(); char line[LINESIZE]; int cnt, nfields; register char *p; char *index(); int gotmatch = 0; progname = *argv++; 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); exit(EX_USAGE); } channel = *argv++; from_addr = *argv++; to_addr = *argv++; 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 } if (gotmatch <= 0) { printf("%s: %s is not authorised to send to host/address %s\n", progname, from_addr, to_addr); exit(EX_NOPERM); } 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); } \Rogue\Monster\ else echo "Will not over-write ./Support/authorise.c" fi chmod 444 ./Support/authorise.c if [ `wc -c < ./Support/authorise.c` -ne 3194 ] then echo 'Got' `wc -c < ./Support/authorise.c` ', Expected ' 3194 fi if `test ! -s ./Support/checkaddr` then echo "Writing ./Support/checkaddr" cat > ./Support/checkaddr << '\Rogue\Monster\' #!/bin/sh # shell script to verify what sendmail would do with given addresses # this version works for sendmail versions 4.40 and above verbose=false if [ $1 = "-v" ] then verbose=true shift fi trap "/bin/rm /tmp/ver.$$; exit" 1 2 3 15 while [ $# -ge 1 ] do echo -n "$1: " /usr/lib/sendmail -bt > /tmp/ver.$$ <<EOF 0 $1 EOF if grep -s 'ruleset 0 returns: "^V" "local"' /tmp/ver.$$ then if /usr/lib/sendmail -bv $1 > /tmp/ver.$$ then echo addr OK else sed -n -e '/deliverable/d' \ -e 's/\(.*\)\.\.\. \(.*\)/\2 (\1)/p' /tmp/ver.$$ fi if $verbose then aliases="" for a in `sed -n 's/\.\.\. deliverable//p' /tmp/ver.$$` do if [ "$a" = "$1" ] then echo "Routed to: channel=local, addr=$a" else aliases="$aliases $a" fi done if [ -n "$aliases" ] then echo "Aliased to:$aliases" $0 $aliases fi fi elif grep -s 'ruleset 0 returns: "^V" "error"' /tmp/ver.$$ then sed -n -e 's/"\([^"]*\)"/\1/g' \ -e '/ruleset 0 returns:/s/.*^X //p' /tmp/ver.$$ else echo addr OK if $verbose then sed -n '/ruleset 3 returns:/s/.*returns: //p' /tmp/ver.$$ | sed -n -e '$s/"\([^"]*\)"/\1/g' \ -e '$s/ \([!.@%]\) /\1/g' \ -e '$s/^/Normalised to: /p' sed -n '/ruleset 0 returns:/s/.*^V" //p' /tmp/ver.$$ | sed -e 's/"\([^"]*\)"/\1/g' \ -e 's/\(.*\) ^W \(.*\) ^X \(.*\)/Routed to: channel=\1, host=\2, addr=\3/'\ -e 's/\(.*\) ^X \(.*\)/Routed to: channel=\1, addr=\2/' \ -e 's/ \([!.@%]\) /\1/g' fi fi /bin/rm /tmp/ver.$$ shift done \Rogue\Monster\ else echo "Will not over-write ./Support/checkaddr" fi chmod 444 ./Support/checkaddr if [ `wc -c < ./Support/checkaddr` -ne 1605 ] then echo 'Got' `wc -c < ./Support/checkaddr` ', Expected ' 1605 fi if `test ! -s ./Support/distribute` then echo "Writing ./Support/distribute" cat > ./Support/distribute << '\Rogue\Monster\' #!/bin/sh # # Send a mail message to users on a distribution list. The message header is # altered mainly to allow error messages to be returned to the list maintainer. # This script should be setuid to one of sendmail's trusted users. # # Usage: put an entry into /usr/lib/aliases in one of the following forms: # # list-name: "|/usr/local/lib/distribute list-name user1 user2 ..." # list-name: "|/usr/local/lib/distribute list-name :include:pathname" # if [ $# -lt 2 ] then echo Usage: $0 list-name user1 user2 ... exit 64 fi dlist=$1 dusers="" shift # gather distribution list usernames for i in $* do case $i in :include:*) file=`expr $i : ':include:\(.*\)'` if [ -f $file ] then dusers="$dusers `cat $file`" else echo $i: No such file or directory exit 64 fi ;; *) dusers="$dusers $i" ;; esac done # adjust headers of incoming message sed -e '1,/^$/s/^$/EOH\ /' | sed -e '/^$/,$b' \ -e '/^From /d' \ -e '/^Via:/s//Original-Via:/' \ -e '/^Sender:/s//Original-Sender:/' \ -e '/^Acknowledge-To:/d' \ -e '/^Return-Receipt-To:/d' \ -e "/^EOH$/s//Sender: $dlist-request/" | /usr/lib/sendmail -f$dlist-request $dusers \Rogue\Monster\ else echo "Will not over-write ./Support/distribute" fi chmod 444 ./Support/distribute if [ `wc -c < ./Support/distribute` -ne 1189 ] then echo 'Got' `wc -c < ./Support/distribute` ', Expected ' 1189 fi if `test ! -s ./Support/mail-news` then echo "Writing ./Support/mail-news" cat > ./Support/mail-news << '\Rogue\Monster\' #!/bin/sh # # mail-news release 2.0 Copyright Jem Taylor 1988 # # Remove To: Cc: Received: and Via: fields, # ensure that there is a Subject: line or make Subject: (none), # re-order header lines to give # From: # Subject: # Message-ID: # Date: # Sender: # and move any other header lines to after these # /bin/awk ' BEGIN { true=1; false=0; head=true; subject="Subject: (none)" gateway="X-Mailer: mail-news 2.0.3" } # From: and Sender: lines must be login@host (real name) # instead of real name <login@host> # assume that <username> is one word - no quoted space - and at end of line /^From:.*>$/ { if (head==true) { user=substr ( $NF, 2, length($NF) -2 ) real = $2 for ( i=3; i<NF; i++ ) real = real " " $i from = "From: " user " (" real ")" next } } /^Sender:.*>$/ { if (head==true) { user=substr ( $NF, 2, length($NF) -2 ) real = $2 for ( i=3; i<NF; i++ ) real = real " " $i sender = "Sender: " user " (" real ")" next } } /^From:/ { if (head==true) { from = $0 ; next } } /^Sender:/ { if (head==true) { sender = $0 ; next } } /^Message-ID:/ { if (head==true) { messageid = $0 ; next } } /^Date:/ { if (head==true) { date = $0 ; next } } ##insist Subject: has something in it! /^Subject:.*[-=:)a-zA-Z@#!]/ { if (head==true) { subject=$0; next } } ## discard these and header continuation lines /^Received:/||/^Via:/|| \ /^To:/||/^Cc:/||\ /^ /||/^ / { if (head==true) next } ## move any other header lines to end of header /^.*:/ { if (head==true) { others[++ocnt]=$0; next } } ## break between head and body - ensure subject in head /^$/ { if (head==true) { head=false; if (from!="") print from print subject if (messageid!="") print messageid if (date!="") print date if (sender!="") print sender for (i=1;i<=ocnt;i++) print others[i] print gateway print "" next } } ## change inclusion mark since sender is not on hand ... /^>/ { if (head==false) { print "|" substr( $0, 2, length - 1 ) next } } ## all lines including body - unless explicitly skipped above { print $0 } ' | /usr/lib/news/inews $@ \Rogue\Monster\ else echo "Will not over-write ./Support/mail-news" fi chmod 444 ./Support/mail-news if [ `wc -c < ./Support/mail-news` -ne 2071 ] then echo 'Got' `wc -c < ./Support/mail-news` ', Expected ' 2071 fi if `test ! -s ./Support/muucp.c` then echo "Writing ./Support/muucp.c" cat > ./Support/muucp.c << '\Rogue\Monster\' /* * MUUCP -- Send mail over uucp, using the UUCP Transmission Format * * This simply prepends a unix from line of the appropriate form to the * message which is then passed on the uux. -Jim Crammond 12/88. * * usage: muucp [-r] [-gA] -f<from_addr> -H<uucpname> host user1 user2... */ #include <stdio.h> #include <sysexits.h> #include <sys/types.h> char uuxcmd[1024] = "/usr/bin/uux -"; char *perc_to_uucp(); char *tidy_addr(); char *index(); char *rindex(); FILE *popen(); main(argc, argv) int argc; char *argv[]; { FILE *out; char lbuf[BUFSIZ]; char *From = NULL; char *sysname = NULL; int i; time_t now; while (argc > 1 && argv[1][0] == '-') { switch(argv[1][1]) { case 'f': From = &argv[1][2]; break; case 'H': sysname = &argv[1][2]; break; case 'r': case 'g': case 'O': case 'x': strcat(uuxcmd, " "); strcat(uuxcmd, argv[1]); break; default: fprintf(stderr, "unknown flag %s\n", argv[1]); break; } argc--; argv++; } if (argc < 3 || From == NULL || sysname == NULL) { fprintf(stderr, "usage: muucp -f<From> -H<sysname> host users...\n"); exit(EX_USAGE); } /* add host!rmail (users) to cmd line */ strcat(uuxcmd, " "); strcat(uuxcmd, argv[1]); strcat(uuxcmd, "!rmail '("); argc--; argv++; while (--argc > 1) { strcat(uuxcmd, argv[1]); strcat(uuxcmd, " "); argv++; } strcat(uuxcmd, argv[1]); strcat(uuxcmd, ")'"); /* open pipe to uux */ out = popen(uuxcmd, "w"); /* generate the UUCP From line */ From = perc_to_uucp(From); From = tidy_addr(From); time(&now); fprintf(out, "From %s %.24s remote from %s\n", From, ctime(&now), sysname); /* pass stdin (mail message) to uux */ while (fgets(lbuf, sizeof lbuf, stdin)) fputs(lbuf, out); /* close pipe */ i = pclose(out); if ((i & 0377) != 0) { fprintf(stderr, "pclose: status 0%o\n", i); exit(EX_OSERR); } exit((i >> 8) & 0377); } /* ** PERC_TO_UUCP -- converts an address in Percent style into uucp style ** ** e.g. user%c.bitnet%b.arpa@a.uucp -> a.uucp!b.arpa!c.bitnet!user */ char * perc_to_uucp(addr) char *addr; { static char buf[512]; char *bp = buf; char *p; while ((p = rindex(addr,'@')) != NULL || (p = rindex(addr,'%')) != NULL) { *p++ = '\0'; while (*p) *bp++ = *p++; *bp++ = '!'; } strcpy(bp, addr); return(buf); } /* ** TIDY_ADDR -- strips duplicate domain names from start of address ** ** e.g. cs.hw.AC.UK!cs.hw.AC.UK!jim -> cs.hw.AC.UK!jim */ char * tidy_addr(addr) char *addr; { register char *p, *q; p = addr; while ((q = index(p, '!')) != NULL) { ++q; while (*p != '!' && *p == *q) { p++; q++; } if (*p != '!' && *q != '!') break; addr = ++p; } return(addr); } \Rogue\Monster\ else echo "Will not over-write ./Support/muucp.c" fi chmod 444 ./Support/muucp.c if [ `wc -c < ./Support/muucp.c` -ne 2720 ] then echo 'Got' `wc -c < ./Support/muucp.c` ', Expected ' 2720 fi if `test ! -s ./Support/rmail.c` then echo "Writing ./Support/rmail.c" cat > ./Support/rmail.c << '\Rogue\Monster\' #ifndef lint static char sccsid[] = "@(#)rmail.c 4.4 (Berkeley) 8/11/83"; #endif /* ** RMAIL -- UUCP mail server. ** ** This program reads the >From ... remote from ... lines that ** UUCP is so fond of and turns them into something reasonable. ** It calls sendmail giving it a -f option built from these ** lines. ** ** Modified to set the sender's hostname (deduced from first ** "remote from host" line) and convert the final "user" part ** from an address with '@' and '%' (which mmdf is so fond of) ** in to a 'pure' uucp address. -Jim Crammond, (hwcs!jim) 29/11/84 */ # include <stdio.h> # include <sysexits.h> typedef char bool; #define TRUE 1 #define FALSE 0 extern FILE *popen(); extern char *index(); extern char *rindex(); char *perc_to_uucp(); bool Debug; # define MAILER "/usr/lib/sendmail" main(argc, argv) char **argv; { FILE *out; /* output to sendmail */ char lbuf[512]; /* one line of the message */ char from[512]; /* accumulated path of sender */ char ufrom[128]; /* user on remote system */ char sys[64]; /* a system in path */ char sysname[64]; /* system received from */ char cmd[2000]; register char *cp; register char *uf; /* ptr into ufrom */ int linecount; int i; # ifdef DEBUG if (argc > 1 && strcmp(argv[1], "-T") == 0) { Debug = TRUE; argc--; argv++; } # endif DEBUG if (argc < 2) { fprintf(stderr, "Usage: rmail user ...\n"); exit(EX_USAGE); } (void) strcpy(from, ""); (void) strcpy(sysname, ""); (void) strcpy(ufrom, "/dev/null"); linecount = 0; while (fgets(lbuf, sizeof lbuf, stdin) != NULL) { if (strncmp(lbuf, "From ", 5) != 0 && strncmp(lbuf, ">From ", 6) != 0) break; linecount++; (void) sscanf(lbuf, "%*s %s", ufrom); cp = lbuf; uf = ufrom; while ((cp = index(cp, 'r')) != NULL) { #ifdef DEBUG if (Debug) printf("cp='%s'\n", cp); #endif if (sscanf(cp, "remote from %s", sys) == 1) { (void) strcat(from, sys); (void) strcat(from, "!"); if (linecount == 1) (void) strcpy(sysname, sys); break; } cp++; } #ifdef DEBUG if (Debug) printf("ufrom='%s', sys='%s', from now '%s'\n", uf, sys, from); #endif } /* * check for percent style addresses in user field */ if (index(uf, '@') != NULL || index(uf, '%') != NULL) uf = perc_to_uucp(uf); /* * if this is a new style "From domain!user .. remote from system" * header then don't prepend the system name to the from person */ if (linecount == 1 && (cp = index(uf, '!')) != NULL) { char *p = index(uf, '.'); if (p != NULL && p < cp) (void) strcpy(from, uf); else (void) strcat(from, uf); } else (void) strcat(from, uf); (void) sprintf(cmd, "%s -em -oi -f%s", MAILER, from); if (*sysname != '\0') { (void) strcat(cmd, " -oMs"); (void) strcat(cmd, sysname); } while (*++argv != NULL) { (void) strcat(cmd, " '"); if (**argv == '(') (void) strncat(cmd, *argv + 1, strlen(*argv) - 2); else (void) strcat(cmd, *argv); (void) strcat(cmd, "'"); } #ifdef DEBUG if (Debug) printf("cmd='%s'\n", cmd); #endif out = popen(cmd, "w"); fputs(lbuf, out); while (fgets(lbuf, sizeof lbuf, stdin)) fputs(lbuf, out); i = pclose(out); if ((i & 0377) != 0) { fprintf(stderr, "pclose: status 0%o\n", i); exit(EX_OSERR); } exit((i >> 8) & 0377); } /* ** PERC_TO_UUCP -- converts an address in Percent style into uucp style ** ** e.g. user%c.bitnet%b.arpa@a.uucp -> a.uucp!b.arpa!c.bitnet!user */ char * perc_to_uucp(addr) char *addr; { static char buf[512]; char *bp = buf; char *p; #ifdef DEBUG if (Debug) printf("perc_to_uucp(%s) ", addr); #endif while ((p = rindex(addr,'@')) != NULL || (p = rindex(addr,'%')) != NULL) { *p++ = '\0'; while (*p) *bp++ = *p++; *bp++ = '!'; } strcpy(bp, addr); #ifdef DEBUG printf("returns %s\n", buf); #endif return(buf); } \Rogue\Monster\ else echo "Will not over-write ./Support/rmail.c" fi chmod 444 ./Support/rmail.c if [ `wc -c < ./Support/rmail.c` -ne 3835 ] then echo 'Got' `wc -c < ./Support/rmail.c` ', Expected ' 3835 fi if `test ! -s ./Support/uumailclean.c` then echo "Writing ./Support/uumailclean.c" cat > ./Support/uumailclean.c << '\Rogue\Monster\' #include "uucp.h" #include <sys/types.h> #include <sys/stat.h> #ifdef BSD42 #include <sys/dir.h> #endif BSD42 #ifdef NDIR #include <ndir.h> #endif NDIR #ifdef LIBNDIR #include "LIBNDIR/ndir.h" #endif LIBNDIR /* * uumailclean - this program searches through the uucp spool directory * looking for mail files. Files which have been around for longer * than "failtime" hours will be returned to the sender. If a file * has been around longer than "warntime" hours, then a warning * message is sent (once) to the sender. * * If you use L.dirs to specify subdirectories, then failtime and * warntime can be specified as 3rd and 4th arguments to the directory * entries respectively: e.g. "C. 336 168 72" * By default, these times are 1 week and 3 days. * * Written by Jim Crammond <jim@cs.hw.ac.uk> 3/86 */ #define FAILTIME 168 /* default hours before returning the mail */ #define WARNTIME 72 /* default hours before sending a warning */ #define WARNFILE UUCPDIR/uucp/warnlist.mail" int warntime, failtime; main(argc, argv) char *argv[]; { #ifdef SUBCS FILE *fdirs; #endif SUBCS char file[NAMESIZE]; char cdir[ MAXFULLNAME ]; char *flds[10]; int nflds, ret; int orig_uid = getuid(); strcpy(Progname, "uumailclean"); uucpname(Myname); chkdebug(orig_uid); /* cd to spool */ ASSERT(subchdir(Spool) != -1, "cannot chdir to ", Spool, 0 ); init_warnedlist(WARNFILE); #ifdef SUBCS fdirs=fopen(DIRFILE,"r"); ASSERT(fdirs != NULL, "uumailclean cannot open", DIRFILE, 0); while (cfgets(cdir, sizeof(cdir), fdirs) != NULL) { nflds = getargs( cdir, flds ); ASSERT(nflds >= 1, "BAD entry in", DIRFILE, 0); /* only interested in command files */ if (flds[0][0] != CMDPRE) continue; failtime = (nflds > 2) ? atoi(flds[2]) : FAILTIME; warntime = (nflds > 3) ? atoi(flds[3]) : WARNTIME; checkfiles(flds[0]); } #else SUBCS failtime = FAILTIME; warntime = WARNTIME; checkfiles("."); #endif SUBCS exit(0); } /* * checkfiles - scan a directory looking for "old" control files. * For each one found, call fail or warn as appropriate. */ checkfiles(dir) char *dir; { DIR *dirp; char file[NAMESIZE]; struct stat stbuf; time_t now; int hours; time(&now); DEBUG(5, "checkfiles(%s)\n", dir); if ((dirp = opendir(dir)) == NULL) { printf("directory unreadable\n"); return; } while (gnamef(dirp, file)) { if (file[0] != CMDPRE) continue; if (stat(subfile(file), &stbuf) == -1) { DEBUG(4, "stat on %s failed\n", file); continue; } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) continue; hours = (int) (now - stbuf.st_mtime) / 3600; if (hours >= failtime) fail(file, hours); else if (hours >= warntime) warn(file, hours); } } /* * fail - send a failure message to the sender and delete the mail. */ fail(cmdfile, hours) char *cmdfile; int hours; { char dfile[NAMESIZE], xfile[NAMESIZE]; char host[NAMESIZE]; char *from, **to; char *sender(), **recipients(); DEBUG(4, "fail called on %s\n", cmdfile); getfnames(cmdfile, dfile, xfile); if ((to = recipients(xfile)) == NULL) return; if ((from = sender(dfile)) == NULL) return; strcpy(host, &cmdfile[2]); host[ strlen(cmdfile)-7 ] = '\0'; sendfailure(from, to, host, hours, dfile); unlink(subfile(cmdfile)); unlink(subfile(dfile)); unlink(subfile(xfile)); return; } /* * warn - send a warning message to the sender and add the control file * to the list of files for which warnings have been sent. */ warn(cmdfile, hours) char *cmdfile; int hours; { char dfile[NAMESIZE], xfile[NAMESIZE]; char host[NAMESIZE]; char *from, **to; char *sender(), **recipients(); if (in_warnedlist(cmdfile)) return; DEBUG(4, "warn called on %s\n", cmdfile); getfnames(cmdfile, dfile, xfile); if ((to = recipients(xfile)) == NULL) return; if ((from = sender(dfile)) == NULL) return; strcpy(host, &cmdfile[2]); host[ strlen(cmdfile)-7 ] = '\0'; sendwarning(from, to, host, hours, failtime, dfile); add_warnedlist(cmdfile); return; } /* * getfnames - read the control file to find the data and execute files * which contain the message and list of recipients. * dfile is set to the datafile, xfile to the execute file. */ getfnames(cmdfile, dfile, xfile) char *cmdfile; char *dfile; char *xfile; { FILE *fp; char dline[100], xline[100]; char *wrkvec[10]; if ((fp = fopen(subfile(cmdfile), "r")) == NULL) return; if (fgets(dline, 100, fp) == NULL || fgets(xline, 100, fp) == NULL) { fclose(fp); return; } if (getargs(dline, wrkvec) <= QF_INDEX) { fclose(fp); return; } strcpy(dfile, wrkvec[ QF_INDEX ]); if (getargs(xline, wrkvec) < QF_INDEX) { fclose(fp); return; } strcpy(xfile, wrkvec[ QF_INDEX ]); fclose(fp); } /* * recipients - returns a list of recipients that the mail was intended * for, or NULL if the execute file is not a mail file. */ char ** recipients(xfile) char *xfile; { static char rbuf[BUFSIZ]; static char *tobuf[1000]; /* see uuxqt */ FILE *fp; char *p, **t; if ((fp = fopen(subfile(xfile), "r")) == NULL) return(NULL); while (fgets(rbuf, BUFSIZ, fp) != NULL) { if (rbuf[0] == X_CMD) { if (strncmp(rbuf, "C rmail ", 8) == SAME) { fclose(fp); /* turn into an array of addresses */ for (p = &rbuf[8], t=tobuf; *p;) { while (*p == ' ' || *p == '\n') *p++ = '\0'; *t = p; while (*p && *p != ' ' && *p != '\n') p++; if (*t != p) t++; } *t = NULL; return(tobuf); } } } fclose(fp); return(NULL); } /* * sender - returns the sender address from the uucp from line, * or NULL if not found. */ char * sender(dfile) char *dfile; { static char sender[BUFSIZ]; char buf[BUFSIZ]; FILE *fp; if ((fp = fopen(subfile(dfile), "r")) == NULL) return(NULL); if (fgets(buf, BUFSIZ, fp) == NULL) return(NULL); if (sscanf(buf, "From %s", sender) == 1) { fclose(fp); return(sender); } fclose(fp); return(NULL); } /* * exists - returns 1 if "file" exists, else 0. */ exists(file) char *file; { return( access(subfile(file),0) == 0 ); } /* * print_message - print the message in "dfile" on the stream "outp". * If the edited flag is set, then only print some * interesting headers and the first few lines of the body. */ print_message(dfile, outp, edited) char *dfile; FILE *outp; int edited; { FILE *dfp; char buf[BUFSIZ]; int iflg, linecount; if ((dfp = fopen(subfile(dfile), "r")) == NULL) return; /* skip unix from line */ fgets(buf, BUFSIZ, dfp); /* print header */ iflg = 0; while (fgets(buf, BUFSIZ, dfp) != NULL && buf[0] != '\n') { if (edited) { if (buf[0] == '\t' || buf[0] == ' ') { if (iflg) fputs(buf, outp); continue; } if (!interested(buf)) { iflg = 0; continue; } iflg = 1; } fputs(buf, outp); } putc('\n', outp); /* print body */ linecount = 0; while (fgets(buf, BUFSIZ, dfp) != NULL) { if (edited && ++linecount > 5) { fprintf(outp, ".....\n"); break; } fputs(buf, outp); } fclose(dfp); } static char *headers[] = { "From:", "Date:", "To:", "Cc:", "Subject:", 0 }; /* * interested - determine whether "hdr" is considered interesting * and thus should be printed in edited mode. */ interested(hdr) char *hdr; { char **hp = headers; while (*hp) { if (strncmp(hdr, *hp, strlen(*hp)) == SAME) return(1); hp++; } return(0); } cleanup(code) int code; { exit(code); } \Rogue\Monster\ else echo "Will not over-write ./Support/uumailclean.c" fi chmod 444 ./Support/uumailclean.c if [ `wc -c < ./Support/uumailclean.c` -ne 7456 ] then echo 'Got' `wc -c < ./Support/uumailclean.c` ', Expected ' 7456 fi if `test ! -s ./Support/warn.c` then echo "Writing ./Support/warn.c" cat > ./Support/warn.c << '\Rogue\Monster\' #include <stdio.h> /* * routines to maintain a list of mailfiles for which warning messages have * been sent out, plus routines to send out warning and failure messages. * * Written by Jim Crammond <jim@cs.hw.ac.uk> 3/86 */ #define SENDMAIL "/usr/lib/sendmail" #define NAMESIZE 15 #define BLKSIZE ((BUFSIZ/NAMESIZE) - 1) struct flist { char fname[BLKSIZE][NAMESIZE]; int nused; struct flist *next; }; struct flist warnlist; FILE *warnfp; /* * Initialise list of files for which warning messages have already been sent. * This involves reading the warnfile into a table, removing files which * no longer exist (i.e. been sent or deleted), and writing this out again. */ init_warnedlist(warnfile) char *warnfile; { struct flist *wp; char warned[NAMESIZE], *p; int i; char *index(); wp = &warnlist; wp->next = NULL; wp->nused = 0; if ((warnfp = fopen(warnfile, "r")) != NULL) { while (fgets(warned, NAMESIZE, warnfp) != NULL) { if ((p = index(warned, '\n')) != NULL) *p = '\0'; if (exists(warned)) { if (wp->nused >= BLKSIZE) { wp->next = (struct flist *) malloc(sizeof(warnlist)); wp = wp->next; wp->next = (struct flist *) NULL; wp->nused = 0; } strcpy(wp->fname[wp->nused], warned); wp->nused++; } } fclose(warnfp); } /* * Rewrite warnedlist removing files that no longer exist. * Could be really paranoid here and create a temporary file * first, rather than overwrite; in case of crashed */ if ((warnfp = fopen(warnfile, "w")) != NULL) { wp = &warnlist; while (wp) { for (i=0; i < wp->nused; i++) fprintf(warnfp, "%s\n", wp->fname[i]); wp = wp->next; } fflush(warnfp); } } /* * Determine whether the given filename is in the warn list. * Returns 1 if found, 0 otherwise. */ in_warnedlist(file) char *file; { struct flist *wp = &warnlist; int i; while (wp) { for (i=0; i < wp->nused; i++) { if (strcmp(file, wp->fname[i]) == 0) return(1); } wp = wp->next; } return(0); } /* * Add a filename to the warn list. */ add_warnedlist(file) char *file; { fprintf(warnfp, "%s\n", file); } /* * Send a Failed Mail message back to the sender, containing the whole * of the failed message. */ sendfailure(sender, rcpts, host, hours, msgfile) char *sender; char **rcpts; char *host; int hours; char *msgfile; { FILE *out, *popen(); char cmd[50]; sprintf(cmd, "%s -t", SENDMAIL); out = popen(cmd, "w"); fprintf(out, "From: MAILER-DAEMON\nSubject:Failed Mail\nTo: %s\n\n", sender); fprintf(out, "After %d days (%d hours), your message to the following people:\n\n", hours/24, hours); /* put out recipents */ while (*rcpts) { fprintf(out, "\t%s (host=%s)\n", *rcpts, host); rcpts++; } fprintf(out, "\ncould not be delivered.\n\n"); fprintf(out, " ----- Unsent message follows ----- \n"); /* print all of the message */ print_message(msgfile, out, 0); pclose(out); return; } /* * Send a Waiting Mail message back to the sender, containing a summary * of the delayed message (to remind him/her what it was about!). */ sendwarning(sender, rcpts, host, hours, failtime, msgfile) char *sender; char **rcpts; char *host; int hours; int failtime; char *msgfile; { FILE *out, *popen(); char cmd[50]; sprintf(cmd, "%s -t", SENDMAIL); out = popen(cmd, "w"); fprintf(out, "From: MAILER-DAEMON\nSubject:Waiting Mail\nTo: %s\n\n", sender); fprintf(out, "After %d days (%d hours), your message to the following people:\n\n", hours/24, hours); /* put out recipents */ while (*rcpts) { fprintf(out, "\t%s (host=%s)\n", *rcpts, host); rcpts++; } fprintf(out, "\nhas not yet been delivered. Attempts to deliver the message will\n"); fprintf(out, "continue for %d more days. No further action is required by you.\n\n", (failtime-hours)/24); fprintf(out, " ----- Queued message begins ----- \n"); /* print a summary of the message */ print_message(msgfile, out, 1); pclose(out); return; } \Rogue\Monster\ else echo "Will not over-write ./Support/warn.c" fi chmod 444 ./Support/warn.c if [ `wc -c < ./Support/warn.c` -ne 3988 ] then echo 'Got' `wc -c < ./Support/warn.c` ', Expected ' 3988 fi if `test ! -d ./Manuals` then mkdir ./Manuals echo "mkdir ./Manuals" fi if `test ! -s ./Manuals/authorise.1` then echo "Writing ./Manuals/authorise.1" cat > ./Manuals/authorise.1 << '\Rogue\Monster\' .TH AUTHORISE 1 "UK-sendmail" .UC 4 .SH NAME authorise - sendmail authorisation program .SH SYNOPSIS .B authorise [-f authorisation_file ] .B channel .B sender .B recipient .B command [args] .SH DESCRIPTION .I Authorise allows outgoing mail to be subjected to authorisation on certain channels, based on sender address and recipient address or relay host. .PP Permission is based on entries contained in an authorisation file ( .I /usr/lib/authorisations by default). Each line has three entries: .I "channel name", .I "sender address", .I "relay host/recipient address". The channel name is a string indicating the name of the outgoing channel. The sender and recipient addresses are pattern strings in which wildcards, lists of alternatives and negative matches (i.e. matches which force authorisation to fail) can be specified. .PP Wildcards are specified by a "*" and will match zero or more characters. Lists are specified by a comma separated list enclosed in brackets, e.g. {a,b,c}. Negative matches are specified by a preceding "^". Lists can contain wildcards and negative matches, thus producing a reasonably powerful pattern matching system. These special characters can be escaped by preceding them with a "\e". Finally, if a "#" is encountered then the rest of the line is treated as comment. .PP .I Authorise will stop searching the authorisation file once a match has been found, so the order of the entries in the file is important when negative matches are used. .SH EXAMPLES Here are some examples of authorisation on .I "sender address" and .I "relay host" (i.e. the host sendmail is about to send the mail to). .in +5 .nf .ta 1i 4i 4.5i # simple per-user sender authorisation csnet jim@cs.hw.ac.uk * # single user csnet {alex,ian,paul}@cs.hw.ac.uk * # a list of users # simple per-host sender authorisation csnet *@cs.hw.ac.uk * # single domain csnet *@*.cs.hw.ac.uk * # and all subdomains # preventing users from using this channel csnet ^{jim,ian}@cs.hw.ac.uk * # jim & ian are banned csnet * * # everyone else is okay .ta 1i 3.5i 4i # more complex example - users on hw.ga and hw.hci # can only send to ukc and ed sites; users at other hw # sites send to anywhere. janet *@uk.ac.hw.{ga,hci} uk.ac.{ukc,ed}* janet ^*@uk.ac.hw.{ga,hci} * janet *@uk.ac.hw* * # only allow local users to use that link to the USA! # anyone can use the other uucp links uucp *@cs.hw.cs.uk ucbvax uucp * {aimmi,spider,zen} .fi .in .PP Note that the syntax of the addresses are in the form appropriate for that mailer and that when authorising on recipient address, it is the .I "transport address" which is actually used (i.e. the one given to the mailer interface in the command line). Thus, an entry using .I "recipient address" on the local uucp channel might be: .in +5 .nf # uucp link to "service" is only for error reports.. luucp * service!bug-reports .ta 0.5i 1.5i 2.5i .fi .in .SH "SENDMAIL INTERFACE" The interface to sendmail is quite simple. For relay host based authorisation two changes need to be made to mailer specification for the channel requiring authorisation in the sendmail configuration. .IP 1. change the pathname of the mailer interface to the path of the authorise program. .IP 2. change the command arguments specification to: .nf A=authorise <channel> $g $h <pathname> <args> .fi where: .RS 0.5i .IP <channel> 12 is the name of the channel (e.g. uucp, janet, csnet); .IP <pathname> 12 is the path of the mailer interface .IP <args> 12 are the arguments to the mailer interface (not including the command name itself). .RE .IP $g is the sender address and $h is the relay host. .PP This is done automatically for you by the UK-2.1 Sendmail Configuration Package when you specify the .I auth option to the channel specification in the configuration description file. .PP For recipient address based authorisation, $u should be given instead of $h as the third argument to authorise (for uucp channels use $h!$u). Further, the 'm' flag must be removed from the mailer flags. .PP This is needed because .I authorise does not allow multiple recipients to be specified. For this reason, authorisation on relay-host is much preferred. .SH EXAMPLE The janet channel, normally specified as :- .nf Mniftp, P=/usr/lib/niftp/ni_send, F=nsmFDMSxu, S=24, R=24, M=100000, A=ni_send -f $g $h $u for relay host authorisation, becomes :- Mniftp, P=/usr/lib/authorise, F=nsmFDMSxu, S=24, R=24, M=100000, A=authorise janet $g $h /usr/lib/niftp/ni_send -f $g $h $u and for recipient address authorisation, becomes :- Mniftp, P=/usr/lib/authorise, F=nsFDMSxu, S=24, R=24, M=100000, A=authorise janet $g $u /usr/lib/niftp/ni_send -f $g $h $u .fi .SH FILES /usr/lib/authorisations - default authorisation file .SH "SEE ALSO" sendmail(8) .SH AUTHOR Jim Crammond .SH BUGS .IP 1. Authorisation cannot be placed on the ethernet or tcp channels as sendmail does the delivery itself, using sockets. \Rogue\Monster\ else echo "Will not over-write ./Manuals/authorise.1" fi chmod 444 ./Manuals/authorise.1 if [ `wc -c < ./Manuals/authorise.1` -ne 4927 ] then echo 'Got' `wc -c < ./Manuals/authorise.1` ', Expected ' 4927 fi if `test ! -s ./Manuals/checkaddr.1` then echo "Writing ./Manuals/checkaddr.1" cat > ./Manuals/checkaddr.1 << '\Rogue\Monster\' .TH CHECKADDR 1 "UK-sendmail" .UC 4 .SH NAME checkaddr - sendmail address verification program .SH SYNOPSIS .B checkaddr [-v] .B addresses... .SH DESCRIPTION The .I checkaddr program is used to check the validity of any address with the local mail system (sendmail). A list of addresses is given on the command line, checkaddr will then announce each address on a separate line and follow the address with its status (normally ``addr OK''). .PP By specifying the -v flag, checkaddr will print additional information about how it .I normalises the address and what routing it then does. .SH "SEE ALSO" sendmail(8) \Rogue\Monster\ else echo "Will not over-write ./Manuals/checkaddr.1" fi chmod 444 ./Manuals/checkaddr.1 if [ `wc -c < ./Manuals/checkaddr.1` -ne 622 ] then echo 'Got' `wc -c < ./Manuals/checkaddr.1` ', Expected ' 622 fi if `test ! -s ./Manuals/distribute.1` then echo "Writing ./Manuals/distribute.1" cat > ./Manuals/distribute.1 << '\Rogue\Monster\' .TH DISTRIBUTE 8 "UK-sendmail" .UC 4 .SH NAME distribute - send mail to a distribution list .SH SYNOPSIS .B /usr/local/lib/distribute .B list-name .B addresses... .SH DESCRIPTION .I Distribute sends a mail message to users on a distribution list. It alters the message header received from a contributor mainly to arrange for any error messages to be returned to the list maintainer. .PP .I Distribute is normally invoked by sendmail from an alias entry in /usr/lib/aliases of the form: .PP .DT list-name: "|/usr/local/lib/distribute list-name users..." .PP With lists containing many names, which maybe subject to frequent alteration, it is best to store the usernames in a file and specify the path name of the file with the syntax .I ":include:file", i.e. .PP .nf list-name: "|/usr/local/lib/distribute list-name :include:file" .fi .PP There should be a second entry in /usr/lib/aliases for the list maintainer. This is the name of the list with "\-request" appended. This should be aliased to the person who is responsible for maintaining the distribution list. e.g. .PP .DT list-name-request: postman-pat .PP .I Distribute should be setuid to one of sendmail's trusted users, so that it will set the sender address to that of the list maintainer. .SH FILES /usr/lib/aliases .SH "SEE ALSO" sendmail(8), aliases(5), newaliases(1) .br "Recommendations for implementors of the JNT Mail Protocol Specifications (MG.B)" by Steve Kille, April 1985 .SH AUTHOR Jim Crammond \Rogue\Monster\ else echo "Will not over-write ./Manuals/distribute.1" fi chmod 444 ./Manuals/distribute.1 if [ `wc -c < ./Manuals/distribute.1` -ne 1471 ] then echo 'Got' `wc -c < ./Manuals/distribute.1` ', Expected ' 1471 fi if `test ! -s ./Manuals/mail-news.8` then echo "Writing ./Manuals/mail-news.8" cat > ./Manuals/mail-news.8 << '\Rogue\Monster\' .TH MAIL-NEWS 8 "UK-sendmail" .UC 4 .SH NAME mail-news - send mail to newsgroups .SH SYNOPSIS .B /usr/lib/news/mail-news .B <arguments for inews> .SH DESCRIPTION .I Mail-news sends a mail message to one or more newsgroups. It alters the message header to ensure that it satisfies certain constraints imposed by inews version B.2.11, mainly to insure that there is a subject and that included text does not cause rejections. .PP .I Mail-news is normally invoked by sendmail from a mailer channel; it may also be invoked by an alias entry (in /usr/lib/aliases) of the form: .PP .DT list-name: "|/usr/lib/news/mail-news [inews argument list]" .SH "SEE ALSO" sendmail(8), inews(8) recnews(1) .SH AUTHOR Jem Taylor \Rogue\Monster\ else echo "Will not over-write ./Manuals/mail-news.8" fi chmod 444 ./Manuals/mail-news.8 if [ `wc -c < ./Manuals/mail-news.8` -ne 711 ] then echo 'Got' `wc -c < ./Manuals/mail-news.8` ', Expected ' 711 fi if `test ! -s ./Manuals/muucp.8c` then echo "Writing ./Manuals/muucp.8c" cat > ./Manuals/muucp.8c << '\Rogue\Monster\' .TH MUUCP 8 "UK-sendmail" .SH NAME muucp \- send mail over uucp, using the UUCP transmission format .SH SYNOPSIS .B muucp [uux options] .B -f<from_address> .B -H<uucpname> host user1 user2 ... .SH DESCRIPTION .I Muucp simply prepends a unix From line to the message received from .IR sendmail (8) which is then passed on to .IR uux (1C). .PP The from address passed by sendmail is expected in "percent form" and is converted to uucp path address ("bang format"). Muucp also removes any duplicate domains which are detected in the resulting path. .SH "SEE ALSO" sendmail(8) uux(1C) \Rogue\Monster\ else echo "Will not over-write ./Manuals/muucp.8c" fi chmod 444 ./Manuals/muucp.8c if [ `wc -c < ./Manuals/muucp.8c` -ne 581 ] then echo 'Got' `wc -c < ./Manuals/muucp.8c` ', Expected ' 581 fi if `test ! -s ./Manuals/uumailclean.8c` then echo "Writing ./Manuals/uumailclean.8c" cat > ./Manuals/uumailclean.8c << '\Rogue\Monster\' .TH UUMAILCLEAN 8C "UK-Sendmail" .UC 4 .SH NAME uumailclean \- uucp spool directory mail clean-up .SH SYNOPSIS .B /usr/lib/uucp/uumailclean .SH DESCRIPTION .I Uumailclean scans the uucp spool directory for mail files and checks to see how long they have been queued. If a mail message is found to have been queued for longer than .I failtime hours, then it is returned to the sender and deleted from the queue. If a mail message is found to have been queued for longer than .I warntime hours (but less than failtime), then a warning message is sent to the sender to inform them that the mail has yet to be delivered. .PP By default, failtime is set to 168 hours (1 week) and warntime to 72 hours (3 days). With the subdirectories option of UKUUCP, .I uumailclean will override these defaults if times are specified in the .I L.dirs file as 3rd and 4th arguments to the subdirectory entries. For example, .nf C.hwcs 336 96 48 .fi specifies a failtime of 96 hours and a warntime of 48 hours. .PP .I uumailclean maintains a list of mail files for which warning messages have already been sent out, so that the sender will only receive one warning message. This is normally the file .I warnlist.mail in the uucp spool directory. .PP .I Uumailclean will typically be started by .IR cron (8). .SH FILES /usr/spool/uucp uucp spool directory .br /usr/spool/uucp/warnlist.mail list of warned mail files .br /usr/lib/uucp/L.dirs list of subdirectories of spool .br /usr/spool/uucp/warnlist.mail list of warned mail files .SH "SEE ALSO" sendmail(8), uuclean(8C) .SH AUTHOR Jim Crammond \Rogue\Monster\ else echo "Will not over-write ./Manuals/uumailclean.8c" fi chmod 444 ./Manuals/uumailclean.8c if [ `wc -c < ./Manuals/uumailclean.8c` -ne 1582 ] then echo 'Got' `wc -c < ./Manuals/uumailclean.8c` ', Expected ' 1582 fi echo "Finished archive 3 of 4" exit