Cover V04, I01
Article
Listing 1

jan95.tar


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.