Open Computing ``Hands-On'': ``Wizard's Grabbag'' Column: October 1994: Listings

Listing: The chkaddrs program summarizes Sendmail address processing.

A. Listing of chkaddrs:

  1  #!/usr/local/bin/perl
  2  # @(#) chkaddrs     Check sendmail address processing
  3  # Based on checksendmail, which was written by
  4  # Gene Kim, Rob Kolstad, and Jeff Polk, July 1990
  5  # Repackaged by Becca Thomas, July 1994
  6  
  7  # Configuration section:
  8  $=              = 24;                   # default report page length
  9  $|              = 1;                    # flush output after print,write
 10  $addr_file      = "address.resolve";    # default address input file
 11  $config_file    = "/etc/sendmail.cf";   # default sendmail config file
 12  $tmpfile        = "/tmp/chkaddrs.$$";   # temporary file
 13  $usage = "Usage: $0 [ -a addr-file ] [ -c config-file ] [ -q queuedir ]
 14      -a address-file         File containing addresses for testing
 15      -c configuration-file   Alternate sendmail configuration file
 16      -q queue directory      Alternate mail queue directory\n";
 17  
 18  # Process command-line options:
 19  require 'getopts.pl';   # library to process command-line options
 20  &Getopts('a:c:q:') || die "$usage"; # opt x arg into opt_x variable
 21  
 22  # Process option arguments:
 23  if ($opt_a) { $addr_file = $opt_a; }    # user-specified addr file
 24  if ($opt_c) { $config_file = $opt_c; }  # alternate config file
 25  
 26  # Determine queue directory specified in sendmail.cf config file:
 27  chop($queue_dir = `grep ^OQ $config_file`); # get dir value from file
 28  $queue_dir =~ s/^OQ//;                  # store default for later use
 29  
 30  if ($opt_q) { $queue_dir = $opt_q; }    # overwrite default value
 31  
 32  # Check for existence of these files and directory:
 33  die "Can't find address file, $addr_file\n"   unless -e $addr_file;
 34  die "Can't find config file $config_file\n"   unless -e $config_file;
 35  die "Can't find queue directory $queue_dir\n" unless -e $queue_dir;
 36  
 37  # Make sure the script user can access the queue directory:
 38  if ((! -r $queue_dir) || (! -x _) || (! -w _)) {
 39      die "$0: Aborting, can't access queue directory, $queue_dir!\n";
 40  }
 41  
 42  # Display status information:
 43  chop($hostname = `hostname`);
 44  chop($pwd = `pwd`);
 45  print "This system: $hostname\nCurrent directory: $pwd\n";
 46  print "Configuration file: $config_file\nAddress file: $addr_file\n";
 47  print "Queue directory: $queue_dir\n\n\n";
 48  
 49  # Trap keyboard-generated signals:
 50  sub handler {
 51      local($sig) = @_;           # first argument is signal name
 52      print STDERR "Caught a SIG$sig--shutting down\n";
 53      unlink($tmpfile);
 54      exit(0);
 55  }
 56  $SIG{'INT'} = 'handler';
 57  $SIG{'QUIT'} = 'handler';
 58  
 59  # REPORT FORMAT SPECIFICATIONS:
 60  # Override default screen length with LINES environment variable.
 61  ($= = $ENV{"LINES"}) if defined($ENV{"LINES"});
 62  
 63  # Current line count must be decremented because
 64  # print() already has been used to display five lines:
 65  $- = -5;
 66  
 67  format MAILERDEFINITIONS_TOP =
 68  Delivery   Input                      Dest            Dest
 69  Agent      Address                    Host            User
 70  ------------------------------------------------------------------------
 71  .
 72  
 73  format MAILERDEFINITIONS =
 74  @<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<
 75  $mailer,   $input,                    $dest_host,     $dest_user
 76  .
 77  
 78  format ADDRESSREWRITING_TOP =
 79  Delivery   Input                      Output
 80  Agent      Address                    Address
 81  ------------------------------------------------------------------------
 82  .
 83  
 84  format ADDRESSREWRITING =
 85  @<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 86  $mailer,   $input,                    $output
 87  .
 88  
 89  # SUBROUTINE DEFINITIONS:
 90  # Parse output of sendmail name resolution
 91  
 92  sub parseaddress
 93  {
 94      local($mailer, $intfile) = @_;      # store intermediate-file name
 95      local($input, $output);         # no conflict with global var.
 96  
 97      open(INTFILE, $intfile) || die "Exiting, can't open $intfile\n";
 98  
 99      $~ = 'ADDRESSREWRITING';
100      while () {
101              if (/^ADDRESS TEST MODE|^Enter /) { next; } # skip
102              chop;
103              if (/^>/) {                         # lines of interest
104                  if ($output) {                  #  contains output addr
105                      $output =~ s/^.*returns:  *//; # remove prefix
106                      $output =~ s/[ "]//g;       # no spaces, no quotes
107                      write;                      # mailer: input=>output
108                  }
109                  s/>.*input: *//; s/[ "]//g;     # isolate address
110                  $input = $_;                    # save input address
111              }
112              $output = $_;                       # save previous line
113      }
114      close(INTFILE);
115  }
116  
117  sub address_processing {
118      ($type) = @_;                   # either "Sender" or "Recipient"
119      $~ = 'STDOUT';                          # back to standard output
120      printf("\n%s-address rewriting:\n", $type);
121      $- = 0;                                 # force header display
122      $^ = 'ADDRESSREWRITING_TOP';            # new header format
123      write;                                  # write header
124      foreach $mailer (keys %mailers) {       # for each mailer
125          next if $mailer eq "error";         # ignore error mailer
126          if (($recvrules{$mailer} == 0) || ($sendrules{$mailer} == 0)) {
127              print STDERR "Ignoring $mailer: Can't locate rule set.\n";
128              next;
129          }
130          open(SENDMAIL,
131          "|/usr/lib/sendmail -bt -C$config_file -oQ$queue_dir >$tmpfile")
132              || die "Can't run /usr/lib/sendmail program.\n";
133           open(ADDRESSFILE, $addr_file) || die "Can't open $addr_file";
134          while () {
135              next if /^$/;                       # skip blank lines
136              $address = $_;                      # save address
137              print SENDMAIL "2,$recvrules{$mailer},4 $address\n"
138                  if $type eq "Recipient";
139              print SENDMAIL "1,$sendrules{$mailer},4 $address\n"
140                  if $type eq "Sender";
141          }
142          close(SENDMAIL); close(ADDRESSFILE);    # close, saving data
143          &parseaddress ($mailer, $tmpfile);      # display result
144      }
145  }
146  
147  # MAIN PROGRAM starts here:
148  
149  # Prefix each line of address file with "0 " so
150  # sendmail will process the addresses with rule set zero:
151  open(ADDRESSFILE, $addr_file)
152      || die "Can't open $addr_file for reading\n";
153  open(TMPFILE, ">$tmpfile")  || die "Can't open $tmpfile for writing\n";
154  while () {
155      print TMPFILE "0 $_" unless $_ eq "\n";     # skip blank lines
156  }
157  close(ADDRESSFILE); close(TMPFILE);
158  
159  open(SENDMAIL, # open to read from temp file containing "0 addr" lines.
160      "/usr/lib/sendmail -bt -C$config_file -oQ$queue_dir < $tmpfile|") ||
161      die "Can't exec /usr/lib/sendmail program...\n";
162  
163  # Get the mailers used from the Rule 0 tests and populate the
164  # the mailers associative array keyed by mailer, value arbitrary
165  $- = 0;                                     # force header display
166  $^ = 'MAILERDEFINITIONS_TOP';               # header format
167  write;                                      # display header
168  $~ = 'MAILERDEFINITIONS';                   # data format
169  while () {                        # Get next line (into $_)
170      chop;                                   # remove the newline from $_
171      if (/^ADDRESS TEST MODE|^Enter /) { next; } # skip prompts
172      if (/^>/) {                             # only process these lines
173          if ($prevline) {                    # prev line had mailer defn.
174              $prevline =~ s/^.*returns:  *//; # remove prefix text
175              $prevline =~ s/[ "]//g;         # no spaces, no quotes
176              # $prevline may contain: $#mailer$@dest_host$:dest_user
177              @t = split(/\$/, $prevline);    # divide into fields at "$"
178              $mailer = $dest_user = $dest_host = "XXX";  # defaults
179              for ($i = 1; $i <= $#t; $i++) { # for all fields
180                  if ($t[$i] =~ /^#(.*)/) {       # was $#mailer
181                      $mailer = $1;
182                  } elsif ($t[$i] =~ /^@(.*)/) {  # was $@dest_host
183                      $dest_host = $1;
184                  } elsif ($t[$i] =~ /^:(.*)/) {  # was $:dest_user
185                      $dest_user = $1;
186                  }
187              }
188              write;                          # display formatted report
189              if ($mailer ne "XXX") {
190                  $mailers{$mailer} = 1;      # add to list of mailers
191              }
192          }   # no previous line means current line has input address
193          s/>.*input: *//; s/[ "]//g;         # isolate address
194          $input = $_;                        # save input address
195      }   # end of if (/^>)
196      $prevline = $_;                         # store previous line
197  }
198  close(SENDMAIL);
199  
200  # Get delivery-agent specific sender and recipient rule-set numbers:
201  # Typical input line: Mether, P=[IPC], F=msDFMueCX, S=11, R=21, A=IPC $h
202  open(CONFIGFILE, "grep ^M $config_file|");  # mailer defn. lines
203  while ()
204  {
205      ($mailer)   = /^M(\w+),.*$/;            # get mailer name
206      ($sendrule) = /^.*S=(\d+),.*$/;         # get sender rule number
207      ($recvrule) = /^.*R=(\d+),.*$/;         # and recipient rule number
208      $sendrules{$mailer} = $sendrule;        # sender and recipient rules
209      $recvrules{$mailer} = $recvrule;        # keyed by mailer name
210  }
211  close(CONFIGFILE);
212  
213  # Display recipient-address processing:
214  &address_processing(Recipient);
215  
216  # Display sender-address processing:
217  &address_processing(Sender);
218  
219  unlink($tmpfile);                           # done so clean up

B. General command-line format for invoking chkaddrs:

chkaddrs [ -a addr-file ] [ -c config-file ] [ -q queuedir ]

C. Sample input address file:

beccat
beccat@yang
kolstad@bsdi.com
D. Report generated by chkaddrs on a ``client'' machine using the addresses shown in Part C:
# chkaddrs -a addressformats
This system: yin
Current directory: /usr/local/scripts
Configuration file: /etc/sendmail.cf
Address file: threeaddr
Queue directory: /usr/spool/mqueue


Delivery   Input                      Dest            Dest
Agent      Address                    Host            User
------------------------------------------------------------------------
local      beccat                     XXX             beccat
local      beccat@yang                XXX             beccat
ddn        kolstad@bsdi.com           bsdi.com        kolstad<@bsdi.com>

Recipient-address rewriting:
Delivery   Input                      Output
Agent      Address                    Address
------------------------------------------------------------------------
ddn        beccat                     beccat@magicats.org
ddn        beccat@yang                beccat@yang.magicats.org
ddn        kolstad@bsdi.com           kolstad@bsdi.com
local      beccat                     beccat
local      beccat@yang                beccat@yang
local      kolstad@bsdi.com           kolstad@bsdi.com

Sender-address rewriting:
Delivery   Input                      Output
Agent      Address                    Address
------------------------------------------------------------------------
ddn        beccat                     beccat@magicats.org
ddn        beccat@yang                beccat@yang.magicats.org
ddn        kolstad@bsdi.com           kolstad@bsdi.com
local      beccat                     beccat
local      beccat@yang                beccat@yang
local      kolstad@bsdi.com           kolstad@bsdi.com

# []

Copyright © 1995 The McGraw-Hill Companies, Inc. All Rights Reserved.
Edited by Becca Thomas / Online Editor / UnixWorld Online / beccat@wcmh.com

[Go to Contents] [Search Editorial]

Last Modified: Tuesday, 22-Aug-95 16:18:51 PDT