#!/usr/local/bin/perl # $valid_users = "kroot,root,daemon"; $valid_group = "misnsm"; $localdocs = "http://infobahn/bsd/depts/ia/docs/messaging/mjdadmin.htm"; require "getopts.pl"; # WARNING: when called from wrapper, a quoted argument is not # preserved: -d 'a test list' becomes '-d' 'a' 'test' 'list'. # Therefore, the -description argument is pretty useless # for wrapper purposes, but perfectly fine if exec'd via # MajorCool (which is already wrapped). # die("Usage: $0 -d description -o owner -p passwd list...") unless &Getopts("C:d:o:p:"); &squawk("no list specified") unless @ARGV; $cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf"; $cf = $opt_C if $opt_C; $passwd = "$list.admin"; $passwd = $opt_p if $opt_p; # Read and execute the .cf file die("$cf not readable; stopped") if ! -r $cf; die("require of majordomo.cf failed $@") unless require "$cf"; # Go to the home directory specified by the .cf file chdir("$homedir"); # All these should be in the standard PERL library unshift(@INC, $homedir); require "ctime.pl"; # To get MoY definitions for month abbrevs require "majordomo_version.pl"; # What version of Majordomo is this? require "majordomo.pl"; # all sorts of general-purpose Majordomo subs require "shlock.pl"; # NNTP-style file locking require "config_parse.pl"; # functions to parse the config files # Here's where the fun begins... # check to see if the cf file is valid die("listdir not defined. Is majordomo.cf being included correctly?") if !defined($listdir); # where do we look for files, by default? $filedir = $listdir if !defined($filedir); $filedir_suffix = ".archive" if !defined($filedir_suffix); #---------------------------------------------------------------------------- # 1.94 has this set in $CF already $sendmail_command = "/usr/lib/sendmail" unless $sendmail_command; # don't allow just anyone to run this command... print "Validating permissions...\n"; &squawk("access denied") unless &is_user($valid_users,$valid_group); # unbuffered stdout/stderr select((select(STDOUT), $|=1)[$[]); select((select(STDERR), $|=1)[$[]); foreach $list (@ARGV) { print "Verifying list name...\n"; &squawk("list '$list' must be lowercase only") if $list =~ /[A-Z]+/; &squawk("invalid characters in list '$list'") unless $list =~ /^[-\w]+$/; &squawk("list '$list' already exists") if -f "$listdir/$list"; print "Checking for existing aliases...\n"; &squawk("address '$list' already exists") unless system("$sendmail_command -bv $list >/dev/null"); # # NOTE: depending on sendmail version, the above might # need to be changed to an "if". # create empty list; make config file # print "Adding list '$list'...\n"; open(LIST, ">$listdir/$list"); close(LIST); print "Creating default config file...\n"; &get_config($listdir, $list) if !&cf_ck_bool($list, '', 1); # tweak config based on command line settings # if ($opt_d || $opt_o || $opt_p) { print "Setting specified config options...\n"; open(OLDCF, "<$listdir/$list.config"); open(NEWCF, ">$listdir/$list.config.new"); while () { s/^description\s+=.*$/description = $opt_d/g if $opt_d; s/^owner\s+=.*$/owner = $opt_o/g if $opt_o; s/^admin_passwd\s+=.*$/admin_passwd = $opt_p/g if $opt_p; print NEWCF $_; } close(OLDCF); close(NEWCF); rename("$listdir/$list.config.new", "$listdir/$list.config"); } # send instructions # if ($opt_o) { print "Sending instructions to '$opt_o'...\n"; &send_docs; } # link to MASTER.PASSWD if it exists link("$listdir/MASTER.PASSWD", "$listdir/$list.passwd") if (-f "$listdir/MASTER.PASSWD"); if (-x "$homedir/mj_build_aliases") { print "Starting alias rebuild...\n"; system("nohup $homedir/mj_build_aliases @ >/dev/null &"); } print "Done.\n"; } sub squawk { local(@argv) = split('/',$0); printf STDERR "%s: @_\n", $argv[$#argv]; exit(1); } ### IS_USER(users, group) # boolean: match current user against other users/group # can be single token or colon-separated list # can be name or gid # sub is_user { local($users, $group) = @_[0,1]; local($valid); $current_user = getlogin || (getpwuid($<))[0] || die "Unknown user"; #print "$current_user: "; if ($users) { foreach (split(',', $users)) { #print "$_..."; if ($current_user eq $_) { $valid = 1; last; } } } if ($group && ! $valid) { #print "$group()..."; foreach (&group_members($group)) { #print "$_..."; if ($_ eq $current_user) { $valid = 1; last; } } } return $valid; } ### GROUP_MEMBERS(group) # list: return members of Unix group # checks both primary (/etc/passwd) and supplementary (/etc/group) # can be name or gid # sub group_members { local($target) = @_; return unless $target; local(@users); if ($target =~ /[^\d]*/) { # supplementary group, by name local($name,$passwd,$gid,$members) = getgrnam($target); $target = $gid; @users = split(' ',$members); } else { # supplementary group, by gid local($name,$passwd,$gid,$members) = getgrgid($target); @users = split(' ',$members); } # primary group, by gid while (($user,$pass,$uid,$gid) = getpwent) { push(@users, $user) if ($gid == $target); } return @users; } sub send_docs { &set_mailer($bounce_mailer ? $bounce_mailer : $mailer); &set_mail_sender($whoami_owner); &set_mail_from($whoami_owner); &sendmail(MAIL, $opt_o, "$list: Majordomo list created"); print MAIL <<"EOF"; A Majordomo list called "$list" has been created in your name. If this new list is unexpected or otherwise incorrect, please contact: $whoami_owner as soon as possible. Majordomo address: $whoami Majordomo owner: $whoami_owner List name: $list List posting address: $list@$whereami List request address: $list-request@$whereami List password: $passwd Your mailing list has been established. It is being served by an automated mailing list manager called 'Majordomo'. This message has all the details of how to manage your list remotely using Majordomo. There's a lot of info here, so please read this completely and carefully, and save it for future reference. Your list-owner password is shown above. Keep track of this; you'll need it later. Instructions for changing your password are below. As soon as possible, please establish an "info" file for your list (see below) to create the file that someone will receive when they join or ask about your list. See $localdocs for configuration instructions and other details. List configuration may be done via mail to Majordomo, or through the MajorCool Web interface at: $whereami_url If you have any questions about all of this, send them to the Majordomo-Owner address shown at the top of this file. ================ The Gory Details ================ Your mailing list is managed by an automated mailing list management program called Majordomo. Majordomo should free you from dealing with most of the administrivia usually associated with running mailing lists (adding users, dropping users, etc.). To submit something to your list, you (or anybody else) should simply mail it to the list posting address shown at the top of this file. If somebody sends something to list request address shown above (which is the traditional Internet way of being added to a mailing list), they'll get back a message telling them how to use Majordomo for routine requests, and how to contact you if they need to speak to a human being. To be added to your list, a user simply sends a message of the form subscribe your-list-name by email to either the Majordomo address or the list request address shown above. Majordomo understands several commands, and is not limited to a single command per message (it will process commands until reaching end-of-message or the command "end"). The command "help" will tell you about all the other commands. Actually, it won't tell you about _all_ the other commands that Majordomo understands. There are several commands there for use by list owners such as yourself, which are not advertised to the public. All of these commands are password-protected on a list-by-list basis, but anyone with a valid list/password combination can invoke these commands. This is not exactly high-tech security, but it's more intended to keep annoyance to a minimum than to be foolproof. The "documented" commands which Majordomo understands and which are for everyone to use are: subscribe [
] unsubscribe [
] which [
] who info index get lists help end You can get detailed explanations of all of these by asking for "help" from Majordomo. The "undocumented" commands for use by list owners are: approve {subscribe|unsubscribe} [
] This is so that you can approve subscription or unsubscription actions that need approval by the list owner. Note that this is just a standard "subscribe" or "unsubscribe" command prefixed with "approve " (where you substitute the password for your list, which is listed above, for ""). newinfo This is so that you can replace the information file that people get when they do "info " or "subscribe ". It reads everything after the "newinfo" command to end-of-message or the word "EOF" on a line by itself as the new info for the list. config Retrieves a self-documenting configuration file for the list . The is the password contained in the admin_passwd setting of the configuration file. newconfig Validates and installs a new configuration file. It reads everything after the "newconfig" command to end-of-message or the word "EOF" on a line by itself as the new info for the list. The config file is expected to be a complete config file as returned by "config". Incremental changing of the config file is not yet supported. As soon as the config file is validated and installed its settings are available for use. This is useful to remember if you have multiple commands in your mail message since they will be subject to the settings of the new config file. If there is an error in the config file (incorrect value...), the config file will not be accepted and the error message identifying the problem line(s) will be returned to the sender. Note that only the error messages are returned to the sender not the entire config file, so it would be a good idea to keep a copy of your outgoing email message. writeconfig Write a new config file in standard form. Writeconfig forces a rewrite of the config file with all comments and default values in place. It is useful to use after an upgrade of Majordomo since it will add the new keywords for people to change. It also updates the documentation in the file if that has changed. Configuring Your List ===================== You should retrieve the configuration file for your list. To do this, send an email message to the Majordomo address listed at the top of this form. The contents of this message should be: config Where are given at the top of this mail. You will receive a config file that can be used to change the operation of your list. The configuration file is meant to be self documenting. Once you have completed all of the changes to the config file, You should use the newconfig command (described above) to put a new configuration file in place. Approval ======== When Majordomo requests your approval for something, it sends you a message that includes a template of the approval message; if you concur, you simply need to replace "PASSWORD" in the template with your list password, and send the template line back to Majordomo. The requests for approval that Majordomo generates all start with "APPROVE" in the "Subject:" line. You aren't limited to approving only things to Majordomo requests approval for. You can approve any "subscribe" or "unsubscribe" request, regardless of whether Majordomo has requested this approval, with an "approve" command. Thus, you can subscribe or unsubscribe people from your list without them having to send anything to Majordomo; just send an appropriate "approve PASSWORD subscribe LIST ADDRESS" or "approve PASSWORD unsubscribe LIST ADDRESS" command off to Majordomo. Bounced Messages ================ Majordomo may bounce certain messages that people attempt to post to your mailing list. These messages may be bounced because they appear to be administrative requests (i.e., someone mailed a request to subscribe or unsubscribe to the posting address rather than to Majordomo or to the -request address), because they are too long, or for any of a number of other reasons. Majordomo will forward these messages to you in another message whose subject line begins with the word "BOUNCE"; the subject line will also indicate the name of the list the message was bounced from (in case you manage more than one list) and the reason the message was bounced. If you decide that the message is OK and should not have been bounced, then you can cause Majordomo to post it anyway by sending the message back to the posting address (NOT to the Majordomo address) with a special "Approved: password" header. To do this, follow these instructions: 1) Save the original message (the body of the message you received from Majordomo) in a file. 2) Edit the file to insert a line that says "Approved: password" (where "password" is the password for your list) at the top, before the headers and body of the original message. 3) Send this edited file back to the posting address for your list (NOT to Majordomo). This time around, Majordomo will notice the "Approved:" line and check it against your list password. If it matches, Majordomo will strip off the header of your message and the "Approved:" line (leaving just the original message), and send the original message on through. Moderation ========== If your list is moderated, (the 'moderate' parameter in the config file is 'yes') then messages without an "Approved:" line are bounced, just as described above. To cause them to be posted to the list, you add a valid "Approved:" line and send them back, just as described above. MajorCool ========= MajorCool is an alternative to using mail-based commands sent to the Majordomo list manager address. MajorCool provides a Web interface for many (but not all) of the most common config file settings. In addition, you can manage user subscriptions or edit the "info" file using this interface. The MajorCool Web interface is available as: $whereami_url EOF close(MAIL); }