An Internal Gate for a Local Email System
Lars Magnusson
Some years ago, I implemented a simple mail server --
qdms,
"the quick and dirty mail server," from alt.sources
-- to show my students what can be done with shell scripts.
The
main feature of the server was the use of a UNIX mailbox
as queuing
system.
Since then I have reused this concept in several other
applications,
as a small-scale netnews distribution system, a fax
gate, and an Internet
gate for a MS-Mail system. In this article I describe
the concept,
with reference to the Internet gate.
The Problem
A former collegue, now working as a regional technical
manager in
the state-owned Swedish Employement Training Cooperation,
needed to
get email out on to Internet through the organization's
newly acquired
MS-Mail system. MS-Mail is supposed to contact the Internet
and X400
through an email switch, Softswitch EMX. The problem
was that this
gate, used with MS-Mail, allowed internal mail users
only to reply
to external mail or to send mail to external correspondents,
who had
earlier sent mail in through the gate. Users could not
send mail out
to recipients not registred in the switch.
The Cause
MS-Mail addresses normally have a format of three fields
with a maximum
of ten letters each. Internet and X400 addresses must
be registered
as a prefix and a shortname, with ten or fewer letters
each. The shortname
is often a machine-generated identity string.
The result is that some MS-Mail to SMTP- or UUCP-gates,
such as the
Softswitch EMX, have serious problems in dealing with
new recipient
addresses. Such addresses must be registered by the
system administrator
before they can be used.
The Solution
Because he needed of immediate contact with people on
Internet, my
former colleague challenged me to come up with a quick
fix for this
problem. Since I knew that I was able to reach registered
addresses
on Internet, my solution was simple: Send the letter
to a fixed address,
a mail server, where the extra receiver address can
be extracted and
the letter rewritten and resent to the correct recipient.
At the local level, outgoing mail would have a fixed
first address
line. This line would specify the correct Internet address.
A UNIX mail machine still on the Internet was designated
as the holder
of the fixed address. This was where the Internet mail
would be queued
and processed.
To ensure that the gate could distinguish the fixed
address line from
ordinary lines in a message, we chose the following
format: "To
userid@domain". The MS-Mail system would send letters
to a shortname
tied to the mailbox on the UNIX system. This mailbox
would be read
by the application, the mailgate. By reading the Internet-address
on the first address line of the letter, the mailgate
could rebuild
the letter and resend it to the correct recipient, as
if it had come
directly from the sender. The receiver would notice
the detour only
if he/she read the receiver lines in the header of the
letter.
When a reply is received, it goes directly back to the
original sender
through the EMX email switch. This eliminates the use
of the extra
gate in future contacts, since the external mail ID
now gets automatically
registered with the reply.
The Implementation
The implementation begins on the UNIX gateway machine,
with the creation
of an ID associated with the gate's function, like inet,
internet,
or some other suitable name. The ID is registered in
the MS-Mail gate
under a similar name, in this case INTERNET-internet,
where the
first part designates the EMX gate and the second the
UNIX mailbox.
Mail sent by users is routed to the UNIX mailbox, where
it is queued
until it can be processed for retransmission out on
Internet.
The gateway process is a shell script, inetmail (Listing
1),
that is run by cron, once a minute. It reads the first
letter
in the box, saving it in a temporary file in /tmp. A
read from the
queue looks like this (under BSD):
/usr/5bin/echo "s 1 /tmp/infile.$$ \n q \n" | \
/usr/ucb/Mail -N -u mailbox-id > /dev/null 2>&1
The request is now saved as the tmp file infile.$$,
which will be used for subsequent processing.
At the same time the script steps the queue one position
forward by
deleting the letter from the queue with qn. Then
simulates a <RETURN> from the keyboard, a functionality
apparently
available only with the SVRx echo (the BSD echo's
that I tried did not have this capacity). If your system
doesn't have
a SVRx addendum, you might try saving the two commands
as two lines
without the "\n" and then using cat to supply
them
to the mail program (either Mail or mailx), like this:
cat mailcmd | Mail -N -u mailbox-id 2>&1 > /dev/null
A major advantage to using the mailer as a queueing
system
is that you don't have to worry about concurrency problems
during
the processing. If new requests come in during processing,
the mailer
system takes care of them independently, as when we
read our own mail.
The result is a fairly decent and flexible queuing system,
with the
only major drawback being that it is not as fast as
a custom-made
queuer.
After the letter is saved in the tmpfile, it must be
rebuilt with
new headers to prevent "Apparently-To:" headers
from showing
up. To accomplish this, I use grep, sed, awk,
and cut, storing the results in shell variables that
are later
used to construct the new header.
To prevent the fixed address line from appearing in
the letter, I
created a sed filter that just reads everything after
the
fixed address line into the new letter. Because of the
way ksh
and sed seem to jointly handle shell variables, I had
to dump
the sed script in a new tmpfile and run it from there.
When the letter is rebuilt, I run an error test on the
extra "To:"
header, to see if the sender had forgotten it. The test
could be placed
before the rebuilding of the letter, but since the load
on the system
from this gate is marginal, I didn't bother about the
order. The test
is a simple one and could be enhanced in different ways
to cover other
errors. The most important aspect is that the sender
receives a message
warning that his/her letter didn't make it through the
gate and telling
how to correct the problem.
Once the letter is rebuilt, I use sendmail, with the
-f
flag set to the original sender, to resend it:
sendmail -fsender receiver < letter
The letter now looks as if it had come directly from
sender.
One warning note: as you may know, this is how some
fake Internet
mail has been generated, so you must run the process
as a trusted
user, but not as root. I chose to run it as daemon,
and as far as
I can see, it should not be possible for this implementation
to compromise
the security within the local system.
Since I want to monitor the performance of the gate,
I also perform
some logging on the outgoing messages. In many organizations
this
is unnecessary, but if you are billing your departments,
you could
use the logging mechanism for accounting purposes. In
this case, though,
your users would have to send all their mail through
the gate, which
would in turn make cron's "every minute" much
too long a period
for coping with the queue.
Conclusion
The gate has worked for some time now as a semiofficial
gate for an
organization of 5,000 employees. Some bugs have been
ironed out --
what the present version lacks most significantly is
some form of
control if the system goes down during processing.
Since the gate was intended as a temporary measure (until
the vendor
solved this problem) and since it is monitored by the
local manager,
we felt that building such a control was not worth the
extra effort.
However, there are several diffent ways you could approach
this issue.
I would probably choose to resolve it by separating
the reading of
the letter into the tmpfile and the deletion of the
letter from the
queue into two steps, so that the letter would be deleted
from the
queue after it had been sent. Then, if the system were
to go down,
the letter would still be in the queue for processing.
This approach
does risk sending a letter twice, if the system should
crash between
sending and deleting -- which you may find unacceptable.
If so,
a lockfile solution would give better security.
Another possible problem can be the filtering of headers
in /usr/lib/mail.rc.
If the filtering becomes extensive -- for example, if
you remove
the ordinary "To" header -- the script would
have to be
reworked to get the make_request function to work properly.
In the case of a missing "To:" header, I would
replace the
present script lines with the following:
TO=`grep "^To: " $INFILE.$$ | awk '{print $0; exit }' | cut -d" " -f2`
Why not just remove the awk section? Well, the user
might
have included an old letter, with an extra, unexpected
"To:"
header. And if this isn't "disarmed" with
some "include"
char, then your script will crash. The same would apply
to the LINE
shell variable.
As a safety measure, when you've installed your queuescript,
run it
manually with sh -x scriptname a couple of times. For
some
shells you might need to add a set -x at the beginning
of
the individual functions. I found this to be the case
when I wrote
a script with the help of MKS Toolkit's DOS-ksh, while
SUN's sh
doesn't seem to need it.
About the Author
Lars Magnusson has a B.Sc. in Geology from Gothenburg
Univ.
in Sweden (1980) and an M.Sc. in Petroleum Exploration
from Chalmers
Univ. of Technology, also in Sweden (1984). He worked
as a mining
geologist/geophysist in Sweden and Greenland in the
early 1980s, but
since 1985 has been a system administrator, system manager,
and a
teacher of UNIX-related topics in Greenland, Denmark,
and Sweden.
He is currently a consultant specializing in UNIX system
administration,
sendmail, and DNS configuration.
|