#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  resend.README resend majordomo.pl sample.cf sample.aliases
#   Makefile wrapper.c
# Wrapped by brent@mycroft on Fri Mar 19 17:02:17 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'resend.README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'resend.README'\"
else
echo shar: Extracting \"'resend.README'\" \(1361 characters\)
sed "s/^X//" >'resend.README' <<'END_OF_FILE'
XThe .cf file is a config file for my listserv-like package called
XMajordomo.  The only one of those variables that "resend" actually
Xuses is "homedir", which tells it where to look for the "majordomo.pl"
Xlibrary.
X
XHere's the rundown of the arguments to "resend":
X
X        -C <config-file>        specify alternate config file
X        -l <list-name>          REQUIRED: specify list name
X        -h <host-name>          REQUIRED: specify host name
X        -f <from-addr>          specify "sender" (default <list-name>-request)
X        -m <sendmail-flags>     specify special sendmail flags
X        -M <max-msg-length>     specify max message length to forward
X        -p <precedence>         add "Precedence: <precedence>" header
X        -R                      delete "Received:" lines
X        -s                      enable "administrivia" checks
X        -d                      debug; say it, but don't do it
X
XAny message that "resend" doesn't like is sent to the list owner (the
X"-f" address, or "<list-name>-request" if -f isn't used) along with a
Xcomment indicating what "resend" didn't like about it.  To go ahead
Xand send the message, just feed it to resend without the flag that
Xcaused it to reject it (in other words, if it rejected it because it
Xwas too long, omit the "-M <>" flag; if it rejected it because it was
Xadministrivia, omit the "-s" flag).
END_OF_FILE
if test 1361 -ne `wc -c <'resend.README'`; then
    echo shar: \"'resend.README'\" unpacked with wrong size!
fi
# end of 'resend.README'
fi
if test -f 'resend' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'resend'\"
else
echo shar: Extracting \"'resend'\" \(7041 characters\)
sed "s/^X//" >'resend' <<'END_OF_FILE'
X#!/usr/local/bin/perl -U
X
X# Copyright 1992, D. Brent Chapman.  All Rights Reserved.  For use by
X# permission only.
X#
X# $Source: /mycroft/brent/majordomo/RCS/resend,v $
X# $Revision: 1.10 $
X# $Date: 1993/02/23 16:05:04 $
X# $Author: brent $
X# $State: Exp $
X#
X# $Locker:  $
X#
X# $Log: resend,v $
X# Revision 1.10  1993/02/23  16:05:04  brent
X# Changed administriva heuristics slightly.  -Brent
X#
X# Revision 1.9  1993/02/01  18:35:55  brent
X# Added command line option for config file.  -Brent
X#
X# Revision 1.8  1993/02/01  18:08:07  brent
X# Switched from "mailstuff.pl" to "majordomo.pl".  -Brent
X#
X# Revision 1.7  1993/01/18  21:13:49  brent
X# Added "sub" and "unsub" to keyword search.  -Brent
X#
X# Revision 1.6  1992/12/25  01:24:14  brent
X# Got rid of "Errors-To:" headers in outgoing mail.  -Brent
X#
X# Revision 1.5  1992/11/24  00:43:58  brent
X# Improved administrivia tests.  -Brent
X#
X# Revision 1.4  1992/11/09  16:48:58  brent
X# Integrated administrivia filter; submitted by Scott Hazen Mueller
X# (scott@dsg.tandem.com).
X#
X# Revision 1.3  1992/10/28  17:14:22  brent
X# Modified to strip "Precedence:" from old header if "-p" arg specified.
X#
X# Revision 1.2  1992/10/26  04:36:53  brent
X# Wasn't deleting /tmp files when messages was bounced.  -Brent
X#
X# Revision 1.1  1992/10/26  04:19:15  brent
X# Initial revision
X#
X
X# set our path explicitly
X$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
X
X# What shall we use for temporary files?
X$tmp = "/tmp/majordomo.$$";
X
X# Read and execute the .cf file
X$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
Xif ($ARGV[0] eq "-C") {
X    $cf = $ARGV[1];
X    shift(@ARGV); 
X    shift(@ARGV); 
X}
Xif (! -r $cf) {
X    die("$cf not readable; stopped");
X}
Xeval(`cat $cf`);
X
Xchdir($homedir) || die("Can't chdir(\"$homedir\"): $!");
Xunshift(@INC, $homedir);
Xrequire "majordomo.pl";
Xrequire "getopts.pl";
X
X&Getopts("l:h:f:m:M:p:Rsd") || die("resend: Getopts(): $!");
X
Xif (! defined($opt_l) || ! defined($opt_h)) {
X    die("resend: must specify both '-l list' and '-h host' arguments");
X}
X
Xif (defined($opt_f)) {
X    $sendmail_sender = $opt_f;
X} else {
X    $sendmail_sender = "$opt_l-request";
X}
X
X$sender = "$sendmail_sender@$opt_h";
X
Xopen(OUT, ">/tmp/resend.$$.out") ||
X    die("resend: Can't open /tmp/resend.$$.out: $!");
X
Xopen(IN, ">/tmp/resend.$$.in") ||
X    die("resend: Can't open /tmp/resend.$$.in: $!");
X
X$in_hdr = 1;
X$kept_last = 0;
X
Xwhile (<STDIN>) {
X    print IN $_;
X}
X
Xclose(IN);
X
Xopen(IN, "/tmp/resend.$$.in") || 
X    die("resend: Can't open /tmp/resend.$$.tmp: $!");
X
Xwhile (<IN>) {
X    if ($in_hdr) {
X	if (/^\s*$/) {
X	    # end of header; add new header fields
X	    print OUT "Sender: $sender\n";
X	    if (defined($opt_p)) {
X		print OUT "Precedence: $opt_p\n";
X	    }
X	    $in_hdr = 0;
X	    print OUT $_;
X	} elsif (/^from /i		# skip all these headers
X	    || /^sender:/i
X	    || /^return-receipt-to:/i
X	    || /^errors-to:/i
X	    || /^return-path:/i
X	    || (/^precedence:/i && defined($opt_p))	# skip only if "-p" set
X	    || (/^received:/i && defined($opt_R))	# skip only if "-R" set
X	    || (/^\s/ && ! $kept_last)			# skip if skipped last
X	) {
X	    # reset $kept_last in case next line is continuation
X	    $kept_last = 0;
X	} else {
X            # check for administrivia requests 
X            if (defined($opt_s)
X	        && (/^subject:\s*subscribe\b/i ||
X		    /^subject:\s*unsubscribe\b/i)) {
X                &bounce("Admin request");
X            } 
X	    &check_hdr_line($_);	# check for length & balance
X	    $kept_last = 1;
X	    print OUT $_;
X	}
X    } else {
X	# this isn't a header line, so print it
X	# first, though, make sure it doesn't make the message too long
X	if (defined($opt_M) && ($body_len += length($_)) > $opt_M) {
X	    &bounce("Message too long (>$opt_M)");
X	}
X        # add admin-request recognition heuristics here... (body)
X        if (defined($opt_s) && ($body_line++ < 5) && (
X	    /\badd me\b/i
X            || /\bdelete me\b/i
X            || /\bsubscribe\b/i || /^sub\b/i
X            || /\bunsubscribe\b/i || /^unsub\b/i
X            )) {
X              &bounce("Admin request");
X        }
X	print OUT $_;
X    }
X}
X
Xclose(OUT);
X
X$sendmail_cmd = "/usr/lib/sendmail $opt_m -f$sendmail_sender " .
X    join(" ", @ARGV);
X
Xif (defined($opt_d)) {
X    $| = 1;
X    print "Command: $sendmail_cmd\n";
X    $status = (system("cat /tmp/resend.$$.out") >> 8);
X    unlink(</tmp/resend.$$.*>);
X    exit($status);
X} else {
X    system("$sendmail_cmd </tmp/resend.$$.out");
X    unlink(</tmp/resend.$$.*>);
X    exit(0);
X}
X
Xsub check_balance {
X    # set a temporary variable
X    local($t) = shift;
X    # strip out all nested parentheses
X    1 while $t =~ s/\([^\(\)]*\)//g;
X    # strip out all nested angle brackets
X    1 while $t =~ s/\<[^\<\>]*\>//g;
X    # if any parentheses or angle brackets remain, were imbalanced
X    if ($t =~ /[\(\)\<\>]/) {
X	&bounce("Imbalanced parentheses or angle brackets");
X	return(undef);
X    }
X    return(1);
X}
X
Xsub check_hdr_line {
X
X    local($_) = shift;
X
X    if (! /^\s/) {	# is this a continuation line?
X	# Not a continuation line.
X	# If $balanced_fld is defined, it means the last field was one
X	# that needed to have balanced "()" and "<>" (i.e., "To:", "From:",
X	# and "Cc:", so check it.  We do it here in case the last field was
X	# multi-line.
X
X	if (defined($balanced_fld)) {
X	    &check_balance($balanced_fld);
X	}
X
X	# we undefine $balanced_fld and reset $field_len; these may be set below
X
X	undef($balanced_fld);
X	$field_len = 0;
X    }
X
X    # is this a field that must be checked for balanced "()" and "<>"?
X    if (defined($balanced_fld) || /^from:/i || /^cc:/i || /^to:/i) {
X	# yes it is, but we can't check it yet because there might be
X	# continuation lines.  Buffer it to be checked at the beginning
X	# of the next non-continuation line.
X
X	# is this line too long?
X	if (length($_) > 128) {
X	    &bounce("Header line too long (>128)");
X	    return(undef);
X	}
X
X	# is this field too long?
X	if (($field_len += length($_)) > 1024) {
X	    &bounce("Header field too long (>1024)");
X	    return(undef);
X	}
X
X	$balanced_fld .= $_;
X	chop($balanced_fld);
X    }
X
X    # if we get here, everything was OK.
X    return(1);
X}
X
Xsub bounce {
X    local($reason) = shift;
X    local($_);
X
X    &sendmail(BOUNCE, $sender, "BOUNCE $opt_l: $reason");
X    
X    seek(IN, 0, 0);
X    while (<IN>) {
X	print BOUNCE $_;
X    }
X    close(BOUNCE);
X    unlink(</tmp/resend.$$.*>);
X    exit(0);
X}
X
Xsub sendmail {
X    local(*MAIL) = shift;
X    local($to) = shift;
X    local($subject) = shift;
X
X    # clean up the addresses, for use on the sendmail command line
X    local(@to) = &ParseAddrs($to);
X    for (@to) {
X        $_ = join(", ", &ParseAddrs($_));
X    }
X    $to = join(", ", @to);
X
X    # open the process
X    if (defined($opt_d)) {
X	# debugging, so just say it, don't do it
X	open(MAIL, ">-");
X	print MAIL ">>> /usr/lib/sendmail -f$sendmail_sender $to\n";
X    } else {
X	open(MAIL, "|/usr/lib/sendmail -f$sendmail_sender $to") ||
X	    &abort("Can't connect to sendmail: $!");
X    }
X
X    # generate the header
X    print MAIL <<"EOM";
XTo: $to
XFrom: $sender
XSubject: $subject
X
XEOM
X
X    return;
X}
END_OF_FILE
if test 7041 -ne `wc -c <'resend'`; then
    echo shar: \"'resend'\" unpacked with wrong size!
fi
chmod +x 'resend'
# end of 'resend'
fi
if test -f 'majordomo.pl' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'majordomo.pl'\"
else
echo shar: Extracting \"'majordomo.pl'\" \(10401 characters\)
sed "s/^X//" >'majordomo.pl' <<'END_OF_FILE'
X# General subroutines for Majordomo
X
X# $Source: /mycroft/brent/majordomo/RCS/majordomo.pl,v $
X# $Revision: 1.16 $
X# $Date: 1993/01/03 04:58:53 $
X# $Author: brent $
X# $State: Exp $
X# 
X# $Header: /mycroft/brent/majordomo/RCS/majordomo.pl,v 1.16 1993/01/03 04:58:53 brent Exp $
X# 
X# $Locker:  $
X# 
X# $Log: majordomo.pl,v $
X# Revision 1.16  1993/01/03  04:58:53  brent
X# Created "is_list_member" function.  -Brent
X#
X# Revision 1.15  1993/01/03  03:00:43  brent
X# Fixed bug in chop_nl.
X# Made addr_match optionally do substring matches instead of addr compares.
X#
X# Revision 1.14  1992/12/30  19:01:18  brent
X# Reworked "sendmail" interface between majordomo and majordomo.pl.
X# Parameterized choice of mailer for use by &sendmail.
X#
X# Revision 1.13  1992/12/27  23:29:57  brent
X# Modified "valid_list" to accept "<list>", "list@site", and "<list@site>"
X# as valid.  -Brent
X#
X# Revision 1.12  1992/12/25  02:10:23  brent
X# Further interface cleanup between "majordomo" and "majordomo.pl".  -Brent
X#
X# Revision 1.11  1992/12/25  01:52:53  brent
X# Fixed bug in chop_nl.  -Brent
X#
X# Revision 1.10  1992/12/25  01:29:38  brent
X# Added "chop_nl" subroutine to chop only trailing newlines.  -Brent
X#
X# Revision 1.9  1992/12/25  01:24:14  brent
X# Got rid of "Errors-To:" headers in outgoing mail.  -Brent
X#
X# Revision 1.8  1992/12/25  01:21:38  brent
X# Cleaned up "log" interface between majordomo and majordomo.pl.  -Brent
X#
X# Revision 1.7  1992/12/25  00:48:53  brent
X# Moved "lopen" and "lclose" functions from "majordomo.pl" to "shlock.pl".
X#
X# Revision 1.6  1992/12/25  00:32:47  brent
X# Moved support functions to majordomo.pl
X#
X# 
X
Xpackage Majordomo;
X
X#  Mail header hacking routines for Majordomo
X#
X#  Derived from:
X#  Routines to parse out an RFC 822 mailheader
X#     E. H. Spafford,  last mod: 11/91
X#  
X#  ParseMailHeader breaks out the header into an % array
X#    indexed by a lower-cased keyword, e.g.
X#       &ParseMailHeader(STDIN, *Array);
X#	use $Array{'subject'}
X#
X#    Note that some duplicate lines (like "Received:") will get joined
X#     into a single entry in %Array; use @Array if you want them separate
X#    $Array will contain the unprocessed header, with embedded
X#     newlines
X#    @Array will contain the header, one line per entry
X#
X#  RetMailAddr tries to pull out the "preferred" return address
X#    based on the presence or absence of various return-reply fields
X
X
X#  Call as &ParseMailHeader(FileHandle, *array)
X
Xsub main'ParseMailHeader  ## Public
X{
X    local($save1, $save2) = ($*, $/);
X    local($FH, *array) =  @_;
X    local ($keyw, $val);
X
X    %array = ();
X
X    # force unqualified filehandles into callers' package
X    local($package) = caller;
X    $FH =~ s/^[^']+$/$package'$&/;
X
X    ($*, $/) = (1, '');
X    $array = $_ = <$FH>;
X    s/\n\s+/ /g;
X       
X    @array = split('\n');
X    foreach $_ (@array)
X    {
X	($keyw, $val) = m/^([^:]+):\s*(.*\S)\s*$/g;
X	$keyw =~ y/A-Z/a-z/;
X	if (defined($array{$keyw})) {
X	    $array{$keyw} .= ", $val";
X	} else {
X	    $array{$keyw} = $val;
X	}
X    }
X    ($*, $/) = ($save1, $save2); 
X}
X
X
X#  Call as $addr = &RetMailAddr(*array)
X#    This assumes that the header is in RFC 822 format
X
Xsub main'RetMailAddr  ## Public
X{
X    local(*array) = @_;
X
X    local($ReplyTo) = defined($array{'reply-to'}) ?
X		$array{'reply-to'} : $array{'from'};
X
X    $ReplyTo = $array{'apparently-from'} unless $ReplyTo;
X
X    join(", ", &main'ParseAddrs($ReplyTo)) if $ReplyTo;
X    $ReplyTo;
X}
X
X# @addrs = &ParseAddrs($addr_list)
Xsub main'ParseAddrs {
X    local($_) = shift;
X    1 while s/\([^\(\)]*\)//g; 		# strip comments
X    1 while s/"[^"]*"//g;		# strip comments
X    split(/,/);				# split into parts
X    foreach (@_) {
X	1 while s/.*<(.*)>.*/\1/;
X	s/^\s+//;
X	s/\s+$//;
X    }
X
X    @_;
X}
X
X# Check to see if a list is valid.  If it is, return the validated list
X# name; if it's not, return ""
Xsub main'valid_list {
X    local($listdir) = shift;
X    # start with a space-separated list of the rest of the arguments
X    local($taint_list) = join(" ", @_);
X    # strip harmless matched leading and trailing angle brackets off the list
X    1 while $taint_list =~ s/^<(.*)>$/\1/;
X    # strip harmless trailing "@.*" off the list
X    $taint_list =~ s/@.*$//;
X    # anything else funny with $taint_list probably isn't harmless; let's check
X    # start with $clean_list the same as $taint_list
X    local($clean_list) = $taint_list;
X    # clean up $clean_list
X    $clean_list =~ s/[^-_0-9a-zA-Z]*//g;
X    # if $clean_list no longer equals $taint_list, something's wrong
X    if ($clean_list ne $taint_list) {
X	return ""; 
X    } 
X    # convert to all-lower-case
X    $clean_list =~ tr/A-Z/a-z/;
X    # check to see that $listdir/$clean_list exists
X    if (! -e "$listdir/$clean_list") {
X	return "";
X    }
X    return $clean_list;
X}
X
X# compare two email address to see if they "match" by converting  to all
X# lower case, then stripping off comments and comparing what's left.  If
X# a optional third argument is specified and it's not undefined, then
X# partial matches (where the second argument is a substring of the first
X# argument) should return true as well as exact matches.
Xsub main'addr_match {
X    local($a1) = &main'chop_nl(shift);
X    local($a2) = &main'chop_nl(shift);
X    local($partial) = shift;	# may be "undef"
X
X    if ($partial) {
X	$a1 =~ tr/A-Z/a-z/;
X	$a2 =~ tr/A-Z/a-z/;
X	if (index($a1, $a2) >= $[) {
X	    return(1);
X	} else {
X	    return(undef);
X	}
X    }
X	
X    local(@a1, @a2);
X
X    $a1 =~ tr/A-Z/a-z/;
X    $a2 =~ tr/A-Z/a-z/;
X
X    @a1 = &main'ParseAddrs($a1);
X    @a2 = &main'ParseAddrs($a2);
X    if (($#a1 != 0) || ($#a2 != 0)) {
X	# Can't match, because at least one of them has either zero or
X	# multiple addresses
X	return(undef);
X    }
X    return($a1[0] eq $a2[0]);
X}
X
X# These are package globals referenced by &setabortaddr and &abort
X
X$abort_addr = "Postmaster";
X
Xsub main'set_abort_addr {
X    $abort_addr = shift unless ($#_ < $[);
X}
X
X# Abort the process, for the reason stated as the argument
Xsub main'abort {
X    # log the reason for the abort, if possible
X    &main'log("ABORT", join(" ", @_), "\n");
X    # print the reason for the abort to stderr; maybe someone will see it
X    print STDERR join(" ", @_), "\n";
X    # send a message to the Majordomo owner, if possible
X    if (defined($abort_addr)) {
X	&main'sendmail(ABORT, $abort_addr, "MAJORDOMO ABORT");
X	print ABORT <<"EOM";
X
XMAJORDOMO ABORT
X
X@_
X
XEOM
X	close(ABORT);
X    }
X    die("ABORT ", @_);
X}
X
X# These are package globals referenced by &setlogfile and &log
X$log_file = "/tmp/log.$$";
X$log_host = "UNKNOWN";
X$log_program = "UNKNOWN";
X$log_session = "UNKNOWN";
X
X# set the log file
Xsub main'set_log {
X    $log_file = shift unless ($#_ < $[);
X    $log_host = shift unless ($#_ < $[);
X    $log_program = shift unless ($#_ < $[);
X    $log_session = shift unless ($#_ < $[);
X}
X
X# Log a message to the log
Xsub main'log {
X    local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
X    if (&main'lopen(LOG, ">>", $log_file)) {
X	# if the log is open, write to the log
X	printf LOG "%s %02d %02d:%02d:%02d %s %s[%d] {%s} ",
X	    $ctime'MoY[$mon], $mday, $hour, $min, $sec,
X	    $log_host, $log_program, $$, $log_session;
X	print LOG join(" ", @_), "\n";
X	&main'lclose(LOG);
X    } else {
X	# otherwise, write to stderr
X	printf STDERR "%s[%d] {%s} ", $log_program, $$, $log_session;
X	print STDERR join(" ", @_), "\n";
X    }
X}
X
X# Globals referenced by &set_mail* and &sendmail
X$mail_prog = "/usr/lib/sendmail -f\$sender \$to";
X$mail_from = "Majordomo";
X$mail_sender = "Majordomo-Owner";
X
X# set the mailer
Xsub main'set_mailer {
X     $mail_prog = shift;
X}
X
X# set the default from address
Xsub main'set_mail_from {
X    $mail_from = shift;
X}
X
X# set the default sender address
Xsub main'set_mail_sender {
X    $mail_sender = shift;
X}
X
X# Open a sendmail process
Xsub main'sendmail {
X    local($MAIL) = shift;
X    local($to) = shift;
X    local($subject) = shift;
X    local($from) = $mail_from;
X    local($sender) = $mail_sender;
X    if ($#_ >= $[) { $from = shift; }
X    if ($#_ >= $[) { $sender = shift; }
X
X    # force unqualified filehandles into callers' package
X    local($package) = caller;
X    $MAIL =~ s/^[^']+$/$package'$&/;
X
X    # clean up the addresses, for use on the sendmail command line
X    local(@to) = &main'ParseAddrs($to);
X    for (@to) {
X	$_ = join(", ", &main'ParseAddrs($_));
X    }
X    $to = join(", ", @to);
X
X    # open the process
X    local($mailer);
X    eval "\$mailer = \"$mail_prog\"";
X    open($MAIL, "|$mailer") ||
X	&main'abort("Can't invoke \"$mailer\": $!");
X
X    # generate the header
X    print $MAIL 
X"To: $to
XFrom: $from
XSubject: $subject
XReply-To: $from
X
X";
X    
X    return;
X}
X
X# check the password for a list
Xsub main'valid_passwd {
X    local($listdir) = shift;
X    local($list) = shift;
X    local($passwd) = shift;
X    # is it a valid list?
X    local($clean_list) = &main'valid_list($listdir, $list);
X    if ($clean_list ne "") {
X	# it's a valid list; read the password
X	if (&main'lopen(PASSWD, "", "$listdir/$clean_list.passwd")) {
X	    local($file_passwd) = <PASSWD>;
X	    &main'lclose(PASSWD);
X	    $file_passwd = &main'chop_nl($file_passwd);
X	    # got the password; now compare it to what the user sent
X	    if ($passwd eq $file_passwd) {
X		return 1;
X	    } else {
X		return 0;
X	    }
X	} else {
X	    return 0;
X	}
X    } else {
X	return 0;
X    }
X}
X
X# Check to see that this is a valid address. 
X# A valid address is a single address with 
X# no "/" or "|" in the address part.
X
Xsub main'valid_addr {
X    local($addr) = shift;
X    local(@addrs);
X
X    # Parse the address out into parts
X    @addrs = &main'ParseAddrs($addr);
X
X    # if there's not exactly 1 part, it's no good
X    if ($#addrs != 0) {
X	return undef;
X    }
X
X    local($_) = @addrs;
X
X    # if there's a "|" or a "/" in it, it's hostile
X    if (tr/|\//|\// != 0) {
X	&main'abort("HOSTILE ADDRESS $addr");
X	return undef;
X    }
X
X    return $_;
X}
X
X# Chop any trailing newlines off of a string, and return the string
Xsub main'chop_nl {
X    if ($#_ >= $[) {
X	local($x) = shift;
X	$x =~ s/\n+$//;
X	return($x);
X    } else {
X	return(undef);
X    }
X}
X
Xsub main'is_list_member {
X    local($subscriber) = shift;
X    local($listdir) = shift;
X    local($clean_list) = shift;
X    local($matches);
X
X    open(LIST, "$listdir/$clean_list")
X	|| &abort("Can't read $listdir/$clean_list: $!");
X    while (<LIST>) {
X	if (&main'addr_match($_, $subscriber)) {
X	    $matches++;
X	}
X    }
X    close(LIST);
X    return($matches);
X}
X
X1;
END_OF_FILE
if test 10401 -ne `wc -c <'majordomo.pl'`; then
    echo shar: \"'majordomo.pl'\" unpacked with wrong size!
fi
# end of 'majordomo.pl'
fi
if test -f 'sample.cf' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sample.cf'\"
else
echo shar: Extracting \"'sample.cf'\" \(208 characters\)
sed "s/^X//" >'sample.cf' <<'END_OF_FILE'
X$whereami = "GreatCircle.COM";
X$whoami = "Majordomo@$whereami";
X$whoami_owner = "Majordomo-Owner@$whereami";
X$homedir = "/usr/local/mail/majordomo";
X$listdir = "/usr/local/mail/lists";
X$log = "$homedir/Log";
END_OF_FILE
if test 208 -ne `wc -c <'sample.cf'`; then
    echo shar: \"'sample.cf'\" unpacked with wrong size!
fi
# end of 'sample.cf'
fi
if test -f 'sample.aliases' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sample.aliases'\"
else
echo shar: Extracting \"'sample.aliases'\" \(1685 characters\)
sed "s/^X//" >'sample.aliases' <<'END_OF_FILE'
Xlist-managers: "|/usr/local/mail/majordomo/wrapper resend -p bulk -M 10000
X	-l List-Managers -f List-Managers-Owner -h GreatCircle.COM -s
X	list-managers-outgoing"
X
Xowner-list-managers: list-managers-owner
X
Xlist-managers-outgoing: :include:/usr/local/mail/lists/list-managers,
X	list-managers-archive, list-managers-digestify
X
Xowner-list-managers-outgoing: list-managers-owner
X
Xlist-managers-archive: /usr/local/mail/archive/list-managers
X
Xowner-list-managers-archive: list-managers-owner
X
Xlist-managers-request:
X	"|/usr/local/mail/majordomo/wrapper request-recording list-managers"
X
Xowner-list-managers-request: list-managers-owner
X
Xlist-managers-approval: brent
X
Xlist-managers-owner: brent
X
Xowner-list-managers-owner: brent
X
Xlist-managers-digest: list-managers
X
Xowner-list-managers-digest: list-managers-digest-owner
X
Xlist-managers-digestify: "|/usr/local/mail/majordomo/wrapper digest
X	-r -c /usr/local/mail/digest/list-managers-digest.cf"
X
Xowner-list-managers-digestify: list-managers-digest-owner
X
Xlist-managers-digest-send: "|/usr/local/mail/majordomo/wrapper resend -p bulk
X	-l List-Managers-Digest -f List-Managers-Digest-Owner
X	-h GreatCircle.COM -s list-managers-digest-outgoing"
X
Xowner-list-managers-digest-send: list-managers-digest-owner
X
Xlist-managers-digest-outgoing:
X	:include:/usr/local/mail/lists/list-managers-digest
X
Xowner-list-managers-digest-outgoing: list-managers-digest-owner
X
Xlist-managers-digest-request: "|/usr/local/mail/majordomo/wrapper
X	request-recording list-managers-digest"
X
Xowner-list-managers-digest-request: list-managers-digest-owner
X
Xlist-managers-digest-approval: brent
X
Xlist-managers-digest-owner: brent
X
Xowner-list-managers-digest-owner: brent
END_OF_FILE
if test 1685 -ne `wc -c <'sample.aliases'`; then
    echo shar: \"'sample.aliases'\" unpacked with wrong size!
fi
# end of 'sample.aliases'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(2094 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# $Source: /mycroft/brent/majordomo/RCS/Makefile,v $
X# $Revision: 1.5 $
X# $Date: 1993/02/01 18:02:10 $
X# $Author: brent $
X# $State: Exp $
X# 
X# $Header: /mycroft/brent/majordomo/RCS/Makefile,v 1.5 1993/02/01 18:02:10 brent Exp $
X# 
X# $Locker:  $
X# 
X# $Log: Makefile,v $
X# Revision 1.5  1993/02/01  18:02:10  brent
X# Moved package-building (shar, tar) stuff to separate makefile.  -Brent
X#
X# Revision 1.4  1993/02/01  18:00:21  brent
X# Changed default target.  -Brent
X#
X# Revision 1.3  1992/12/24  22:37:30  brent
X# Added reference to "Files" file for building tars; added shars.  -Brent
X#
X# Revision 1.2  1992/12/01  03:48:11  brent
X# Added "SYSV_UID" and "SYSV_GID" functionality to work around SysV problem
X# with "setuid(geteuid())" and "setgid(getegid())".  -Brent
X#
X# Revision 1.1  1992/12/01  03:37:12  brent
X# Initial revision
X#
X# 
X
X# This is where "wrapper" looks for the programs it's supposed to run.
XW_BIN=/mycroft/brent/majordomo
X
X# for BSD-based systems, this is the UID/GID "wrapper" is chown'd to and runs as
XW_USER=daemon
XW_GROUP=listserv
XW_CHOWN=${W_USER}.${W_GROUP}
XW_CHMOD=6755
X
X# if you're running SYSV, you need to define these to be the numeric
X# UID/GID that wrapper should run as, and install it setuid to root.
X# Don't forget to add the W_UID/W_GID line for "WRAPPER_FLAGS" below
X# W_UID = 1
X# W_GID = 15
X# W_CHOWN=root
X# W_CHMOD=4755
X
X# This is the environment that (along with LOGNAME and USER inherited from the
X# parent process, and without the leading "W_" in the variable names) gets
X# passed to processes run by "wrapper"
X
XW_PATH=/bin:/usr/bin:/usr/ucb
XW_HOME=/mycroft/brent/majordomo
XW_SHELL=/bin/csh
X
X# for BSD
XWRAPPER_FLAGS = -DBIN=\"${W_BIN}\" -DPATH=\"PATH=${W_PATH}\" \
X	-DHOME=\"HOME=${W_HOME}\" -DSHELL=\"SHELL=${W_SHELL}\"
X
X# for SysV
X# WRAPPER_FLAGS = -DBIN=\"${W_BIN}\" -DPATH=\"PATH=${W_PATH}\" \
X# 	-DHOME=\"HOME=${W_HOME}\" -DSHELL=\"SHELL=${W_SHELL}\" \
X# 	-DSYSV_UID=${W_UID} -DSYSV_GID=${W_GID}
X
Xdefault: wrapper
X
Xinstall: wrapper
X
Xwrapper: wrapper.c
X	cc ${WRAPPER_FLAGS} -o wrapper wrapper.c
X	chown ${W_CHOWN} wrapper
X	chmod ${W_CHMOD} wrapper
X
END_OF_FILE
if test 2094 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'wrapper.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'wrapper.c'\"
else
echo shar: Extracting \"'wrapper.c'\" \(2685 characters\)
sed "s/^X//" >'wrapper.c' <<'END_OF_FILE'
X/*
X *  $Source: /mycroft/brent/majordomo/RCS/wrapper.c,v $
X *  $Revision: 1.7 $
X *  $Date: 1992/12/01 03:48:11 $
X *  $Author: brent $
X *  $State: Exp $
X *
X *  $Locker:  $
X *  
X *  $Log: wrapper.c,v $
X *  Revision 1.7  1992/12/01  03:48:11  brent
X *  Added "SYSV_UID" and "SYSV_GID" functionality to work around SysV problem
X *  with "setuid(geteuid())" and "setgid(getegid())".  -Brent
X *
X *  Revision 1.6  1992/10/02  20:54:59  brent
X *  Added creation of minimal environment, rather than inheriting parent's
X *  environment, for security.  -Brent
X *
X *  Revision 1.5  1992/10/02  18:18:46  brent
X *  Revised to run programs only from "BIN" directory, per suggestion and
X *  sample code from Jeff Beadles <jeff@onion.rain.com>.  -Brent
X *
X *  Revision 1.4  1992/10/02  18:07:55  brent
X *  Added RCS headers.  -Brent
X *
X *
X */
X
X#ifndef lint
Xstatic char rcs_header[] = "$Header: /mycroft/brent/majordomo/RCS/wrapper.c,v 1.7 1992/12/01 03:48:11 brent Exp $";
X#endif
X
X#include <stdio.h>
X
X#ifndef STRCHR
X#  define STRCHR(s,c) strchr(s,c)
X#endif
X
X#ifndef BIN
X#  define BIN "/usr/local/mail/majordomo"
X#endif
X
X#ifndef PATH
X#  define PATH "PATH=/bin:/usr/bin:/usr/ucb"
X#endif
X
X#ifndef HOME
X#  define HOME "HOME=/usr/local/mail/majordomo"
X#endif
X
X#ifndef SHELL
X#  define SHELL "SHELL=/bin/csh"
X#endif
X
Xchar * new_env[] = {
X    HOME,	/* 0 */
X    PATH,	/* 1 */
X    SHELL,	/* 2 */
X    0,		/* 3; possibly for USER or LOGNAME */
X    0,		/* 4; possible for LOGNAME */
X    0
X};
X    
Xmain(argc, argv, env)
X    int argc;
X    char * argv[];
X    char * env[];
X
X{
X    char * prog;
X    int e, i;
X
X    if (argc < 2) {
X	fprintf(stderr, "USAGE: %s program [<arg> ...]\n", argv[0]);
X	exit(1);
X    }
X
X    /* if the command contains a /, then don't allow it */
X    if (STRCHR(argv[1], '/') != NULL) {
X	/* this error message is intentionally cryptic */
X	fprintf(stderr, "%s: error: insecure usage\n", argv[0]);
X	exit(2);
X    }
X
X    if ((prog = (char *) malloc(strlen(BIN) + strlen(argv[1]) + 2)) == NULL) {
X	fprintf(stderr, "%s: error: malloc failed\n", argv[0]);
X	exit(3);
X    }
X
X    sprintf(prog, "%s/%s", BIN, argv[1]);
X
X    /*  copy the "USER=" and "LOGNAME=" envariables into the new environment,
X     *  if they exist.
X     */
X
X    e = 3; /* the first unused slot in new_env[] */
X
X    for (i = 0 ; env[i] != NULL ; i++) {
X	if ((strncmp(env[i], "USER=", 5) == 0) ||
X		(strncmp(env[i], "LOGNAME=", 8) == 0)) {
X	    new_env[e++] = env[i];
X	}
X    }
X
X#ifdef SYSV_GID
X    setgid(SYSV_GID);
X#else
X    setgid(getegid());
X#endif
X
X#ifdef SYSV_UID
X    setuid(SYSV_UID);
X#else
X    setuid(geteuid());
X#endif
X
X    execve(prog, argv+1, new_env);
X
X    /* the exec should never return */
X    perror(argv[1]);
X    exit(4);
X}
END_OF_FILE
if test 2685 -ne `wc -c <'wrapper.c'`; then
    echo shar: \"'wrapper.c'\" unpacked with wrong size!
fi
# end of 'wrapper.c'
fi
echo shar: End of shell archive.
exit 0
