diff options
author | Jason Downs <downsj@cvs.openbsd.org> | 1996-12-14 21:17:55 +0000 |
---|---|---|
committer | Jason Downs <downsj@cvs.openbsd.org> | 1996-12-14 21:17:55 +0000 |
commit | 608a01ad15ff5ab89386edfd559332580581c47d (patch) | |
tree | 0247c82ab4d95ed523c3f3ecf6cf792a84cb635e | |
parent | 454743c06055e0f6c7c4532bdc9b81aeab85126c (diff) |
Update to Sendmail 8.8.4, plus recent patches, plus OpenBSD support.
Also include entire example configuration subset.
Includes smrsh (using /usr/libexec/sm.bin).
Of the top of my head, the only things I removed from the distribution were
contrib/mail.local.linux, src/Makefiles, all the *.0 and *.ps files.
Our praliases man page replaces the distributed one, ours is better.
82 files changed, 10827 insertions, 3248 deletions
diff --git a/usr.sbin/sendmail/FAQ b/usr.sbin/sendmail/FAQ index cc27e50805f..3ed325746f1 100644 --- a/usr.sbin/sendmail/FAQ +++ b/usr.sbin/sendmail/FAQ @@ -1,731 +1,9 @@ -Newsgroups: comp.mail.sendmail,comp.mail.misc,comp.mail.smail,comp.answers,news.answers -Subject: comp.mail.sendmail Frequently Asked Questions (FAQ) -From: brad@birch.ims.disa.mil (Brad Knowles) -Followup-to: comp.mail.sendmail -Summary: This posting contains a list of Frequently Asked Questions - (and their answers) about the program "sendmail", distributed - with many versions of Unix (and available for some other - operating systems). This FAQ is shared between - comp.mail.sendmail and the Sendmail V8 distribution. It should - be read by anyone who wishes to post to comp.mail.sendmail, or - anyone having questions about the newsgroup itself. - -Archive-name: mail/sendmail-faq -Posting-Frequency: monthly (first Monday) - - -[The most recent copy of this document can be obtained via anonymous -FTP from rtfm.mit.edu in /pub/usenet/news.answers/mail/sendmail-faq. +The FAQ is no longer maintained with the sendmail release. It is +posted regularly to comp.mail.sendmail, comp.mail.misc, comp.mail.smail, +comp.answers, and news.answers, and can be obtained via anonymous FTP +from ftp://rtfm.mit.edu/pub/usenet/news.answers/mail/sendmail-faq. If you do not have access to anonymous FTP, you can retrieve it by sending email to mail-server@rtfm.mit.edu with the command "send -usenet/news.answers/mail/sendmail-faq" in the message.] - - - - Sendmail Version 8 - Frequently Asked Questions - Last updated 9/17/95 - - -This FAQ is specific to Version 8.6.10 of sendmail. Other questions, -particularly regarding compilation and configuration, are answered in -src/READ_ME and cf/README (found in the V8 sendmail distribution). - -This is also the official FAQ for the Usenet newsgroup -comp.mail.sendmail. - -====================================================================== -BEFORE YOU GO ANY FURTHER -====================================================================== - - * What do you wish everyone would do before sending you mail or - posting to comp.mail.sendmail? - - Read this FAQ completely. Read src/READ_ME and cf/README - completely. Read the books written to help with common - problems such as compilation and installation, configuration, - security issues, etc.... Ask themselves if their question - hasn't already been answered. ----------------------------------------------------------------------- - * How can I be sure if this is the right place to look for answers - to my questions? - - 1. Do you know, for a fact, that the question is related to - sendmail V8? - - 2. Do you know, for a fact, that the question is related to an - older version of sendmail? - - 3. Is the question about a sendmail-like program (e.g., Smail, - Zmailer, MMDF, etc...)? - - 4. Is the question about an SMTP Gateway product for a LAN - mail package (e.g., cc:Mail, MS-Mail, WordPerfect - Office/GroupWise, etc...)? - - If you answered "yes" to the question #1, then this is the - right place. - - If you answered "yes" to questions #2 or #3, then you should - seriously consider upgrading to the most recent version of - sendmail V8. - - For question #2, If you're going to continue using an older - version of sendmail, you may not find much help and will - probably get some responses that amount to "Get V8". - Otherwise, this is probably the best place to look for - answers. - - If you answered "yes" to question #3 and are not going to - upgrade to sendmail V8, then this is probably not the right - place to look. - - If you answered "yes" to question #4, then this is almost - certainly not the right place to look. - - For questions #3 and #4, try looking around elsewhere in the - "comp.mail.*" hierarchy for a more appropriate newsgroup. - For example, you might want to try posting to comp.mail.misc - or comp.mail.smail. - - If you couldn't answer "yes" to any of the above questions, - then you're DEFINITELY in the wrong place. For the sake of - your sanity and ego, not to mention avoiding the waste of - your time and ours, try asking your System or E-Mail - Administrator(s) before you post any questions publicly. ----------------------------------------------------------------------- - * Where can I find the latest version of this FAQ? - - It is included in the most recent Version 8 distribution of - sendmail (described below), as well as via anonymous FTP from - rtfm.mit.edu in /pub/usenet/news.answers/mail/sendmail-faq. - If you do not have access to anonymous FTP, you can retrieve - it by sending email to mail-server@rtfm.mit.edu with the - command "send usenet/news.answers/mail/sendmail-faq" in the - message. ----------------------------------------------------------------------- - * I don't have access to Usenet news. Can I still get access to - comp.mail.sendmail? - - Yes. Send email to mxt@dl.ac.uk with the command "sub - comp-news.comp.mail.sendmail <full-US-ordered-email-address>" - in the message. - - E-mail you want posted on comp.mail.sendmail should be sent - to comp-mail-sendmail@dl.ac.uk ----------------------------------------------------------------------- - * I have sendmail-related DNS questions. Where should I ask them? - - Depending on how deeply they get into the DNS, they can be - asked here. However, you'll probably be told that you should - send them to the Info-BIND mailing list (if the question is - specific to that program) or to the Usenet newsgroup - comp.protocols.tcp-ip.domains (DNS in general). ----------------------------------------------------------------------- - * How do I subscribe to either of these? - - For comp.protocols.tcp-ip.domains, you have to be on Usenet. - They don't have a news-to-mail gateway yet. - - For the Info-BIND mailing list, send email to - bind-request@uunet.uu.net with the command "subscribe" in the - message. Submissions should be sent to bind@uunet.uu.net - -====================================================================== -GENERAL QUESTIONS -====================================================================== - - * Where can I get Version 8? - - Via anonymous FTP from FTP.CS.Berkeley.EDU in /ucb/sendmail. ----------------------------------------------------------------------- - * What are the differences between Version 8 and other versions? - - See doc/changes/changes.me in the sendmail distribution. ----------------------------------------------------------------------- - * What happened to sendmail 6.x and 7.x? - - When a new (Alpha/Beta) version of sendmail was released, it - was changed to Release 6. Development continued in that tree - until 4.4BSD was released, when everything on the 4.4 tape - was set to be version 8.1. Version 7.x never existed. ----------------------------------------------------------------------- - * What books are available describing sendmail? - - There is one book available devoted to sendmail: - - Costales, Allman, and Rickert, _Sendmail_. O'Reilly & - Associates. - - Several books have sendmail chapters, for example: - - Nemeth, Snyder, and Seebass, _Unix System Administration - Handbook_. Prentice-Hall. - Carl-Mitchell and Quarterman, _Practical Internetworking with - TCP/IP and UNIX_. Addison-Wesley. - Hunt, _TCP/IP Network Administration_. O'Reilly & Associates. - - Another book about sendmail is due out "soon": - - Avolio & Vixie, _Sendmail Theory and Practice_. Digital - Press (release date unknown). - - For details on sendmail-related DNS issues, consult: - - Liu and Albitz, _DNS and BIND_. O'Reilly & Associates. - - For details on UUCP, see: - - O'Reilly and Todino, _Managing UUCP and Usenet_. - O'Reilly & Associates. - -====================================================================== -COMPILING AND INSTALLING SENDMAIL 8 -====================================================================== - - * Version 8 requires a new version of "make". Where can I get this? - - Actually, Version 8 does not require a new version of "make". - It includes a collection of Makefiles for different architectures, - only one or two of which require the new "make". For a supported - architecture, use ``sh makesendmail''. If you are porting to a - new architecture, start with Makefile.dist. - - If you really do want the new make, it is available on any of - the BSD Net2 or 4.4-Lite distribution sites. These include: - - ftp.uu.net /systems/unix/bsd-sources - gatekeeper.dec.com /.0/BSD/net2 - ucquais.cba.uc.edu /pub/net2 - ftp.luth.se /pub/unix/4.3bsd/net2 - - Diffs and instructions for building this version of make - under SunOS 4.1.x are available on ftp.css.itd.umich.edu in - /pub/systems/sun/Net2-make.sun4.diff.Z. A patchkit for - Ultrix is on ftp.vix.com in /pub/patches/pmake-for-ultrix.Z. - Patches for AIX 3.2.4 are available on ftp.uni-stuttgart.de - in /sw/src/patches/bsd-make-rus-patches. - - There is also a Linux version available on the main Linux - distribution sites as pmake; this version is included as - standard with the current Slackware distributions. ----------------------------------------------------------------------- - * What macro package do I use to format the V8 man pages? - - The BSD group switched over the the ``mandoc'' macros for the - 4.4 release. These include more hooks designed for hypertext - handling. However, new man pages won't format under the old - man macros. Fortunately, old man pages will format under the - new mandoc macros. - - Get the new macros with the BSD Net2 or 4.4-Lite release (see - above for locations; for example, on FTP.UU.NET the files - /system/unix/bsd-sources/share/tmac/me/strip/sed and - /system/unix/bsd-sources/share/tmac/* are what you need). - - This macro set is also included with newer versions of groff. ----------------------------------------------------------------------- - * What modes should be used when installing sendmail? - - The sendmail binary should be owned by root, mode 4755. - The queue directory should be owned by root, with a mode - between 700 and 755. Under no circumstances should - it be group or other writable! - The sendmail config file should be owned by root, mode 644. - The aliases file should generally be owned by one trusted - user and writable only by that user, although it is - not unreasonable to have it group writable by a - "sysadmin" group. It should not be world writable. - The aliases database files (aliases.db or aliases.{pag,dir} - depending on what database format you compile with) - should be owned by root, mode 644. - -====================================================================== -CONFIGURATION QUESTIONS -====================================================================== - - * How do I make all my addresses appear to be from a single host? - - Using the V8 configuration macros, use: - - MASQUERADE_AS(my.dom.ain) - - This will cause all addresses to be sent out as being from - the indicated domain. ----------------------------------------------------------------------- - * How do I rewrite my From: lines to read ``First_Last@My.Domain''? - - There are a couple of ways of doing this. This describes - using the "user database" code. This is still experimental, - and was intended for a different purpose -- however, it does - work with a bit of care. It does require that you have the - Berkeley "db" package installed (it won't work with DBM). - - First, create your input file. This should have lines like: - - loginname:mailname First_Last - First_Last:maildrop loginname - - Install it in (say) /etc/userdb. Create the database: - - makemap btree /etc/userdb.db < /etc/userdb - - You can then create a config file that uses this. You will - have to include the following in your .mc file: - - define(confUSERDB_SPEC, /etc/userdb.db) - FEATURE(notsticky) ----------------------------------------------------------------------- - * So what was the user database feature intended for? - - The intent was to have all information for a given user - (where the user is the unique login name, not an inherently - non-unique full name) in one place. This would include phone - numbers, addresses, and so forth. The "maildrop" feature is - because Berkeley does not use a centralized mail server - (there are a number of reasons for this that are mostly - historic), and so we need to know where each user gets his or - her mail delivered -- i.e., the mail drop. - - We are in the process of setting up our environment so that - mail sent to an unqualified "name" goes to that person's - preferred maildrop; mail sent to "name@host" goes to that - host. The purpose of "FEATURE(notsticky)" is to cause - "name@host" to be looked up in the user database for delivery - to the maildrop. ----------------------------------------------------------------------- - * Why are you so hostile to using full names for e-mail addresses? - - Because full names are not unique. For example, the computer - community has two Andy Tannenbaums and two Peter Deutsches. - At one time, Bell Labs had two Stephen R. Bournes with - offices a few doors apart. You can create alternative - addresses (e.g., Stephen_R_Bourne_2), but that's even worse - -- which one of them has to have their name desecrated in - this way? And you can bet that one of them will get most of - the other person's e-mail. - - So called "full names" are just an attempt to create longer - versions of unique names. Rather that lulling people into a - sense of security, I'd rather that it be clear that these - handles are arbitrary. People should use good user agents - that have alias mappings so that they can attach arbitrary - names for their personal use to those with whom they - correspond (such as the MH alias file). - - Even worse is fuzzy matching in e-mail -- this can make good - addresses turn bad. For example, Eric Allman is currently - (to the best of our knowledge) the only ``Allman'' at - Berkeley, so mail sent to "Allman@Berkeley.EDU" should get to - him. But if another Allman ever appears, this address could - suddenly become ambiguous. He's been the only Allman at - Berkeley for over fifteen years -- to suddenly have this - "good address" bounce mail because it is ambiguous would be a - heinous wrong. - - Finger services should be as fuzzy as possible (within - reason, of course). Mail services should be unique. ----------------------------------------------------------------------- - * Should I use a wildcard MX for my domain? - - If at all possible, no. - - Wildcard MX records have lots of semantic "gotcha"s. For - example, they will match a host "unknown.your.domain" -- if - you don't explicitly test for unknown hosts in your domain, - you will get "config error: mail loops back to myself" - errors. - - See RFCs 1535-1537 for more detail and other related (or - common) problems. ----------------------------------------------------------------------- - * How can I get sendmail to process messages sent to an account and - send the results back to the originator? - - This is a local mailer issue, not a sendmail issue. - Depending on what you're doing, look at procmail (mentioned - again below), ftpmail, or Majordomo. - - Check your local archie server to see what machine(s) nearest - you have the most recent versions of these programs. ----------------------------------------------------------------------- - * How can I get sendmail to deliver local mail to $HOME/.mail - instead of into /usr/spool/mail (or /usr/mail)? - - Again, this is a local mailer issue, not a sendmail issue. - Either modify your local mailer (source code will be - required) or change the program called in the "local" mailer - configuration description to be a new program that does this - local delivery. One program that is capable of doing this is - "procmail", although there are probably many others as well. - - You might be interested in reading the paper ``HLFSD: - Delivering Email to your $HOME'' available in the Proceedings - of the USENIX System Administration (LISA VII) Conference - (November 1993). This is also available via public FTP from - ftp.cs.columbia.edu in /pub/hlfsd/{README.hlfsd,hlfsd.ps}. ----------------------------------------------------------------------- - * I'm trying to to get my mail to go into queue only mode, and it - delivers the mail interactively anyway. (Or, I'm trying to use - the "don't deliver to expensive mailer" flag, and it delivers the - mail interactively anyway.) I can see it does it: here's the - output of "sendmail -v foo@somehost" (or Mail -v or equivalent). - - The -v flag to sendmail (which is implied by the -v flag to - Mail and other programs in that family) tells sendmail to - watch the transaction. Since you have explicitly asked to - see what's going on, it assumes that you do not want to to - auto-queue, and turns that feature off. Remove the -v flag - and use a "tail -f" of the log instead to see what's going - on. - - If you are trying to use the "don't deliver to expensive - mailer" flag (mailer flag "e"), be sure you also turn on - global option "c" -- otherwise it ignores the mailer flag. ----------------------------------------------------------------------- - * There are four UUCP mailers listed in the configuration files. - Which one should I use? - - The choice is partly a matter of local preferences and what - is running at the other end of your UUCP connection. Unlike - good protocols that define what will go over the wire, UUCP - uses the policy that you should do what is right for the - other end; if they change, you have to change. This makes it - hard to do the right thing, and discourages people from - updating their software. In general, if you can avoid UUCP, - please do. - - If you can't avoid it, you'll have to find the version that - is closest to what the other end accepts. Following is a - summary of the UUCP mailers available. - - uucp-old (obsolete name: "uucp") - This is the oldest, the worst (but the closest to UUCP) way - of sending messages across UUCP connections. It does - bangify everything and prepends $U (your UUCP name) to the - sender's address (which can already be a bang path - itself). It can only send to one address at a time, so it - spends a lot of time copying duplicates of messages. Avoid - this if at all possible. - - uucp-new (obsolete name: "suucp") - The same as above, except that it assumes that in one rmail - command you can specify several recipients. It still has a - lot of other problems. - - uucp-dom - This UUCP mailer keeps everything as domain addresses. - Basically, it uses the SMTP mailer rewriting rules. - - Unfortunately, a lot of UUCP mailer transport agents - require bangified addresses in the envelope, although you - can use domain-based addresses in the message header. (The - envelope shows up as the From_ line on UNIX mail.) So.... - - uucp-uudom - This is a cross between uucp-new (for the envelope - addresses) and uucp-dom (for the header addresses). It - bangifies the envelope sender (From_ line in messages) - without adding the local hostname, unless there is no host - name on the address at all (e.g., "wolf") or the host - component is a UUCP host name instead of a domain name - ("somehost!wolf" instead of "some.dom.ain!wolf"). - - Examples: - - We are on host grasp.insa-lyon.fr (UUCP host name "grasp"). - The following summarizes the sender rewriting for various - mailers. - - Mailer sender rewriting in the envelope - ------ ------ ------------------------- - uucp-{old,new} wolf grasp!wolf - uucp-dom wolf wolf@grasp.insa-lyon.fr - uucp-uudom wolf grasp.insa-lyon.fr!wolf - - uucp-{old,new} wolf@fr.net grasp!fr.net!wolf - uucp-dom wolf@fr.net wolf@fr.net - uucp-uudom wolf@fr.net fr.net!wolf - - uucp-{old,new} somehost!wolf grasp!somehost!wolf - uucp-dom somehost!wolf somehost!wolf@grasp.insa-lyon.fr - uucp-uudom somehost!wolf grasp.insa-lyon.fr!somehost!wolf - -====================================================================== -RESOLVING PROBLEMS -====================================================================== - - * When I compile, I get "undefined symbol inet_aton" messages. - - You've probably replaced your resolver with the version from - BIND 4.9.3. You need to compile with -l44bsd in order to get - the additional routines. ----------------------------------------------------------------------- - * I'm getting "Local configuration error" messages, such as: - - 553 relay.domain.net config error: mail loops back to myself - 554 <user@domain.net>... Local configuration error - - How can I solve this problem? - - You have asked mail to the domain (e.g., domain.net) to be - forwarded to a specific host (in this case, relay.domain.net) - by using an MX record, but the relay machine doesn't - recognize itself as domain.net. Add domain.net to - /etc/sendmail.cw (if you are using FEATURE(use_cw_file)) or - add "Cw domain.net" to your configuration file. - - IMPORTANT: Be sure you kill and restart the sendmail daemon - after you change the configuration file (for ANY change in - the configuration, not just this one): - - kill `head -1 /etc/sendmail.pid` - sh -c "`tail -1 /etc/sendmail.pid`" - - NOTA BENE: kill -1 does not work! ----------------------------------------------------------------------- - * When I use sendmail V8 with a Sun config file I get lines like: - - /etc/sendmail.cf: line 273: replacement $3 out of bounds - - the line in question reads: - - R$*<@$%y>$* $1<@$2.LOCAL>$3 user@ether - - what does this mean? How do I fix it? - - V8 doesn't recognize the Sun "$%y" syntax, so as far as it is - concerned, there is only a $1 and a $2 (but no $3) in this - line. Read Rick McCarty's paper on "Converting Standard Sun - Config Files to Sendmail Version 8", in the contrib directory - (file "converting.sun.configs") on the sendmail distribution - for a full discussion of how to do this. ----------------------------------------------------------------------- - * When I use sendmail V8 on a Sun, I sometimes get lines like: - - /etc/sendmail.cf: line 445: bad ruleset 96 (50 max) - - what does this mean? How do I fix it? - - You're somehow trying to start up the old Sun sendmail (or - sendmail.mx) with a sendmail V8 config file, which Sun's - sendmail doesn't like. Check your /etc/rc.local, any - procedures that have been created to stop and re-start the - sendmail processes, etc.... Make sure that you've switched - everything over to using the new sendmail. To keep this - problem from ever happening again, try the following: - - mv /usr/lib/sendmail /usr/lib/sendmail.old - ln -s /usr/local/lib/sendmail.v8 /usr/lib/sendmail - mv /usr/lib/sendmail.mx /usr/lib/sendmail.mx.old - ln -s /usr/local/lib/sendmail.v8 /usr/lib/sendmail.mx - chmod 0000 /usr/lib/sendmail.old - chmod 0000 /usr/lib/sendmail.mx.old - - Assuming you have installed sendmail V8 in /usr/local/lib. ----------------------------------------------------------------------- - * When I use sendmail V8 on an IBM RS/6000 running AIX, the system - resource controller always reports sendmail as "inoperative" even - though it is running. What's wrong? - - IBM's system resource controller is one of their "value - added" features to AIX -- it's not a Unix standard. You'll - need to either redefine the subsystem to use signals (see - chssys(1)) or dump the entire subsystem and invoke sendmail - in /etc/rc.tcpip or some other boot script. ----------------------------------------------------------------------- - * When I use sendmail V8 on an Intel x86 machine running Linux, I - have some problems. Specifically, I have.... - - The current versions of Linux are generally considered to be - great for hobbyists and anyone else who wants to learn Unix - inside and out, or wants to always have something to do, or - wants a machine for light-duty mostly personal use and not - high-volume multi-user purposes. - - However, for those who want a system that will just sit in - the background and work without a fuss handling thousands of - mail messages a day for lots of different users, it's not - (yet) stable enough to fit the bill. - - Unfortunately, there are no known shareware/freeware - implementations of any operating system that provides the - level of stability necessary to handle that kind of load - (i.e., there are no free lunches). - - If you're wedded to the Intel x86 platform and want to run - sendmail, we suggest you look at commercial implementations - of Unix such as Interactive, UnixWare, Solaris, or BSD/386 - (just a sample of the dozens of different versions of Unix - for Intel x86). - - Of all known vendor supported versions of Unix for Intel x86, - BSDI's BSD/386 is least expensive and the only one known to - currently ship with sendmail V8 pre-installed. Since sendmail - V8 is continuing to be developed at UC Berkeley, and BSD/386 - is a full BSD 4.4 implementation, this is obviously be the most - "native" sendmail V8 environment. ----------------------------------------------------------------------- - * When I use sendmail on an Intel x86 machine running OS/2, I have - some problems. Specifically, I have.... - - The OS/2 port of sendmail is known to have left out huge - chunks of the code and functionality of even much older - versions of sendmail, in large part because the underlying OS - just doesn't have the necessary hooks to make it happen. - This port is so broken that we make no attempt to provide any - kind of support for it. Try BSDI's BSD/386 instead. ----------------------------------------------------------------------- - * I'm connected to the network via a SLIP/PPP link. Sometimes my - sendmail process hangs (although it looks like part of the - message has been transfered). Everything else works. What's - wrong? - - Most likely, the problem isn't sendmail at all, but the low - level network connection. It's important that the MTU - (Maximum Transfer Unit) for the SLIP connection be set - properly at both ends. If they disagree, large packets will - be trashed and the connection will hang. ----------------------------------------------------------------------- - * I just upgraded to 8.x and suddenly I'm getting messages in my - syslog of the form "collect: I/O error on connection". What is - going wrong? - - Nothing. This is just a diagnosis of a condition that had - not been diagnosed before. If you are getting a lot of these - from a single host, there is probably some incompatibility - between 8.x and that host. If you get a lot of them in - general, you may have network problems that are causing - connections to get reset. ----------------------------------------------------------------------- - * I just upgraded to 8.x and now when my users try to forward their - mail to a program they get an "illegal shell" message and their - mail is not delivered. What's wrong? - - In order for people to be able to run a program from their - .forward file, 8.x insists that their shell (that is, the - shell listed for that user in the passwd entry) be a "valid" - shell, meaning a shell listed in /etc/shells. If /etc/shells - does not exist, a default list is used, typically consisting - of /bin/sh and /bin/csh. - - This is to support environments that may have NFS-shared - directories mounted on machines on which users do not have - login permission. For example, many people make their - file server inaccessible for performance or security - reasons; although users have directories, their shell on - the server is /usr/local/etc/nologin or some such. If you - allowed them to run programs anyway you might as well let - them log in. - - If you are willing to let users run programs from their - .forward file even though they cannot telnet or rsh in (as - might be reasonable if you run smrsh to control the list of - programs they can run) then add the line - - /SENDMAIL/ANY/SHELL/ - - to /etc/shells. This must be typed exactly as indicated, - in caps, with the trailing slash. NOTA BENE: DO NOT - list /usr/local/etc/nologin in /etc/shells -- this will - open up other security problems. ----------------------------------------------------------------------- - * I just upgraded to 8.x and suddenly connections to the SMTP port - take a long time. What is going wrong? - - It's probably something weird in your TCP implementation that - makes the IDENT code act oddly. On most systems V8 tries to - do a ``callback'' to the connecting host to get a validated - user name (see RFC 1413 for detail). If the connecting host - does not support such a service it will normally fail quickly - with "Connection refused", but certain kinds of packet - filters and certain TCP implementations just time out. - - To test this, set the IDENT timeout to zero using - ``OrIdent=0'' in the configuration file. This will - completely disable all use of the IDENT protocol. - - Another possible problem is that you have your name server - and/or resolver configured improperly. Make sure that all - "nameserver" entries in /etc/resolv.conf point to functional - servers. If you are running your own server make certain - that all the servers listed in your root cache (usually - called something like "/var/namedb/root.cache"; see your - /etc/named.boot file to get your value) are up to date. - Either of these can cause long delays. ----------------------------------------------------------------------- - * I just upgraded to 8.x and suddenly I get errors such as ``unknown - mailer error 5 -- mail: options MUST PRECEDE recipients.'' What is - going wrong? - - You need OSTYPE(systype) in your .mc file -- otherwise the - configurations use a default that probably disagrees with - your local mail system. See cf/README for details. ----------------------------------------------------------------------- - * Under V8, the "From " header gets mysteriously munged when I send - to an alias. - - ``It's not a bug, it's a feature.'' This happens when you - have a "owner-list" alias and you send to "list". V8 - propagates the owner information into the envelope sender - field (which appears as the "From " header on UNIX mail or as - the Return-Path: header) so that downstream errors are - properly returned to the mailing list owner instead of to the - sender. In order to make this appear as sensible as possible - to end users, I recommend making the owner point to a - "request" address -- for example: - - list: :include:/path/name/list.list - owner-list: list-request - list-request: eric - - This will make message sent to "list" come out as being "From - list-request" instead of "From eric". ----------------------------------------------------------------------- - * I am trying to use MASQUERADE_AS (or the user database) to - rewrite from addresses, and although it works in the From: header - line, it doesn't work in the envelope (e.g., the "From " line). - - Believe it or not, this is intentional. The interpretation - of the standards by the V8 development group was that this - was an inappropriate rewriting, and that if the rewriting - were incorrect at least the envelope would contain a valid - return address. Other people have since described scenarios - where the envelope cannot be correct without this rewriting, - so 8.7 will have an option to rewrite both header and - envelope. ----------------------------------------------------------------------- - * I want to run Sendmail version 8 on my DEC system, but you don't - have MAIL11V3 support in sendmail. How do I handle this? - - Get Paul Vixie's reimplementation of the mail11 protocol from - gatekeeper.dec.com in /pub/DEC/gwtools. - - Rumour has it that he will be fully integrating into sendmail - V8 what little is left of IDA sendmail that is not handled - (or handled as well) by V8. No additional information on - this project is currently available. ----------------------------------------------------------------------- - * Messages seem to disappear from my queue unsent. When I look in - the queue directory I see that they have been renamed from qf* to - Qf*, and sendmail doesn't see these. - - If you look closely you should find that the Qf files are - owned by users other than root. Since sendmail runs as root - it refuses to believe information in non-root-owned qf files, - and it renames them to Qf to get them out of the way and make - it easy for you to find. The usual cause of this is - twofold: first, you have the queue directory world writable - (which is probably a mistake -- this opens up other security - problems) and someone is calling sendmail with an "unsafe" - flag, usually a -o flag that sets an option that could - compromise security. When sendmail sees this it gives up - setuid root permissions. +usenet/news.answers/mail/sendmail-faq" in the message. - The usual solution is to not use the problematic flags. If - you must use them, you have to write a special queue - directory and have them processed by the same uid that - submitted the job in the first place. ----------------------------------------------------------------------- -@(#)FAQ 8.16 (Berkeley) 9/17/95 -Send updates to sendmail@sendmail.ORG. + --Eric Allman 8/17/96 diff --git a/usr.sbin/sendmail/KNOWNBUGS b/usr.sbin/sendmail/KNOWNBUGS index f9020e7fb75..b948ca2d03e 100644 --- a/usr.sbin/sendmail/KNOWNBUGS +++ b/usr.sbin/sendmail/KNOWNBUGS @@ -1,7 +1,7 @@ K N O W N B U G S I N S E N D M A I L - (for 8.7) + (for 8.8) The following are bugs or deficiencies in sendmail that I am aware of @@ -74,18 +74,8 @@ This list is not guaranteed to be complete. not in the sendmail source code, so I assume it is also a bug in the sockets emulation. (Errno 22 is EINVAL "Invalid Argument" on all the systems I have available, including Solaris 2.x.) - -* Sending user deletion not done properly in :include: lists. - - If you don't have the "m" (me too) option set, then a person - sending to a list that contains themselves should not get a copy - of the message. However, if that list points to a :include: file - that has one address per line, this will break, and the sender - will always get a copy of their own message, just as though the - "m" option were set. - - You can eliminate this by adding commas at the end of each line - of the :include: file. + Apparently, this problem is due to linking -lc before -lsocket; + if you are having this problem, check your Makefile. * Excessive mailing list nesting can run out of file descriptors. @@ -116,4 +106,4 @@ This list is not guaranteed to be complete. allow for 8->7 bit MIME conversions either. -(Version 8.21, last updated 8/27/95) +(Version 8.23, last updated 10/15/96) diff --git a/usr.sbin/sendmail/Makefile b/usr.sbin/sendmail/Makefile index a9624233b60..67ee510fcbe 100644 --- a/usr.sbin/sendmail/Makefile +++ b/usr.sbin/sendmail/Makefile @@ -1,6 +1,7 @@ +# $OpenBSD: Makefile,v 1.3 1996/12/14 21:15:07 downsj Exp $ # @(#)Makefile 8.12 (Berkeley) 5/29/95 -SUBDIR= src mailstats makemap praliases cf/cf +SUBDIR= src smrsh mailstats makemap praliases cf/cf .if make(install) SUBDIR+= doc/intro doc/op .endif diff --git a/usr.sbin/sendmail/READ_ME b/usr.sbin/sendmail/READ_ME index 2e50d085eca..159ac81d9ef 100644 --- a/usr.sbin/sendmail/READ_ME +++ b/usr.sbin/sendmail/READ_ME @@ -1,5 +1,5 @@ /*- - * @(#)READ_ME 8.25 (Berkeley) 11/19/95 + * @(#)READ_ME 8.29 (Berkeley) 9/24/96 */ SENDMAIL RELEASE 8 @@ -9,6 +9,9 @@ doc/changes/changes.me for a summary of changes since 5.67. Report any bugs to sendmail-bugs@sendmail.ORG +There is a web site at http://WWW.Sendmail.ORG -- see that site for +the latest updates. + ****************************************************************** ** DO NOT USE MAKE to compile sendmail. Instead, cd src and ** ** use the "makesendmail" shell script. On many environments ** @@ -128,13 +131,20 @@ Important RFCs for electronic mail are: RFC976 UUCP mail format RFC1123 Host requirements (modifies 821, 822, and 974) RFC1413 Identification server - RFC1425 SMTP Service Extensions (ESMTP spec) - RFC1426 SMTP Service Extension for 8bit-MIMEtransport - RFC1427 SMTP Service Extension for Message Size Declaration + RFC1869 SMTP Service Extensions (ESMTP spec) + RFC1652 SMTP Service Extension for 8bit-MIMEtransport + RFC1870 SMTP Service Extension for Message Size Declaration RFC1521 MIME: Multipurpose Internet Mail Extensions RFC1344 Implications of MIME for Internet Mail Gateways RFC1428 Transition of Internet Mail from Just-Send-8 to 8-bit SMTP/MIME + RFC1891 SMTP Service Extension for Delivery Status Notifications + RFC1892 Multipart/Report Content Type for the Reporting of + Mail System Administrative Messages + RFC1893 Enhanced Mail System Status Codes + RFC1894 An Extensible Message Format for Delivery Status + Notifications + RFC1985 SMTP Service Extension for Remote Message Queue Starting Other standards that may be of interest (but which are less directly relevant to sendmail) are: diff --git a/usr.sbin/sendmail/RELEASE_NOTES b/usr.sbin/sendmail/RELEASE_NOTES index a4daceaf313..621cbcc3326 100644 --- a/usr.sbin/sendmail/RELEASE_NOTES +++ b/usr.sbin/sendmail/RELEASE_NOTES @@ -1,11 +1,930 @@ SENDMAIL RELEASE NOTES - @(#)RELEASE_NOTES 8.7.6.4 (Berkeley) 9/16/96 + @(#)RELEASE_NOTES 8.8.4.4 (Berkeley) 12/2/96 This listing shows the version of the sendmail binary, the version of the sendmail configuration files, the date of release, and a summary of the changes in that release. +8.8.4/8.8.4 96/12/02 + SECURITY: under some circumstances, an attacker could get additional + permissions by hard linking to files that were group + writable by the attacker. The solution is to disallow any + files that have hard links -- this will affect .forward, + :include:, and output files. Problem noted by Terry + Kyriacopoulos of Interlog Internet Services. As a + workaround, set UnsafeGroupWrites -- always a good idea. + SECURITY: the TryNullMXList (w) option should not be safe -- if it + is, it is possible to do a denial-of-service attack on + MX hosts that rely on the use of the null MX list. There + is no danger if you have this option turned off (the default). + Problem noted by Dan Bernstein. Also, make the DontInitGroups + unsafe. I know of no specific attack against this, although + a denial-of-service attack is probably possible, but in theory + you should not be able to safely tweak anything that affects + the permissions that are used when mail is delivered. + Purgestat could go into an infinite loop if one of the host status + directories somehow became empty. Problem noted by Roy + Mongiovi of Georgia Tech. + Processes got "lost" when counting children due to a race condition. + This caused "proc_list_probe: lost pid" messages to be logged. + Problem noted by several people. + On systems with System V SIGCLD child signal semantics (notably AIX + and HP-UX), mail transactions would print the message "451 + SMTP-MAIL: lost child: No child processes". Problem noted + by several people. + Miscellaneous compiler warnings on picky compilers (or when setting + gcc to high warning levels). From Tom Moore of NCR Corp. + SMTP protocol errors, and most errors on MAIL FROM: lines should + not be persistent between runs, since they are based on the + message rather than the host. Problem noted by Matt Dillon + of Best Internet Communications. + The F=7 flag was ignored on SMTP mailers. Problem noted by Tom Moore + of NCR (a.k.a., AT&T Global Information Solutions). + Avoid the possibility of having a child daemon run to completion + (including closing the SMTP socket) before the parent has + had a chance to close the socket; this can cause the parent + to hang for a long time waiting for the socket to drain. + Patch from Don Lewis of TDK Semiconductor. + If the fork() failed in a queue run, the queue runners would not be + rescheduled (so queue runs would stop). Patch from Don Lewis. + Some error conditions in ETRN could cause output without an SMTP + status code. Problem noted by Don Lewis. + Multiple :maildrop addresses in the user database didn't work properly. + Patch from Roy Mongiovi of Georgia Tech. + Add ".db" automatically onto any user database spec that does not + already have it; this is for consistency with makemap, the + K line, and the documentation. Inconsistency pointed out + by Roy Mongiovi. + Allow sendmail to be properly called in nohup mode. Patch from + Kyle Jones of UUNET. + Change ETRN to ignore but still update host status files; previously + it would ignore them and not save the updated status, which + caused stale information to be maintained. Based on a patch + from Christopher Davis of Kapor Enterprises Inc. Also, have + ETRN ignore the MinQueueAge option. + Patch long term host status to recover more gracefully from an empty + host status file condition. Patch from NAKAMURA Motonori + of Kyoto University. + Several patches to signal handling code to fix potential race + conditions from Don Lewis. + Make it possible to compile with -DDAEMON=0 (previously it had some + compile errors). This turns DAEMON, QUEUE, and SMTP into + 0/1 compilation flags. Note that DAEMON is an obsolete + compile flag; use NETINET instead. Solution based on a + patch from Bryan Costales. + PORTABILITY FIXES: + AIX4: getpwnam() and getpwuid() do a sequential scan of the + /etc/security/passwd file when called as root. This + is very slow on some systems. To speed it up, use the + (undocumented) _getpw{nam,uid}_shadow() routines. + Patch from Chris Thomas of UCLA/OAC Systems Group. + SCO 5.x: include -lprot in the Makefile. Patch from Bill + Glicker of Burrelle's Information Service. + NEWS-OS 4.x: need a definition for MODE_T to compile. Patch + from Makoto MATSUSHITA of Osaka University. + SunOS 4.0.3: compile problems. Patches from Andrew Cole of + Leeds University and SASABE Tetsuro of the University + of Tokyo. + DG/UX 5.4.4.11 from Brian J. Murrell of InterLinx Support + Services, Inc. + Domain/OS from Don (Truck) Lewis of TDK Semiconductor Corp. + I believe this to have only been a problem if you + compiled with -DUSE_VENDOR_CF_PATH -- another reason + to stick with /etc/sendmail.cf as your One True Path. + Digital UNIX (OSF/1 on Alpha) load average computation from + Martin Laubach of the Technischen Universität Wien. + CONFIG: change default Received: line to be multiple lines rather + than one long one. By popular demand. + MAIL.LOCAL: warnings weren't being logged on some systems. Patch + from Jerome Berkman of U.C. Berkeley. + MAKEMAP: be sure to zero hinfo to avoid cruft that can cause runs + to take a very long time. Problem noted by Yoshiro YONEYA + of NTT Software Corporation. + CONTRIB: add etrn.pl, contributed by John Beck. + NEW FILES: + contrib/etrn.pl + +8.8.3/8.8.3 96/11/17 + SECURITY: it was possible to get a root shell by lying to sendmail + about argv[0] and then sending it a signal. Problem noted + by Leshka Zakharoff <leshka@leshka.chuvashia.su> on the + best-of-security list. + Log sendmail binary version number in "Warning: .cf version level + (%d) exceeds program functionality (%d) message" -- this + should make it clearer to people that they are running + the wrong binary. + Fix a problem that occurs when you open an SMTP connection and then + do one or more ETRN commands followed by a MAIL command; at + the end of the DATA phase sendmail would incorrectly report + "451 SMTP-MAIL: lost child: No child processes". Problem + noted by Eric Bishop of Virginia Tech. + When doing text-based host canonification (typically /etc/hosts + lookup), a null host name would match any /etc/hosts entry + with space at the end of the line. Problem noted by Steve + Hubert of the University of Washington, Seattle. + 7 to 8 bit BASE64 MIME conversions could duplicate bits of text. + Problem reported by Tom Smith of Digital Equipment Corp. + Increase the size of the DNS answer buffer -- the standard UDP packet + size PACKETSZ (512) is not sufficient for some nameserver + answers containing very many resource records. The resolver + may also switch to TCP and retry if it detects UDP packet + overflow. Also, allow for the fact that the resolver + routines res_query and res_search return the size of the + *un*truncated answer in case the supplied answer buffer it + not big enough to accommodate the entire answer. Patch from + Eric Wassenaar. + Improvements to MaxDaemonChildren code. If you think you have too + many children, probe the ones you have to verify that they + are still around. Suggested by Jared Mauch of CICnet, Inc. + Also, do this probe before growing the vector of children + pids; this previously caused the vector to grow indefinitely + due to a race condition. Problem reported by Kyle Jones of + UUNET. + On some architectures, <db.h> (from the Berkeley DB library) defines + O_EXLOCK to zero; this fools the map compilation code into + thinking that it can avoid race conditions by locking on open. + Change it to check for O_EXLOCK non-zero. Problem noted by + Leif Erlingsson of Data Lege. + Always call res_init() on startup (if compiled in, of course) to + allow the sendmail.cf file to tweak resolver flags; without + it, flag tweaks in ResolverOptions are ignored. Patch from + Andrew Sun of Merrill Lynch. + Improvements to host status printing code. Suggested by Steve Hubert + of the University of Washington, Seattle. + Change MinQueueAge option processing to do the check for the job age + when reading the queue file, rather than at the end; this + avoids parsing the addresses, which can do DNS lookups. + Problem noted by John Beck of InReference, Inc. + When MIME was being 7->8 bit decoded, "From " lines weren't being + properly escaped. Problem noted by Peter Nilsson of the + University of Linkoping. + In some cases, sendmail would retain root permissions during queue + runs even if RunAsUser was set. Problem noted by Mark + Thomas of Mark G. Thomas Consulting. + If the F=l flag was set on an SMTP mailer to indicate that it is + actually local delivery, and NOTIFY=SUCCESS is specified in + the envelope, and the receiving SMTP server speaks DSN, then + the DSN would be both generated locally and propogated to the + other end. + The U= mailer field didn't correctly extract the group id if the + user id was numeric. Problem noted by Kenneth Herron of + MCI Telecommunications Communications. + If a message exceeded the fixed maximum size on input, the body of + the message was included in the bounce. Note that this did + not occur if it exceeded the maximum _output_ size. Problem + reported by Kyle Jones of UUNET. + PORTABILITY FIXES: + AIX4: 4.1 does't have a working setreuid(2); change the + AIX4 defines to use seteuid(2) instead, which + works on 4.1 as well as 4.2. Problem noted by + Håkan Lindholm of interAF, Sweden. + AIX4: use tzname[] vector to determine time zone name. + Patch from NAKAMURA Motonori of Kyoto University. + MkLinux: add Makefile.Linux.ppc and OSTYPE(mklinux) support. + Contributed by Paul DuBois <dubois@primate.wisc.edu>. + Solaris: kstat(3k) support for retrieving the load average. + This adds the LA_KSTAT definition for LA_TYPE. + The outline of the implementation was contributed + by Michael Tokarev of Telecom Service, JSC, Moscow. + HP-UX 10.0 gripes about the (perfectly legal!) forward + declaration of struct rusage at the top of conf.h; + change it to only be included if you are using gcc, + which is apparently the only compiler that requires + it in the first place. Problem noted by Jeff + Earickson of Colby College. + IRIX: don't default to using gcc. IRIX is a civilized + operating system that comes with a decent compiler + by default. Problem noted by Barry Bouwsma and + Kari Hurtta. + CONFIG: specify F=9 as default in FEATURE(local_procmail) for + consistency with other local mailers. Inconsistency + pointed out by Teddy Hogeborn <teddy@fukt.hk-r.se>. + CONFIG: if the "limited best mx" feature is used (to reduce DNS + overhead) as part of the bestmx_is_local feature, the + domain part was dropped from the name. Patch from Steve + Hubert of the University of Washington, Seattle. + CONFIG: catch addresses of the form "user@.dom.ain"; these could + end up being translated to the null host name, which would + return any entry in /etc/hosts that had a space at the end + of the line. Problem noted by Steve Hubert of the + University of Washington, Seattle. + CONFIG: add OSTYPE(aix4). From Michael Sofka of Rensselaer + Polytechnic Institute. + MAKEMAP: tweak hash and btree parameters for better performance. + Patch from Matt Dillon of Best Internet Communications. + NEW FILES: + src/Makefiles/Makefile.Linux.ppc + cf/ostype/aix4.m4 + cf/ostype/mklinux.m4 + +8.8.2/8.8.2 96/10/18 + SECURITY: fix a botch in the 7-bit MIME patch; the previous patch + changed the code but didn't fix the problem. + PORTABILITY FIXES: + Solaris: Don't use the system getusershell(3); it can + apparently corrupt the heap in some circumstances. + Problem found by Ken Pizzini of Spry, Inc. + OP.ME: document several mailer flags that were accidently omitted + from this document. These flags were F=d, F=j, F=R, and F=9. + CONFIG: no changes. + +8.8.1/8.8.1 96/10/17 + SECURITY: unset all environment variables that the resolver will + examine during queue runs and daemon mode. Problem noted + by Dan Bernstein of the University of Illinois at Chicago. + SECURITY: in some cases an illegal 7-bit MIME-encoded text/plain + message could overflow a buffer if it was converted back + to 8 bits. This caused core dumps and has the potential + for a remote attack. Problem first noted by Gregory Shapiro + of WPI. + Avoid duplicate deliveries of error messages on systems that don't + have flock(2) support. Patch from Motonori Nakamura of + Kyoto University. + Ignore null FallBackMX (V) options. If this option is null (as + opposed to undefined) it can cause "null signature" syserrs + on illegal host names. + If a Base64 encoded text/plain message has no trailing newline in + the encoded text, conversion back to 8 bits will drop the + final line. Problem noted by Pierre David. + If running with a RunAsUser, sendmail would give bogus "cannot + setuid" (or seteuid, or setreuid) messages on some systems. + Problem pointed out by Jordan Mendelson of Web Services, Inc. + Always print error messages in -bv mode -- previously, -bv would + be absolutely silent on errors if the error mode was sent + to (say) mail-back. Problem noted by Kyle Jones of UUNET. + If -qI/R/S is set (or the ETRN command is used), ignore all long + term host status. This is necessary because it is common + to do this when you know a host has just come back up. + Disallow duplicate HELO/EHLO commands as required by RFC 1651 section + 4.2. Excessive permissiveness noted by Lee Flight of the + University of Leicester. + If a service (such as NIS) is specified as the last entry in the + service switch, but that service is not compiled in, sendmail + would return a temporary failure when an entry was not found + in the map. This caused the message to be queued instead of + bouncing immediately. Problem noted by Harry Edmon of the + University of Washington. + PORTABILITY FIXES: + Solaris 2.3 had compilation problems in conf.c. Several + people pointed this out. + NetBSD from Charles Hannum of MIT. + AIX4 improvements based on info from Steve Bauer of South + Dakota School of Mines & Technology. + CONFIG: ``error:code message'' syntax was broken in virtusertable. + Patch from Gil Kloepfer Jr. + CONFIG: if FEATURE(nocanonify) was specified, hosts in $=M (set + using MASQUERADE_DOMAIN) were not masqueraded unless they + were also in $=w. Problem noted by Zoltan Basti of + Softec. + MAIL.LOCAL: patches to compile and link cleanly on AIX. Based + on a patch from Eric Hagberg of Morgan Stanley. + MAIL.LOCAL: patches to compile on NEXTSTEP. From Patrick Nolan + of Stanford via Robert La Ferla. + +8.8.0/8.8.0 96/09/26 + Under some circumstances, Bcc: headers would not be properly + deleted. Pointed out by Jonathan Kamens of OpenVision. + Log a warning if the sendmail daemon is invoked without a full + pathname, which prevents "kill -1" from working. I was + urged to put this in by Andrey A. Chernov of DEMOS (Russia). + Fix small buffer overflow. Since the data in this buffer was not + read externally, there was no security problem (and in fact + probably wouldn't really overflow on most compilers). Pointed + out by KIZU takashi of Osaka University. + Fix problem causing domain literals such as [1.2.3.4] to be ignored + if a FallbackMXHost was specified in the configuration file + -- all mail would be sent to the fallback even if the original + host was accessible. Pointed out by Munenari Hirayama of + NSC (Japan). + A message that didn't terminate with a newline would (sometimes) not + have the trailing "." added properly in the SMTP dialogue, + causing SMTP to hang. Patch from Per Hedeland of Ericsson. + The DaemonPortOptions suboption to bind to a particular address was + incorrect and nonfunctional due to a misunderstanding of the + semantics of binding on a passive socket. Patch from + NIIBE Yutaka of Mitsubishi Research Institute. + Increase the number of MX hosts for a single name to 100 to better + handle the truly huge service providers such as AOL, which + has 13 at the moment (and climbing). In order to avoid + trashing memory, the buffer for all names has only been + slightly increased in size, to 12.8K from 10.2K -- this means + that if a single name had 100 MX records, the average size + of those records could not exceed 128 bytes. Requested by + Brad Knowles of America On Line. + Restore use of IDENT returns where the OSTYPE field equals "OTHER". + Urged by Dan Bernstein of U.C. Berkeley. + Print q_statdate and q_specificity in address structure debugging + printout. + Expand MCI structure flag bits for debugging output. + Support IPv6-style domain literals, which can have colons between + square braces. + Log open file descriptors for the "cannot dup" messages in deliver(); + this is an attempt to track down a bug that one person seems + to be having (it may be a Solaris bug!). + DSN NOTIFY parameters were not properly propogated across queue runs; + this caused the NOTIFY info to sometimes be lost. Problem + pointed out by Claus Assmann of the + Christian-Albrechts-University of Kiel. + The statistics gathered in the sendmail.st file were too high; in + some cases failures (e.g., user unknown or temporary failure) + would count as a delivery as far as the statistics were + concerned. Problem noted by Tom Moore of AT&T GIS. + Systems that don't have flock() would not send split envelopes in + the initial run. Problem pointed out by Leonard Zubkoff of + Dandelion Digital. + Move buffer overflow checking -- these primarily involve distrusting + results that may come from NIS and DNS. + 4.4-BSD-derived systems, including FreeBSD, NetBSD, and BSD/OS didn't + include <paths.h> and hence had the wrong pathnames for a few + things like /var/tmp. Reported by Matthew Green. + Conditions were reversed for the Priority: header, resulting in all + values being interpreted as non-urgent except for non-urgent, + which was interpreted as normal. Patch from Bryan Costales. + The -o (optional) flag was being ignored on hash and btree maps + since 8.7.2. Fix from Bryan Costales. + Content-Types listed in class "q" will always be encoded as + Quoted-Printable (or more accurately, will never be encoded + as base64). The class can have primary types (e.g., "text") + or full types (e.g., "text/plain"). Based on a suggestion by + Marius Olafsson of the University of Iceland. + Define ${envid} to be the original envelope id (from the ESMTP DSN + dialogue) so it can be passed to programs in mailers. + Define ${bodytype} to be the body type (from the -B flag or the + BODY= ESMTP parameter) so it can be passed to programs in + mailers. + Cause the VRFY command to return 252 instead of 250 unless the F=q + flag is set in the mailer descriptor. Suggested by John + Myers of CMU. + Implement ESMTP ETRN command to flush the queue for a specific host. + The command takes a host name; data for that host is + immediately (and asynchronously) flushed. Because this shares + the -qR implementation, other hosts may be attempted, but + there should be no security implications. Implementation + from John Beck of InReference, Inc. See RFC 1985 for details. + Add three new command line flags to pass in DSN parameters: -V envid + (equivalent to ENVID=envid on the MAIL command), -R ret + (equivalent to RET=ret on the MAIL command), and -Nnotify + (equivalent to NOTIFY=notify on the RCPT command). Note + that the -N flag applies to all recipients; there is no way + to specify per-address notifications on the command line, + nor is there an equivalent for the ORCPT= per-address + parameter. + Restore LogLevel option to be safe (it can only be increased); + apparently I went into paranoid mode between 8.6 and 8.7 + and made it unsafe. Pointed out by Dabe Murphy of the + University of Maryland. + New logging on log level 15: all SMTP traffic. Patches from + Andrew Gross of San Diego Supercomputer Center. + NetInfo property value searching code wasn't stopping when it found + a match. This was causing the wrong values to be found (and + had a memory leak). Found by Bastian Schleuter of TU-Berlin. + Add new F=0 (zero) mailer flag to turn off MX lookups. It was pointed + out by Bill Wisner of Electronics for Imaging that you can't + use the bracket address form for the MAIL_HUB macro, since + that causes the brackets to remain in the envelope recipient + address used for delivery. The simple fix (stripping off the + brackets in the config file) breaks the use of IP literal + addresses. This flag will solve that problem. + Add MustQuoteChars option. This is a list of characters that must + be quoted if they are found in the phrase part of an address + (that is, the full name part). The characters @,;:\()[] are + always in this list and cannot be removed. The default is + this list plus . and ' to match RFC 822. + Add AllowBogusHELO option; if set, sendmail will allow HELO commands + that do not include a host name for back compatibility with + some stupid SMTP clients. Setting this violates RFC 1123 + section 5.2.5. + Add MaxDaemonChildren option; if this is set, sendmail will start + rejecting connections if it has more than this many + outstanding children accepting mail. Note that you may + see more processes than this because of outgoing mail; this + is for incoming connections only. + Add ConnectionRateThrottle option. If set to a positive value, the + number of incoming SMTP connections that will be permitted + in a single second is limited to this number. Connections are + not refused during this time, just deferred. The intent is to + flatten out demand so that load average limiting can kick in. + It is less radical than MaxDaemonChildren, which will stop + accepting connections even if all the connections are idle + (e.g., due to connection caching). + Add Timeout.hoststatus option. This interval (defaulting to 30m) + specifies how long cached information about the state of a + host will be kept before they are considered stale and the + host is retried. If you are using persistent host status + (i.e., the HostStatusDirectory option is set) this will apply + between runs; otherwise, it applies only within a single queue + run and hence is useful only for hosts that have large queues + that take a very long time to run. + Add SingleLineFromHeader option. If set, From: headers are coerced + into being a single line even if they had newlines in them + when read. This is to get around a botch in Lotus Notes. + Text class maps were totally broken -- if you ever retrieved the last + item in a table it would be truncated. Problem noted by + Gregory Neil Shapiro of WPI. + Extend the lines printed by the mailq command (== the -bp flag) when + -v is given to 120 characters; this allows more information + to be displayed. Suggested by Gregory Neil Shapiro of WPI. + Allow macro definitions (`D' lines) with unquoted commas; previously + this was treated as end-of-input. Problem noted by Bryan + Costales. + The RET= envelope parameter (used for DSNs) wasn't properly written + to the queue file. Fix from John Hughes of Atlantic + Technologies, Inc. + Close /var/tmp/dead.letter after a successful write -- otherwise + if this happens in a queue run it can cause nasty delays. + Problem noted by Mark Horton of AT&T. + If userdb entries pointed to userdb entries, and there were multiple + values for a given key, the database cursor would get + trashed by the recursive call. Problem noted by Roy Mongiovi + of Georgia Tech. Fixed by reading all the values and creating + a comma-separated list; thus, the -v output will be somewhat + different for this case. + Fix buffer allocation problem with Hesiod-based userdb maps when + HES_GETMAILHOST is defined. Based on a patch by Betty Lee + of Stanford University. + When envelopes were split due to aliases with owner- aliases, and + there was some error on one of the lists, more than one of + the owners would get the message. Problem pointed out by + Roy Mongiovi of Georgia Tech. + Detect excessive recursion in macro expansions, e.g., $X defined + in terms of $Y which is defined in terms of $X. Problem + noted by Bryan Costales; patch from Eric Wassenaar. + When using F=U to get "ugly UUCP" From_ lines, a buffer could in + some cases get trashed causing bogus From_ lines. Fix from + Kyle Jones of UUNET. + When doing load average initialization, if the nlist call for avenrun + failed, the second and subsequent lookups wouldn't notice + that fact causing bogus load averages to be returned. Noted + by Casper Dik of Sun Holland. + Fix problem with incompatibility with some versions of inet_aton that + have changed the return value to unsigned, so a check for an + error return of -1 doesn't work. Use INADDR_NONE instead. + This could cause mail to addresses such as [foo.com] to bounce + or get dropped. Problem noted by Christophe Wolfhugel of the + Pasteur Institute. + DSNs were inconsistent if a failure occured during the DATA phase + rather than the RCPT phase: the Action: would be correct, but + the detailed status information would be wrong. Problem noted + by Bob Snyder of General Electric Company. + Add -U command line flag and the XUSR ESMTP extension, both indicating + that this is the initial MUA->MTA submission. The flag current + does nothing, but in future releases (when MUAs start using + these flags) it will probably turn on things like DNS + canonification. + Default end-of-line string (E= specification on mailer [M] lines) + to \r\n on SMTP mailers. Default remains \n on non-SMTP + mailers. + Change the internal definition for the *file* and *include* mailers + to have $u in the argument vectors so that they aren't + misinterpreted as SMTP mailers and thus use \r\n line + termination. This will affect anyone who has redefined + either of these in their configuration file. + Don't assume that IDENT servers close the connection after a query; + responses can be newline terminated. From Terry Kennedy of + St. Peter's College. + Avoid core dumps on erroneous configuration files that have + $#mailer with nothing following. From Bryan Costales. + Avoid null pointer dereference with high debug values in unlockqueue. + Fix from Randy Martin of Clemson University. + Fix possible buffer overrun when expanding very large macros. Fix + from Kyle Jones of UUNET. + After 25 EXPN or VRFY commands, start pausing for a second before + processing each one. This avoids a certain form of denial + of service attack. Potential attack pointed out by Bryan + Costales. + Allow new named (not numbered!) config file rules to do validity + checking on SMTP arguments: check_mail for MAIL commands and + check_rcpt for RCPT commands. These rulesets can do anything + they want; their result is ignored unless they resolve to the + $#error mailer, in which case the indicated message is printed + and the command is rejected. Similarly, the check_compat + ruleset is called before delivery with "from_addr $| to_addr" + (the $| is a meta-symbol used to separate the two addresses); + it can give a "this sender can't send to this recipient" + notification. Note that this patch allows $| to stand alone + in rulesets. + Define new macros ${client_name}, ${client_addr}, and ${client_port} + that have the name, IP address, and port number (respectively) + of the SMTP client (that is, the entity at the other end of + the connection. These can be used in (e.g.) check_rcpt to + verify that someone isn't trying to relay mail through your + host inappropriately. Be sure to use the deferred evaluation + form, for example $&{client_name}, to avoid having these bound + when sendmail reads the configuration file. + Add new config file rule check_relay to check the incoming connection + information. Like check_compat, it is passed the host name + and host address separated by $| and can reject connections + on that basis. + Allow IDA-style recursive function calls. Code contributed by Mark + Lovell and Paul Vixie. + Eliminate the "No ! in UUCP From address!" message" -- instead, create + a virtual UUCP address using either a domain address or the $k + macro. Based on code contributed by Mark Lovell and Paul + Vixie. + Add Stanford LDAP map. Requires special libraries that are not + included with sendmail. Contributed by Booker C. Bense + <bbense@networking.stanford.edu>; contact him for support. + See also the src/READ_ME file. + Allow -dANSI to turn on ANSI escape sequences in debug output; this + puts metasymbols (e.g., $+) in reverse video. Really useful + only for debugging deep bits of code where it is important to + distinguish between the single-character metasymbol $+ and the + two characters $, +. + Changed ruleset 89 (executed in dumpstate()) to a named ruleset, + debug_dumpstate. + Add new UnsafeGroupWrites option; if set, .forward and :include: + files that are group writable are considered "unsafe" -- that + is, programs and files referenced from such files are not + valid recipients. + Delete bogosity test for FallBackMX host; this prevented it to be a + name that was not in DNS or was a domain-literal. Problem + noted by Tom May. + Change the introduction to error messages to more clearly delineate + permanent from temporary failures; if both existed in a + single message it could be confusing. Suggested by John + Beck of InReference, Inc. + The IngoreDot (i) option didn't work for lines that were terminated + with CRLF. Problem noted by Ted Stockwell of Secure + Computing Corporation. + Add a heuristic to improve the handling of unbalanced `<' signs in + message headers. Problem reported by Matt Dillon of Best + Internet Communications. + Check for bogus characters in the 0200-0237 range; since these are + used internally, very strange errors can occur if those + characters appear in headers. Problem noted by Anders Gertz + of Lysator. + Implement 7 -> 8 bit MIME conversions. This only takes place if the + recipient mailer has the F=9 flag set, and only works on + text/plain body types. Code contributed by Marius Olafsson + of the University of Iceland. + Special case "postmaster" name so that it is always treated as lower + case in alias files regardless of configuration settings; + this prevents some potential problems where "Postmaster" or + "POSTMASTER" might not match "postmaster". In most cases + this change is a no-op. + The -o map flag was ignored for text maps. Problem noted by Bryan + Costales. + The -a map flag was ignored for dequote maps. Problem noted by + Bryan Costales. + Fix core dump when a lookup of a class "prog" map returns no + response. Patch from Bryan Costales. + Log instances where sendmail is deferring or rejecting connections + on LogLevel 14. Suggested by Kyle Jones of UUNET. + Include port number in process title for network daemons. Suggested + by Kyle Jones of UUNET. + Send ``double bounces'' (errors that occur when sending an error + message) to the address indicated in the DoubleBounceAddress + option (default: postmaster). Previously they were always + sent to postmaster. Suggested by Kyle Jones of UUNET. + Add new mode, -bD, that acts like -bd in all respects except that + it runs in foreground. This is useful for using with a + wrapper that "watches" system services. Suggested by Kyle + Jones of UUNET. + Fix botch in spacing around (parenthesized) comments in addresses + when the comment comes before the address. Patch from + Motonori Nakamura of Kyoto University. + Use the prefix "Postmaster notify" on the Subject: lines of messages + that are being bounced to postmaster, rather than "Returned + mail". This permits the person who is postmaster more + easily determine what messages are to their role as + postmaster versus bounces to mail they actually sent. Based + on a suggestion by Motonori Nakamura. + Add new value "time" for QueueSortOrder option; this causes the queue + to be sorted strictly by the time of submission. Note that + this can cause very bad behaviour over slow lines (because + large jobs will tend to delay small jobs) and on nodes with + heavy traffic (because old things in the queue for hosts that + are down delay processing of new jobs). Also, this does not + guarantee that jobs will be delivered in submission order + unless you also set DeliveryMode=queue. In general, it should + probably only be used on the command line, and only in + conjunction with -qRhost.domain. In fact, there are very few + cases where it should be used at all. Based on an + implementation by Motonori Nakamura. + If a map lookup in ruleset 5 returns tempfail, queue the message in + the same manner as other rulesets. Previously a temporary + failure in ruleset 5 was ignored. Patch from Booker Bense + of Stanford University. + Don't proceed to the next MX host if an SMTP MAIL command returns a + 5yz (permanent failure) code. The next MX host will still be + tried if the connection cannot be opened in the first place + or if the MAIL command returns a 4yz (temporary failure) code. + (It's hard to know what to do here, since neither RFC 974 nor + RFC 1123 specify when to proceed to the next MX host.) + Suggested by Jonathan Kamens of OpenVision, Inc. + Add new "-t" flag for map definitions (the "K" line in the .cf file). + This causes map lookups that get a temporary failure (e.g., + name server failure) to _not_ defer the delivery of the + message. This should only be used if your configuration file + is prepared to do something sensible in this case. Based on + an idea by Gregory Shapiro of WPI. + Fix problem finding network interface addresses. Patch from + Motonori Nakamura. + Don't reject qf entries that are not owned by your effective uid if + you are not running setuid; this makes management of certain + kinds of firewall setups difficult. Patch suggested by + Eamonn Coleman of Qualcomm. + Add persistent host status. This keeps the information normally + maintained within a single queue run in disk files that are + shared between sendmail instances. The HostStatusDirectory + is the directory in which the information is maintained. If + not set, persistent host status is turned off. If not a full + pathname, it is relative to the queue directory. A common + value is ".hoststat". + There are also two new operation modes: + * -bh prints the status of hosts that have had recent + connections. + * -bH purges the host statuses. No attempt is made to save + recent status information. + This feature was originally written by Paul Vixie of Vixie + Enterprises for KJS and adapted for V8 by Mark Lovell of + Bigrock Consulting. Paul's funding of Mark and Mark's patience + with my insistence that things fit cleanly into the V8 + framework is gratefully appreciated. + New SingleThreadDelivery option (requires HostStatusDirectory to + operate). Avoids letting two sendmails on the local machine + open connections to the same remote host at the same time. + This reduces load on the other machine, but can cause mail to + be delayed (for example, if one sendmail is delivering a huge + message, other sendmails won't be able to send even small + messages). Also, it requires another file descriptor (for the + lock file) per connection, so you may have to reduce + ConnectionCacheSize to avoid running out of per-process + file descriptors. Based on the persistent host status code + contributed by Paul Vixie and Mark Lovell. + Allow sending to non-simple files (e.g., /dev/null) even if the + SafeFileEnvironment option is set. Problem noted by Bryan + Costales. + The -qR flag mistakenly matched flags in the "R" line of the queue + file. Problem noted by Bryan Costales. + If a job was aborted using the interrupt signal (e.g., control-C from + the keyboard), on some occasions an empty df file would be + left around; these would collect in the queue directory. + Problem noted by Bryan Costales. + Change the makesendmail script to enhance the search for Makefiles + based on release number. For example, on SunOS 5.5.1, it will + search for Makefile.SunOS.5.5.1, Makefile.SunOS.5.5, and then + Makefile.SunOS.5.x (in addition to the other rules, e.g., + adding $arch). Problem noted by Jason Mastaler of Atlanta + Webmasters. + When creating maps using "newaliases", always map the keys to lower + case when creating the map unless the -f flag is specified on + the map itself. Previously this was done based on the F=u + flag in the local mailer, which meant you could create aliases + that you could never access. Problem noted by Bob Wu of DEC. + When a job was read from the queue, the bits causing notification on + failure or delay were always set. This caused those + notifications to be sent even if NOTIFY=NEVER had been + specified. Problem noted by Steve Hubert of the University + of Washington, Seattle. + Add new configurable routine validate_connection (in conf.c). This + lets you decide if you are willing to accept traffic from + this host. If it returns FALSE, all SMTP commands will return + "550 Access denied". -DTCPWRAPPERS will include support for + TCP wrappers; you will need to add -lwrap to the link line. + (See src/READ_ME for details.) + Don't include the "THIS IS A WARNING MESSAGE ONLY" banner on postmaster + bounces. Some people seemed to think that this could be + confusing (even though it is true). Suggested by Motonori + Nakamura. + Add new RunAsUser option; this causes sendmail to do a setuid to that + user early in processing to avoid potential security problems. + However, this means that all .forward and :include: files must + be readable by that user, and on systems that don't support the + saved uid bit properly, all files to be written must be + writable by that user and all programs will be executed by that + user. It is also incompatible with the SafeFileEnvironment + option. In other words, it may not actually add much to + security. However, it should be useful on firewalls and other + places where users don't have accounts and the aliases file is + well constrained. + Add Timeout.iconnect. This is like Timeout.connect except it is used + only on the first attempt to delivery to an address. It could + be set to be lower than Timeout.connect on the principle that + the mail should go through quickly to responsive hosts; less + responsive hosts get to wait for the next queue run. + Fix a problem on Solaris that occassionally causes programs + (such as vacation) to hang with their standard input connected + to a UDP port. It also created some signal handling problems. + The problems turned out to be an interaction between vfork(2) + and some of the libraries, particularly NIS/NIS+. I am + indebted to Tor Egge <tegge@idt.ntnu.no> for this fix. + Change user class map to do the same matching that actual delivery + will do instead of just a /etc/passwd lookup. This adds + fuzzy matching to the user map. Patch from Dan Oscarsson. + The Timeout.* options are not safe -- they can be used to create a + denial-of-service attack. Problem noted by Christophe + Wolfhugel. + Don't send PostMasterCopy messages in the event of a "delayed" + notification. Suggested by Barry Bouwsma. + Don't advertise "VERB" ESMTP extension if the "noexpn" privacy + option is set, since this disables VERB mode. Suggested + by John Hawkinson of MIT. + Complain if the QueueDirectory (Q) option is not set. Problem noted + by Motonori Nakamura of Kyoto University. + Only queue messages on transient .forward open failures if there + were no successful opens. The previous behaviour caused it + to queue even if a "fall back" .forward was found. Problem + noted by Ann-Kian Yeo of the Dept. of Information Systems + and Computer Science (DISCS), NUS, Singapore. + Don't do 8->7 bit conversions when bouncing a MIME message that + is bouncing because of a MIME error during 8->7 bit conversion; + the encapsulated message will bounce again, causing a loop. + Problem noted by Steve Hubert of the University of Washington. + Create xf (transcript) files using the TempFileMode option value + instead of 0644. Suggested by Ann-Kian Yeo of the + National University of Singapore. + Print errors if setgid/setuid/etc. fail during delivery. This helps + detect cases where DefaultUid is set to something that the + system can't cope with. + PORTABILITY FIXES: + Support for AIX/RS 2.2.1 from Mark Whetzel of Western + Atlas International. + Patches for Intel Paragon OSF/1 1.3 from Leo Bicknell + <bicknell@ufp.org>. + On DEC OSF/1 3.2 and earlier, the MatchGECOS code would only + work on the first recipient of a message due to a + bug in the getpwent family. If this is something you + use, you can define DEC_OSF_BROKEN_GETPWENT=1 for a + workaround. From Maximum Entropy of Sanford C. + Bernstein and Associates. + FreeBSD 1.1.5.1 uname -r returns a string containing + parentheses, which breaks makesendmail. Reported + by Piero Serini <piero@strider.ibenet.it>. + Sequent DYNIX/ptx 4.0.2 patches from Jack Woolley of + Systems and Computer Technology Corporation. + Solaris 2.x: omit the UUCP grade parameter (-g flag) because + it is system-dependent. Problem noted by J.J. Bailey + of Bailey Computer Consulting. + Pyramid NILE running DC/OSx support from Earle F. Ake of + Hassler Communication Systems Technology, Inc. + HP-UX 10.x compile glitches, reported by Anne Brink of the + U.S. Army and James Byrne of Harte & Lyne Limited. + NetBSD from Matthew Green of the NetBSD crew. + SCO 5.x from Keith Reynolds of SCO. + IRIX 6.2 from Robert Tarrall of the University of + Colorado and Kari Hurtta of the Finnish Meteorological + Institute. + UXP/DS (Fujitsu/ICL DS/90 series) support from Diego R. + Lopez, CICA (Seville). + NCR SVR4 MP-RAS 3.x support from Tom Moore of NCR. + PTX 3.2.0 from Kenneth Stailey of the US Department of Labor + Employment Standards Administration. + Altos System V (5.3.1) from Tim Rice of Multitalents. + Concurrent Systems Corporation Maxion from Donald R. Laster + Jr. + NetInfo maps (improved debugging and multi-valued aliases) + from Adrian Steinmann of Steinmann Consulting. + ConvexOS 11.5 (including SecureWare C2 and the Share Scheduler) + from Eric Schnoebelen of Convex. + Linux 2.0 mail.local patches from Horst von Brand. + NEXTSTEP 3.x compilation from Robert La Ferla. + NEXTSTEP 3.x code changes from Allan J. Nathanson of NeXT. + Solaris 2.5 configuration fixes for mail.local by Jim Davis + of the University of Arizona. + Solaris 2.5 has a working setreuid. Noted by David Linn of + Vanderbilt University. + Solaris changes for praliases, makemap, mailstats, and smrsh. + Previously you had to add -DSOLARIS in Makefile.dist; + this auto-detects. Based on a patch from Randall + Winchester of the University of Maryland. + CONFIG: add generic-nextstep3.3.mc file. Contributed by + Robert La Ferla of Hot Software. + CONFIG: allow mailertables to resolve to ``error:code message'' + (where "code" is an exit status) on domains (previously + worked only on hosts). Patch from Cor Bosman of Xs4all + Foundation. + CONFIG: hooks for IPv6-style domain literals. + CONFIG: predefine ALIAS_FILE and change the prototype file so that + if it is undefined the AliasFile option is never set; this + should be transparent for most everyone. Suggested by John + Myers of CMU. + CONFIG: add FEATURE(limited_masquerade). Without this feature, any + domain listed in $=w is masqueraded. With it, only those + domains listed in a MASQUERADE_DOMAIN macro are masqueraded. + CONFIG: add FEATURE(masquerade_entire_domain). This causes + masquerading specified by MASQUERADE_DOMAIN to apply to all + hosts under those domains as well as the domain headers + themselves. For example, if a configuration had + MASQUERADE_DOMAIN(foo.com), then without this feature only + foo.com would be masqueraded; with it, *.foo.com would be + masqueraded as well. Based on an implementation by Richard + (Pug) Bainter of U. Texas. + CONFIG: add FEATURE(genericstable) to do a more general rewriting of + outgoing addresses. Defaults to ``hash -o /etc/genericstable''. + Keys are user names; values are outgoing mail addresses. Yes, + this does overlap with the user database, and figuring out + just when to use which one may be tricky. Based on code + contributed by Richard (Pug) Bainter of U. Texas with updates + from Per Hedeland of Ericsson. + CONFIG: add FEATURE(virtusertable) to do generalized rewriting of + incoming addresses. Defaults to ``hash -o /etc/virtusertable''. + Keys are either fully qualified addresses or just the host + part (with the @ sign). For example, a table containing: + info@foo.com foo-info + info@bar.com bar-info + @baz.org jane@elsewhere.net + would send all mail destined for info@foo.com to foo-info + (which is presumably an alias), mail addressed to info@bar.com + to bar-info, and anything addressed to anyone at baz.org will + be sent to jane@elsewhere.net. The names foo.com, bar.com, + and baz.org must all be in $=w. Based on discussions with + a great many people. + CONFIG: add nullclient configurations to define SMTP_MAILER_FLAGS. + Suggested by Richard Bainter. + CONFIG: add FAX_MAILER_ARGS to tweak the arguments passed to the + "fax" mailer. + CONFIG: allow mailertable entries to resolve to local:user; this + passes the original user@host in to procmail-style local + mailers as the "detail" information to allow them to do + additional clever processing. From Joe Pruett of + Teleport Corporation. Delivery to the original user can + be done by specifying "local:" (with nothing after the colon). + CONFIG: allow any context that takes "mailer:domain" to also take + "mailer:user@domain" to force mailing to the given user; + "local:user" can also be used to do local delivery. This + applies on *_RELAY and in the mailertable entries. Based + on a suggestion by Ribert Kiessling of Easynet. + CONFIG: Allow FEATURE(bestmx_is_local) to take an argument that + limits the possible domains; this reduces the number of DNS + lookups required to support this feature. For example, + FEATURE(bestmx_is_local, my.site.com) limits the lookups + to domains under my.site.com. Code contributed by Anthony + Thyssen <anthony@cit.gu.edu.au>. + CONFIG: LOCAL_RULESETS introduces any locally defined rulesets, + such as the check_rcpt ruleset. Suggested by Gregory Shapiro + of WPI. + CONFIG: MAILER_DEFINITIONS introduces any mailer definitions, in the + event you have to define local mailers. Suggested by + Gregory Shapiro of WPI. + CONFIG: fix cases where a three- (or more-) stage route-addr could + be misinterpreted as a list:...; syntax. Based on a patch by + Vlado Potisk <Vlado_Potisk@tempest.sk>. + CONFIG: Fix masquerading of UUCP addresses when the UUCP relay is + remotely connected. The address host!user was being + converted to host!user@thishost instead of host!user@uurelay. + Problem noted by William Gianopoulos of Raytheon Company. + CONFIG: add confTO_ICONNECT to set Timeout.iconnect. + CONFIG: change FEATURE(redirect) message from "User not local" to + "User has moved"; the former wording was confusing if the + new address is still on the local host. Based on a suggestion + by Andreas Luik. + CONFIG: add support in FEATURE(nullclient) for $=E (exposed users). + However, the class is not pre-initialized to contain root. + Suggested by Gregory Neil Shapiro. + CONTRIB: Remove XLA code at the request of the author, Christophe + Wolfhugel. + CONTRIB: Add re-mqueue.pl, contributed by Paul Pomes of Qualcomm. + MAIL.LOCAL: make it possible to compile mail.local on Solaris. Note + well: this produces a slightly different mailbox format (no + Content-Length: headers), file ownerships and modes are + different (not owned by group mail; mode 600 instead of 660), + and the local mailer flags will have to be tweaked (make them + match bsd4.4) in order to use this mailer. Patches from Paul + Hammann of the Missouri Research and Education Network. + MAIL.LOCAL: in some cases it could return EX_OK even though there + was a delivery error, such as if the ownership on the file + was wrong or the mode changed between the initial stat and + the open. Problem reported by William Colburn of the New + Mexico Institute of Mining and Technology. + MAILSTATS: handle zero length files more reliably. Patch from Bryan + Costales. + MAILSTATS: add man page contributed by Keith Bostic of BSDI. + MAKEMAP: The -d flag (to allow duplicate keys) to a btree map wasn't + honored. Fix from Michael Scott Shappe. + PRALIASES: add man page contributed by Keith Bostic of BSDI. + NEW FILES: + src/Makefiles/Makefile.AIX.2 + src/Makefiles/Makefile.IRIX.6.2 + src/Makefiles/Makefile.maxion + src/Makefiles/Makefile.NCR.MP-RAS.3.x + src/Makefiles/Makefile.SCO.5.x + src/Makefiles/Makefile.UXPDSV20 + mailstats/mailstats.8 + praliases/praliases.8 + cf/cf/generic-nextstep3.3.mc + cf/feature/genericstable.m4 + cf/feature/limited_masquerade.m4 + cf/feature/masquerade_entire_domain.m4 + cf/feature/virtusertable.m4 + cf/ostype/aix2.m4 + cf/ostype/altos.m4 + cf/ostype/maxion.m4 + cf/ostype/solaris2.ml.m4 + cf/ostype/uxpds.m4 + contrib/re-mqueue.pl + DELETED FILES: + src/Makefiles/Makefile.Solaris + contrib/xla/README + contrib/xla/xla.c + RENAMED FILES: + src/Makefiles/Makefile.NCR3000 => Makefile.NCR.MP-RAS.2.x + src/Makefiles/Makefile.SCO.3.2v4.2 => Makefile.SCO.4.2 + src/Makefiles/Makefile.UXPDS => Makefile.UXPDSV10 + src/Makefiles/Makefile.NeXT => Makefile.NeXT.2.x + src/Makefiles/Makefile.NEXTSTEP => Makefile.NeXT.3.x + 8.7.6/8.7.3 96/09/17 SECURITY: It is possible to force getpwuid to fail when writing the queue file, causing sendmail to fall back to running programs @@ -18,8 +937,11 @@ summary of the changes in that release. 8.7.5/8.7.3 96/03/04 Fix glitch in 8.7.4 when putting certain internal lines; this can - in some case cause connections to hang. Patch from Eric - Wassenaar. + in some case cause connections to hang or messages to have + extra spaces in odd places. Patch from Eric Wassenaar; + reports from Eric Hall of Chiron Corporation, Stephen + Hansen of Stanford University, Dean Gaudet of HotWired, + and others. 8.7.4/8.7.3 96/02/18 SECURITY: In some cases it was still possible for an attacker to @@ -80,7 +1002,7 @@ summary of the changes in that release. to simplify queue management for clustered systems. Suggested by Gregory Neil Shapiro of WPI. The same problem could break MH, which assumes that the SMTP session will succeed (tsk, tsk - -- mail gets lost!); this was pointe dout by Stuart Pook of + -- mail gets lost!); this was pointed out by Stuart Pook of Infobiogen. Fix possible buffer overflow in munchstring(). This was not a security problem because you couldn't specify any argument to this @@ -379,7 +1301,7 @@ summary of the changes in that release. Syntax errors such as unbalanced parentheses in the configuration file could be omitted if you had "Oem" prior to the syntax error in the config file. Change to always print - the error message. It was especially wierd because it + the error message. It was especially weird because it would cause a "warning" message to be sent to the Postmaster for every message sent (but with no transcript). Problem noted by Gregory Paris of Motorola. @@ -720,7 +1642,8 @@ summary of the changes in that release. "dns" is in the service list for "hosts". Add preliminary support for the ESMTP "DSN" extension (Delivery Status Notifications). DSN notifications override - Return-Receipt-To: headers, which are bogus anyhow. + Return-Receipt-To: headers, which are bogus anyhow -- + support for them has been removed. Add T=mts-name-type/address-type/diagnostic-type keyletter to mailer definitions to define the types used in DSN returns for MTA names, addresses, and diagnostics respectively. @@ -1112,7 +2035,7 @@ summary of the changes in that release. only works on adjacent preferences, so an MX list that had A=5, B=10, A=15 would leave both As, but one that had A=5, A=10, B=15 would reduce to A, B. This is intentional, - just in case there is something wierd I haven't thought of. + just in case there is something weird I haven't thought of. Suggested by Barry Shein of Software Tool & Die. SECURITY: .forward files cannot be symbolic links. If they are, a bad guy can read your private files. @@ -1484,7 +2407,7 @@ summary of the changes in that release. contrib/rcpt-streaming src/Makefiles/Makefile.SunOS.5.x -8.6.13/8.6.12 95/01/25 +8.6.13/8.6.12 96/01/25 SECURITY: In some cases it was still possible for an attacker to insert newlines into a queue file, thus allowing access to any user (except root). @@ -1709,7 +2632,7 @@ summary of the changes in that release. fixed by Michael Corrigan and Christophe Wolfhugel. 8.6.7/8.6.6 94/03/14 - SECURITY: it was possible to get root access by using wierd + SECURITY: it was possible to get root access by using weird values to the -d flag. Thanks to Alain Durand of INRIA for forwarding me the notice from the bugtraq list. @@ -1847,7 +2770,7 @@ summary of the changes in that release. CNAME loops caused an error message to be generated, but also re-queued the message. Changed to just re-queue the message (it's really hard to just bounce it because - of the wierd way the name server works in the presence + of the weird way the name server works in the presence of CNAME loops). Problem noted by James M.R.Matheson of Cambridge University. Avoid giving ``warning: foo owned process doing -bs'' messages @@ -2112,7 +3035,7 @@ summary of the changes in that release. Make sure that route-addrs always have <angle brackets> around them in non-SMTP envelopes (SMTP envelopes already do this properly). - Avoid wierd headers on unbalanced punctuation of the form: + Avoid weird headers on unbalanced punctuation of the form: ``Joe User <user)'' -- this caused reference to the null macro. Fix from Rick McCarty of IO.COM. Fix a problem that caused an alias "user: user@local.host" to @@ -2516,7 +3439,8 @@ summary of the changes in that release. is set. Problem noted by P{r (Pell) Emanuelsson. Fix a problem causing the "c" option (don't connect to expensive mailers) to be ignored in SMTP. Problem noted and the - solution suggested by Robert Elz of Munnari University. + solution suggested by Robert Elz of The University of + Melbourne. Improve connection caching algorithm by passing "[host]" to hostsignature, which strips the square brackets and returns the real name. This allows mailertable entries @@ -2776,7 +3700,7 @@ summary of the changes in that release. the "to" address). Problem noted by John Myers. Fix dfopen to return NULL if the open failed; I was depending on fdopen(-1) returning NULL, which isn't the case. This - isn't serious, but does result in wierd error diagnoses. + isn't serious, but does result in weird error diagnoses. From Michael Corrigan. CONFIG: add UUCP_MAX_SIZE M4 macro to set the maximum size of messages sent through UUCP-family mailers. Suggested @@ -2812,7 +3736,7 @@ summary of the changes in that release. Changes from Eric Wassenaar. Open /dev/null for the transcript if the create of the xf file failed; this avoids at least one possible null pointer - reference in very wierd cases. From Eric Wassenaar. + reference in very weird cases. From Eric Wassenaar. Clean up statistics gathering; it was over-reporting because of forks. From Eric Wassenaar. Fix problem that causes old Return-Path: line to override new @@ -3063,7 +3987,7 @@ summary of the changes in that release. PRALIASES: support for printing NEWDB databases. From Michael J. Corrigan of U.C. San Diego. CONFIG: don't pass pseudo-domains to $[ ... $] (if you have - a wildcard MX it can have wierd results). From + a wildcard MX it can have weird results). From Christophe Wolfhugel. CONFIG: dot terminate relay hostnames in S0. From Christophe Wolfhugel. @@ -3176,7 +4100,7 @@ summary of the changes in that release. Don't try to flock non-regular files when mailing to a file. In particular, this was a problem if you tried to send to /dev/null. - Fix a wierd bug that can cause senders to be queued as + Fix a weird bug that can cause senders to be queued as recipients if the name server is down when the mail is initially sent. This hack just ignores sender deletion (essentially, it sets the MeToo flag) if there @@ -3510,7 +4434,7 @@ summary of the changes in that release. file to have an F line, and the format of the T option to accept take the format "return/warn" (both intervals). Don't force all local names to lower case -- this was left over - from the wierd handling of case mapping on aliases. It + from the weird handling of case mapping on aliases. It is now driven (as expected) by the "u" mailer flag. Problem noted by P{r Emanuelsson. Fix problem that caused headers on returned email to be trashed; @@ -3613,7 +4537,7 @@ summary of the changes in that release. mailer. Additional debug printing in getcanonname (show query type). Don't add the e_fromdomain on sender addresses -- this interacts - wierdly with the owner- code. + weirdly with the owner- code. Improve delivery logging to not log obvious or meaningless stuff. Include numeric IP address in Received: lines per RFC 1123 section 5.2.8. @@ -3695,7 +4619,7 @@ summary of the changes in that release. Config extensions for Sam Leffler's FlexFAX software. 6.31/6.10 93/02/28 - Fix some more bugs in alias owner code -- there were some wierd + Fix some more bugs in alias owner code -- there were some weird cases where an error in a non-aliased name would override the return info in an aliased name with an owner. Changes from WIDE Project, forwarded to me by Motonori Nakamura: diff --git a/usr.sbin/sendmail/cf/README b/usr.sbin/sendmail/cf/README index 3a4979f83e4..e17d08a38d4 100644 --- a/usr.sbin/sendmail/cf/README +++ b/usr.sbin/sendmail/cf/README @@ -4,7 +4,7 @@ Eric Allman <eric@CS.Berkeley.EDU> - @(#)README 8.81 (Berkeley) 12/3/95 + @(#)README 8.108 (Berkeley) 11/16/96 This document describes the sendmail configuration files being used @@ -13,7 +13,7 @@ not work on other versions. These configuration files are probably not as general as previous versions, and don't handle as many of the weird cases automagically. -I was able to simplify by them for two reasons. First, the network +I was able to simplify them for two reasons. First, the network has become more consistent -- for example, at this point, everyone on the internet is supposed to be running a name server, so hacks to handle NIC-registered hosts can go away. Second, I assumed that a @@ -128,7 +128,7 @@ Let's examine a typical .mc file: divert(0) The divert(-1) will delete the crud in the resulting output file. -The copyright notice can be replace by whatever your lawyers require; +The copyright notice can be replaced by whatever your lawyers require; our lawyers require the one that I've included in my files. A copyleft is a copyright by another name. The divert(0) restores regular output. @@ -158,9 +158,38 @@ definition appropriate for your environment. MAILER(smtp) These describe the mailers used at the default CS site site. The -local mailer is always included automatically. Beware MAILER -declarations should always be last in the configuration file, and -MAILER(smtp) should always precede MAILER(uucp). +local mailer is always included automatically. Beware: MAILER +declarations should always be at the end of the configuration file, +and MAILER(smtp) should always precede MAILER(uucp). The general +rules are that the order should be: + + VERSIONID + OSTYPE + DOMAIN + FEATURE + local macro definitions + MAILER + LOCAL_RULESET_* + + ++----------------------------+ +| A BRIEF INTRODUCTION TO M4 | ++----------------------------+ + +Sendmail uses the M4 macro processor to ``compile'' the configuration +files. The most important thing to know is that M4 is stream-based, +that is, it doesn't understand about lines. For this reason, in some +places you may see the word ``dnl'', which standards for ``delete +through newline''; essentially, it deletes all characters starting +at the ``dnl'' up to and including the next newline character. In +most cases sendmail uses this only to avoid lots of unnecessary +blank lines in the output. + +Other important directives are define(A, B) which defines the macro +``A'' to have value ``B''. Macros are expanded as they are read, so +one normally quotes both values to prevent expansion. For example, + + define(`SMART_HOST', `smart.foo.com') One word of warning: M4 macros are expanded even in lines that appear to be comments. For example, if you have @@ -251,6 +280,7 @@ SMTP_MAILER_CHARSET [undefined] If defined, messages containing 8-bit data that ARRIVE from an address that resolves to one of the SMTP mailers and which are converted to MIME will be labelled with this character set. +UUCP_MAILER_PATH [/usr/bin/uux] The program used to send UUCP mail. UUCP_MAILER_FLAGS [undefined] Flags added to UUCP mailer. Default flags are `DFMhuU' (and `m' for uucp-new mailer, minus `U' for uucp-dom mailer). @@ -264,12 +294,16 @@ UUCP_MAILER_CHARSET [undefined] If defined, messages containing 8-bit data be labelled with this character set. FAX_MAILER_PATH [/usr/local/lib/fax/mailfax] The program used to submit FAX messages. +FAX_MAILER_ARGS [mailfax $u $h $f] The arguments passed to the FAX + mailer. FAX_MAILER_MAX [100000] The maximum size message accepted for transmission by FAX. POP_MAILER_PATH [/usr/lib/mh/spop] The pathname of the POP mailer. POP_MAILER_FLAGS [Penu] Flags added to POP mailer. Flags "lsDFM" are always added. POP_MAILER_ARGS [pop $u] The arguments passed to the POP mailer. +PROCMAIL_MAILER_PATH [/usr/local/bin/procmail] The path to the procmail + program. This is also used by FEATURE(local_procmail). PROCMAIL_MAILER_FLAGS [Shu] Flags added to Procmail mailer. Flags ``DFMmn'' are always set. PROCMAIL_MAILER_ARGS [procmail -m $h $f $u] The arguments passed to @@ -290,6 +324,10 @@ CYRUS_MAILER_PATH [/usr/cyrus/bin/deliver] The progam used to deliver cyrus mail. CYRUS_MAILER_ARGS [deliver -e -m $h -- $u] The arguments passed to deliver cyrus mail. +CYRUS_MAILER_MAX [undefined] If set, the maximum size message that + will be accepted by the cyrus mailer. +CYRUS_MAILER_USER [cyrus:mail] The user and group to become when + running the cyrus mailer. CYRUS_BB_MAILER_FLAGS [undefined] The flags used by the cyrusbb mailer. The flags lsDFMnP are always included. CYRUS_BB_MAILER_ARGS [deliver -e -m $u] The arguments passed @@ -549,8 +587,10 @@ uucpdomain Similar feature for UUCP hosts. The default map definition always_add_domain Include the local host domain even on locally delivered - mail. Normally it is not added unless it is already - present. + mail. Normally it is not added on unqualified names. + However, if you use a shared message store but do not use + the same user name space everywhere, you may need the host + name on local names. allmasquerade If masquerading is enabled (using MASQUERADE_AS), this feature will cause recipient addresses to also masquerade @@ -565,6 +605,73 @@ allmasquerade If masquerading is enabled (using MASQUERADE_AS), this namespace on your masquerade host supersets all the local entries. +limited_masquerade + Normally, any hosts listed in $=w are masqueraded. If this + feature is given, only the hosts listed in $=M are masqueraded. + This is useful if you have several domains with disjoint + namespaces hosted on the same machine. + +masquerade_entire_domain + If masquerading is enabled (using MASQUERADE_AS) and + MASQUERADE_DOMAIN (see below) is set, this feature will + cause addresses to be rewritten such that the masquerading + domains are actually entire domains to be hidden. All + hosts within the masquerading domains will be rewritten + to the masquerade name (used in MASQUERADE_AS). For example, + if you have: + + MASQUERADE_AS(masq.com) + MASQUERADE_DOMAIN(foo.org) + MASQUERADE_DOMAIN(bar.com) + + then *foo.org and *bar.com are converted to masq.com. Without + this feature, only foo.org and bar.com are masqueraded. + + NOTE: only domains within your jurisdiction and + current hierarchy should be masqueraded using this. + +genericstable This feature will cause certain addresses originating in the + local domain or a domain listed in $=G to be looked up in a + map and turned into another ("generic") form, which can change + both the domain name and the user name. This is similar to + the userdb functionality. The same types of addresses as for + masquerading are looked up, i.e. only header sender addresses + unless the allmasquerade and/or masquerade_envelope features + are given. The addresses must be in the list of names given + by the macros GENERICS_DOMAIN or GENERICS_DOMAIN_FILE + (analogously to MASQUERADE_DOMAIN and MASQUERADE_DOMAIN_FILE, + see below). + + The argument of FEATURE(genericstable) may be the map + defintion; the default map definition is: + + hash -o /etc/genericstable + + The key for this table is either the full address or the + unqualified username (the former is tried first); the + value is the new user address. If the new user address does + not include a domain, $j is used. + +virtusertable A domain-specific form of aliasing, allowing multiple + virtual domains to be hosted on one machine. For example, + if the virtuser table contained: + + info@foo.com foo-info + info@bar.com bar-info + @baz.org jane@elsewhere.net + + then mail addressed to info@foo.com will be sent to the + address foo-info, mail addressed to info@bar.com will be + delivered to bar-info, and mail addressed to anyone at + baz.org will be sent to jane@elsewhere.net. All the host + names on the left hand side (foo.com, bar.com, and baz.org) + must be in $=w. The default map definition is: + + hash -o /etc/virtusertable + + A new definition can be specified as the second argument of + the FEATURE macro. + nodns We aren't running DNS at our site (for example, we are UUCP-only connected). It's hard to consider this a "feature", but hey, it had to go somewhere. @@ -587,7 +694,7 @@ local_procmail Use procmail as the local mailer. This mailer can normally the +indicator is just tossed, but by default it is passed as the -a argument to procmail. The argument to this feature is the pathname of procmail, - which defaults to /usr/local/bin/procmail. + which defaults to PROCMAIL_MAILER_PATH. bestmx_is_local Accept mail as though locally addressed for any host that lists us as the best possible MX record. This generates @@ -834,14 +941,17 @@ You can have your host masquerade as another using MASQUERADE_AS(host.domain) -This causes outgoing SMTP mail to be labeled as coming from the -indicated domain, rather than $j. One normally masquerades as one -of one's own subdomains (for example, it's unlikely that I would -choose to masquerade as an MIT site). +This causes mail being sent to be labeled as coming from the +indicated host.domain, rather than $j. One normally masquerades as +one of one's own subdomains (for example, it's unlikely that I would +choose to masquerade as an MIT site). This behaviour is modified by +a plethora of FEATUREs; in particular, see masquerade_envelope, +allmasquerade, limited_masquerade, and masquerade_entire_domain. The masquerade name is not normally canonified, so it is important that it be your One True Name, that is, fully qualified and not a -CNAME. +CNAME. However, if you use a CNAME, the receiving side may canonify +it for you, so don't think you can cheat CNAME mapping this way. Normally the only addresses that are masqueraded are those that come from this host (that is, are either unqualified or in $=w, the list @@ -883,7 +993,7 @@ to have .forward files or aliases. You can do this using define(`LOCAL_RELAY', mailer:hostname) The ``mailer:'' can be omitted, in which case the mailer defaults to -"smtp". There are some user names that you don't want relayed, perhaps +"relay". There are some user names that you don't want relayed, perhaps because of local aliases. A common example is root, which may be locally aliased. You can add entries to this list using @@ -898,13 +1008,13 @@ shared /var/spool/mail scheme, use define(`MAIL_HUB', mailer:hostname) -Again, ``mailer:'' defaults to "smtp". If you define both LOCAL_RELAY +Again, ``mailer:'' defaults to "relay". If you define both LOCAL_RELAY and MAIL_HUB _AND_ you have FEATURE(stickyhost), unqualified names will be sent to the LOCAL_RELAY and other local names will be sent to MAIL_HUB. Names in $=L will be delivered locally, so you MUST have aliases or .forward files for them. -For example, if are on machine mastodon.CS.Berkeley.EDU and you have +For example, if you are on machine mastodon.CS.Berkeley.EDU and you have FEATURE(stickyhost), the following combinations of settings will have the indicated effects: @@ -936,6 +1046,12 @@ really want absolutely everything to go to a single central site you will need to unset all the other relays -- or better yet, find or build a minimal config file that does this. +For duplicate suppression to work properly, the host name is best +specified with a terminal dot: + + define(`MAIL_HUB', `host.domain.') + note the trailing dot ---^ + +-------------------------------+ | NON-SMTP BASED CONFIGURATIONS | @@ -1103,6 +1219,11 @@ Plussed users If that is not found, the alias "root+*" will be tried, then "root". +LDAP + For notes on use LDAP in sendmail, see + http://www-leland.stanford.edu/~bbense/Inst.html + + +----------------+ | SECURITY NOTES | @@ -1118,7 +1239,7 @@ for. In particular: version. * Make sure that other files that sendmail reads, such as the - mailertable, is only writable by trusted system personnel. + mailertable, are only writable by trusted system personnel. * The queue directory should not be world writable PARTICULARLY if your system allows "file giveaways" (that is, if a non-root @@ -1148,7 +1269,7 @@ Sam Leffler's FlexFAX software is still in beta test -- but he expects a public version out "later this week" [as of 3/1/93]. The following blurb is direct from Sam: - Header: /usr/people/sam/fax/RCS/HOWTO,v 1.14 93/05/24 11:42:16 sam Exp + $Header: /cvs/OpenBSD/src/usr.sbin/sendmail/cf/Attic/README,v 1.3 1996/12/14 21:15:15 downsj Exp $ How To Obtain This Software (in case all you get is this file) -------------------------------------------------------------- @@ -1319,7 +1440,7 @@ confTRUSTED_USERS Ct class [no default] Names of users to add to the list of trusted users. This list always includes root, uucp, and daemon. See also FEATURE(use_ct_file). -confSMTP_MAILER - [smtp] The mailer name used when +confSMTP_MAILER - [esmtp] The mailer name used when SMTP connectivity is required. One of "smtp", "smtp8", or "esmtp". confUUCP_MAILER - [uucp-old] The mailer to be used by @@ -1351,7 +1472,7 @@ confMIN_FREE_BLOCKS MinFreeBlocks [100] Minimum number of free blocks on for the second value now.) confMAX_MESSAGE_SIZE MaxMessageSize [infinite] The maximum size of messages that will be accepted (in bytes). -confBLANK_SUB BlankSub [ ] Blank (space) substitution +confBLANK_SUB BlankSub [.] Blank (space) substitution character. confCON_EXPENSIVE HoldExpensive [False] Avoid connecting immediately to mailers marked expensive? @@ -1383,6 +1504,17 @@ confMCI_CACHE_SIZE ConnectionCacheSize [2] Size of open connection cache. confMCI_CACHE_TIMEOUT ConnectionCacheTimeout [5m] Open connection cache timeout. +confHOST_STATUS_DIRECTORY HostStatusDirectory + [undefined] If set, host status is kept + on disk between sendmail runs in the + named directory tree. This need not be + a full pathname, in which case it is + interpreted relative to the queue + directory. This option also + single-threads connections to each + host, i.e., prevents multiple + connections to a single server from + this client. confUSE_ERRORS_TO* UserErrorsTo [False] Use the Errors-To: header to deliver error messages. This should not be necessary because of general @@ -1411,6 +1543,18 @@ confSAFE_QUEUE* SuperSafe [True] Commit all messages to disk before forking. confTO_INITIAL Timeout.initial [5m] The timeout waiting for a response on the initial connect. +confTO_CONNECT Timeout.connect [0] The timeout waiting for an initial + connect() to complete. This can only + shorten connection timeouts; the kernel + silently enforces an absolute maximum + (which varies depending on the system). +confTO_ICONNECT Timeout.iconnect + [undefined] Like Timeout.connect, but + applies only to the very first attempt + to connect to a host in a message. + This allows a single very fast pass + followed by more careful delivery + attempts in the future. confTO_HELO Timeout.helo [5m] The timeout waiting for a response to a HELO or EHLO command. confTO_MAIL Timeout.mail [10m] The timeout waiting for a @@ -1469,6 +1613,13 @@ confTO_QUEUEWARN_NONURGENT Timeout.queuewarn.non-urgent [undefined] As above, for non-urgent (low) priority messages. +confTO_HOSTSTATUS Timeout.hoststatus + [30m] How long information about host + statuses will be maintained before it + is considered stale and the host should + be retried. This applies both within + a single queue run and to persistent + information (see below). confTIME_ZONE TimeZoneSpec [USE_SYSTEM] Time zone info -- can be USE_SYSTEM to use the system's idea, USE_TZ to use the user's TZ envariable, @@ -1486,6 +1637,19 @@ confQUEUE_LA QueueLA [8] Load average at which queue-only function kicks in. confREFUSE_LA RefuseLA [12] Load average at which incoming SMTP connections are refused. +confMAX_DAEMON_CHILDREN MaxDaemonChildren + [undefined] The maximum number of + children the daemon will permit. After + this number, connections will be + rejected. If not set or <= 0, there is + no limit. +confCONNECTION_RATE_THROTTLE ConnectionRateThrottle + [undefined] The maximum number of + connections permitted per second. + After this many connections are + accepted, further connections will be + delayed. If not set or <= 0, there is + no limit. confWORK_RECIPIENT_FACTOR RecipientFactor [30000] Cost of each recipient. confSEPARATE_PROC ForkEachJob [False] Run all deliveries in a separate @@ -1585,6 +1749,39 @@ confDONT_INIT_GROUPS DontInitGroups [False] If set, the initgroups(3) this, agents run on behalf of users will only have their primary (/etc/passwd) group permissions. +confUNSAFE_GROUP_WRITES UnsafeGroupWrites + [False] If set, group-writable + :include: and .forward files are + considered "unsafe", that is, programs + and files cannot be directly referenced + from such files. World-writable files + are always considered unsafe. +confDOUBLE_BOUNCE_ADDRESS DoubleBounceAddress + [postmaster] If an error occurs when + sending an error message, send that + "double bounce" error message to this + address. +confRUN_AS_USER RunAsUser [undefined] If set, become this user + when reading and delivering mail. + Causes all file reads (e.g., .forward + and :include: files) to be done as + this user. Also, all programs will + be run as this user, and all output + files will be written as this user. + Intended for use only on firewalls + where users do not have accounts. +confSINGLE_THREAD_DELIVERY SingleThreadDelivery + [False] If this option and the + HostStatusDirectory option are both + set, single thread deliveries to other + hosts. That is, don't allow any two + sendmails on this host to connect + simultaneously to any other single + host. This can slow down delivery in + some cases, in particular since a + cached but otherwise idle connection + to a host will prevent other sendmails + from connecting to the other host. See also the description of OSTYPE for some parameters that can be tweaked (generally pathnames to mailers). @@ -1710,12 +1907,12 @@ MACROS CLASSES A - B + B domains that are candidates for bestmx lookup C D E addresses that should not seem to come from $M F hosts we forward for - G + G domains that should be looked up in genericstable H I J @@ -1736,6 +1933,7 @@ CLASSES Y locally connected smart UUCP hosts Z locally connected domain-ized UUCP hosts . the class containing only a dot + [ the class containing only a left bracket M4 DIVERSIONS diff --git a/usr.sbin/sendmail/cf/cf/clientproto.mc b/usr.sbin/sendmail/cf/cf/clientproto.mc index a59ac037e19..7cbb352c8fb 100644 --- a/usr.sbin/sendmail/cf/cf/clientproto.mc +++ b/usr.sbin/sendmail/cf/cf/clientproto.mc @@ -48,7 +48,8 @@ divert(-1) # Other than these, it should never contain any other lines. # -VERSIONID(`@(#)clientproto.mc 8.6 (Berkeley) 8/16/95') +divert(0)dnl +VERSIONID(`@(#)clientproto.mc 8.7 (Berkeley) 3/23/96') OSTYPE(unknown) FEATURE(nullclient, mailhost.$m) diff --git a/usr.sbin/sendmail/cf/cf/tcpproto.mc b/usr.sbin/sendmail/cf/cf/tcpproto.mc index 7f43558ca97..d023185ccbd 100644 --- a/usr.sbin/sendmail/cf/cf/tcpproto.mc +++ b/usr.sbin/sendmail/cf/cf/tcpproto.mc @@ -46,7 +46,8 @@ divert(-1) # will not trash your changes. # -VERSIONID(`@(#)tcpproto.mc 8.4 (Berkeley) 8/6/95') +divert(0)dnl +VERSIONID(`@(#)tcpproto.mc 8.5 (Berkeley) 3/23/96') OSTYPE(unknown) FEATURE(nouucp) MAILER(local) diff --git a/usr.sbin/sendmail/cf/cf/ucbarpa.mc b/usr.sbin/sendmail/cf/cf/ucbarpa.mc new file mode 100644 index 00000000000..5fe99d00476 --- /dev/null +++ b/usr.sbin/sendmail/cf/cf/ucbarpa.mc @@ -0,0 +1,51 @@ +divert(-1) +# +# Copyright (c) 1983 Eric P. Allman +# Copyright (c) 1988, 1993 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# +# This machine has been decommissioned at Berkeley, and hence should +# not be considered to be tested. This file is provided as an example +# only, of how you might set up a joint SMTP/UUCP configuration. At +# this point I recommend using `FEATURE(mailertable)' instead of +# `SITECONFIG'. See also ucbvax.mc. +# + +divert(0)dnl +VERSIONID(`@(#)ucbarpa.mc 8.4 (Berkeley) 3/23/96') +DOMAIN(CS.Berkeley.EDU)dnl +OSTYPE(bsd4.4)dnl +MAILER(local)dnl +MAILER(smtp)dnl +MAILER(uucp)dnl +SITECONFIG(uucp.ucbarpa, ucbarpa, U) diff --git a/usr.sbin/sendmail/cf/cf/ucbvax.mc b/usr.sbin/sendmail/cf/cf/ucbvax.mc new file mode 100644 index 00000000000..89a0f1014cd --- /dev/null +++ b/usr.sbin/sendmail/cf/cf/ucbvax.mc @@ -0,0 +1,112 @@ +divert(-1) +# +# Copyright (c) 1983 Eric P. Allman +# Copyright (c) 1988, 1993 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# +# This machine has been decommissioned at Berkeley, and hence should +# not be considered to be tested. This file is provided as an example +# only, of how you might set up a fairly complex configuration. +# Ucbvax was our main relay (both SMTP and UUCP) for many years. +# At this point I recommend using `FEATURE(mailertable)' instead of +# `SITECONFIG' for routing of UUCP within your domain. +# + +divert(0)dnl +VERSIONID(`@(#)ucbvax.mc 8.6 (Berkeley) 3/23/96') +OSTYPE(bsd4.3) +DOMAIN(CS.Berkeley.EDU) +MASQUERADE_AS(CS.Berkeley.EDU) +MAILER(local) +MAILER(smtp) +MAILER(uucp) +undefine(`UUCP_RELAY')dnl + +LOCAL_CONFIG +DDBerkeley.EDU + +# names for which we act as a local forwarding agent +CF CS +FF/etc/sendmail.cw + +# local UUCP connections, and our local uucp name +SITECONFIG(uucp.ucbvax, ucbvax, U) + +# remote UUCP connections, and the machine they are on +SITECONFIG(uucp.ucbarpa, ucbarpa.Berkeley.EDU, W) + +SITECONFIG(uucp.cogsci, cogsci.Berkeley.EDU, X) + +LOCAL_RULE_3 +# map old UUCP names into Internet names +UUCPSMTP(bellcore, bellcore.com) +UUCPSMTP(decvax, decvax.dec.com) +UUCPSMTP(decwrl, decwrl.dec.com) +UUCPSMTP(hplabs, hplabs.hp.com) +UUCPSMTP(lbl-csam, lbl-csam.arpa) +UUCPSMTP(pur-ee, ecn.purdue.edu) +UUCPSMTP(purdue, purdue.edu) +UUCPSMTP(research, research.att.com) +UUCPSMTP(sdcarl, sdcarl.ucsd.edu) +UUCPSMTP(sdcsvax, sdcsvax.ucsd.edu) +UUCPSMTP(ssyx, ssyx.ucsc.edu) +UUCPSMTP(sun, sun.com) +UUCPSMTP(ucdavis, ucdavis.ucdavis.edu) +UUCPSMTP(ucivax, ics.uci.edu) +UUCPSMTP(ucla-cs, cs.ucla.edu) +UUCPSMTP(ucla-se, seas.ucla.edu) +UUCPSMTP(ucsbcsl, ucsbcsl.ucsb.edu) +UUCPSMTP(ucscc, c.ucsc.edu) +UUCPSMTP(ucsd, ucsd.edu) +UUCPSMTP(ucsfcgl, cgl.ucsf.edu) +UUCPSMTP(unmvax, unmvax.cs.unm.edu) +UUCPSMTP(uwvax, spool.cs.wisc.edu) + +LOCAL_RULE_0 + +# make sure we handle the local domain as absolute +R$* < @ $* $D > $* $: $1 < @ $2 $D . > $3 + +# handle names we forward for as though they were local, so we will use UDB +R< @ $=F . $D . > : $* $@ $>7 $2 @here:... -> ... +R< @ $D . > : $* $@ $>7 $1 @here:... -> ... +R$* $=O $* < @ $=F . $D . > $@ $>7 $1 $2 $3 ...@here -> ... +R$* $=O $* < @ $D . > $@ $>7 $1 $2 $3 ...@here -> ... + +R$* < @ $=F . $D . > $#local $: $1 use UDB + +# handle local UUCP connections in the Berkeley.EDU domain +R$+<@cnmat.$D . > $#uucp$@cnmat$:$1 +R$+<@cnmat.CS.$D . > $#uucp$@cnmat$:$1 +R$+<@craig.$D . > $#uucp$@craig$:$1 +R$+<@craig.CS.$D . > $#uucp$@craig$:$1 diff --git a/usr.sbin/sendmail/cf/cf/uucpproto.mc b/usr.sbin/sendmail/cf/cf/uucpproto.mc index 49c4a0de656..6a21156ed52 100644 --- a/usr.sbin/sendmail/cf/cf/uucpproto.mc +++ b/usr.sbin/sendmail/cf/cf/uucpproto.mc @@ -46,7 +46,8 @@ divert(-1) # will not trash your changes. # -VERSIONID(`@(#)uucpproto.mc 8.5 (Berkeley) 8/6/95') +divert(0)dnl +VERSIONID(`@(#)uucpproto.mc 8.6 (Berkeley) 3/23/96') OSTYPE(unknown) FEATURE(nodns)dnl MAILER(local)dnl diff --git a/usr.sbin/sendmail/cf/domain/generic.m4 b/usr.sbin/sendmail/cf/domain/generic.m4 index 6799ff89522..ca91f50f112 100644 --- a/usr.sbin/sendmail/cf/domain/generic.m4 +++ b/usr.sbin/sendmail/cf/domain/generic.m4 @@ -41,8 +41,7 @@ divert(-1) # files. # divert(0) -VERSIONID(`@(#)generic.m4 8.2 (Berkeley) 4/21/95') +VERSIONID(`@(#)generic.m4 8.3 (Berkeley) 3/24/96') define(`confFORWARD_PATH', `$z/.forward.$w:$z/.forward')dnl -define(`confCW_FILE', `-o /etc/sendmail.cw')dnl FEATURE(redirect)dnl FEATURE(use_cw_file)dnl diff --git a/usr.sbin/sendmail/cf/feature/bestmx_is_local.m4 b/usr.sbin/sendmail/cf/feature/bestmx_is_local.m4 index 23dff8c93ee..1b96aa13f8d 100644 --- a/usr.sbin/sendmail/cf/feature/bestmx_is_local.m4 +++ b/usr.sbin/sendmail/cf/feature/bestmx_is_local.m4 @@ -34,12 +34,16 @@ divert(-1) # divert(0) -VERSIONID(`@(#)bestmx_is_local.m4 8.2 (Berkeley) 10/29/95') +VERSIONID(`@(#)bestmx_is_local.m4 8.4 (Berkeley) 10/23/96') divert(-1) LOCAL_CONFIG +# turn on bestMX lookup table Kbestmx bestmx +# limit bestmx to these domains +CB`'_ARG_ + LOCAL_NET_CONFIG # If we are the best MX for a site, then we want to accept @@ -50,9 +54,13 @@ LOCAL_NET_CONFIG # Warning: this may generate a lot of extra DNS traffic -- a # lower cost method is to list all the expected best MX hosts # in $=w. This should be fine (and easier to administer) for -# low to medium traffic hosts. +# low to medium traffic hosts. If you use the limited bestmx +# by passing in a set of possible domains it will improve things. +ifelse(_ARG_, `', `', `#')dnl unlimited bestmx R$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3 +ifelse(_ARG_, `', `#', `')dnl limit bestmx to $=B +R$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4 R$* $=O $* < @ $* @@ $=w . > $* $@ $>97 $1 $2 $3 R$* < @ $* @@ $=w . > $* $#local $: $1 R$* < @ $* @@ $* > $* $: $1 < @ $2 > $4 diff --git a/usr.sbin/sendmail/cf/feature/local_procmail.m4 b/usr.sbin/sendmail/cf/feature/local_procmail.m4 index 9087a690d08..db0cc87964c 100644 --- a/usr.sbin/sendmail/cf/feature/local_procmail.m4 +++ b/usr.sbin/sendmail/cf/feature/local_procmail.m4 @@ -34,11 +34,14 @@ divert(-1) # divert(0) -VERSIONID(`@(#)local_procmail.m4 8.3 (Berkeley) 10/29/95') +VERSIONID(`@(#)local_procmail.m4 8.6 (Berkeley) 10/20/96') divert(-1) -define(`PROCMAIL_PATH', - ifelse(_ARG_, `', `/usr/local/bin/procmail', `_ARG_')) -define(`LOCAL_MAILER_FLAGS', `SPfhn') -define(`LOCAL_MAILER_PATH', PROCMAIL_PATH) +define(`LOCAL_MAILER_PATH', + ifelse(_ARG_, `', + ifdef(`PROCMAIL_MAILER_PATH', + PROCMAIL_MAILER_PATH, + `/usr/local/bin/procmail'), + _ARG_)) +define(`LOCAL_MAILER_FLAGS', `SPfhn9') define(`LOCAL_MAILER_ARGS', `procmail -Y -a $h -d $u') diff --git a/usr.sbin/sendmail/cf/feature/nullclient.m4 b/usr.sbin/sendmail/cf/feature/nullclient.m4 index 7543070f77f..6eaa8c1aeca 100644 --- a/usr.sbin/sendmail/cf/feature/nullclient.m4 +++ b/usr.sbin/sendmail/cf/feature/nullclient.m4 @@ -45,7 +45,7 @@ POPDIVERT # sendmail. # -VERSIONID(`@(#)nullclient.m4 8.6 (Berkeley) 6/29/95') +VERSIONID(`@(#)nullclient.m4 8.7 (Berkeley) 2/11/96') PUSHDIVERT(6) # hub host (to which all mail is sent) @@ -65,7 +65,8 @@ ifdef(`confRELAY_MAILER',, `define(`confRELAY_MAILER', `nullclient')')dnl ifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', <$g>)')dnl +ifdef(`SMTP_MAILER_ARGS',, `define(`SMTP_MAILER_ARGS', `IPC $h')')dnl Mnullclient, P=[IPC], F=CONCAT(mDFMuXa, SMTP_MAILER_FLAGS),ifdef(`SMTP_MAILER_MAX', ` M=SMTP_MAILER_MAX,') - A=IPC $h + A=SMTP_MAILER_ARGS POPDIVERT diff --git a/usr.sbin/sendmail/cf/feature/redirect.m4 b/usr.sbin/sendmail/cf/feature/redirect.m4 index 081db113ae0..27f23576535 100644 --- a/usr.sbin/sendmail/cf/feature/redirect.m4 +++ b/usr.sbin/sendmail/cf/feature/redirect.m4 @@ -34,7 +34,7 @@ divert(-1) # divert(0) -VERSIONID(`@(#)redirect.m4 8.4 (Berkeley) 6/25/95') +VERSIONID(`@(#)redirect.m4 8.5 (Berkeley) 8/17/96') divert(-1) @@ -42,7 +42,7 @@ PUSHDIVERT(3) # addresses sent to foo@host.REDIRECT will give a 551 error code R$* < @ $+ .REDIRECT. > $: $1 < @ $2 . REDIRECT . > < ${opMode} > R$* < @ $+ .REDIRECT. > <i> $: $1 < @ $2 . REDIRECT. > -R$* < @ $+ .REDIRECT. > < $- > $# error $@ 5.1.1 $: "551 User not local; please try " <$1@$2> +R$* < @ $+ .REDIRECT. > < $- > $# error $@ 5.1.1 $: "551 User has moved; please try " <$1@$2> POPDIVERT PUSHDIVERT(6) diff --git a/usr.sbin/sendmail/cf/m4/cfhead.m4 b/usr.sbin/sendmail/cf/m4/cfhead.m4 index 46605e7e34c..91d4b9ad456 100644 --- a/usr.sbin/sendmail/cf/m4/cfhead.m4 +++ b/usr.sbin/sendmail/cf/m4/cfhead.m4 @@ -86,8 +86,13 @@ define(`LOCAL_RULE_2', S2 ') +define(`LOCAL_RULESETS', +`divert(9) + +') define(`LOCAL_RULE_3', `divert(2)') define(`LOCAL_CONFIG', `divert(6)') +define(`MAILER_DEFINITIONS', `divert(7)') define(`LOCAL_NET_CONFIG', `define(`_LOCAL_RULES_', 1)divert(1)') define(`UUCPSMTP', `R DOL(*) < @ $1 .UUCP > DOL(*) DOL(1) < @ $2 > DOL(2)') define(`CONCAT', `$1$2$3$4$5$6$7') @@ -109,16 +114,23 @@ define(`MASQUERADE_DOMAIN', `PUSHDIVERT(5)CM$1 POPDIVERT`'dnl') define(`MASQUERADE_DOMAIN_FILE', `PUSHDIVERT(5)FM$1 POPDIVERT`'dnl') +define(`GENERICS_DOMAIN', `PUSHDIVERT(5)CG$1 +POPDIVERT`'dnl') +define(`GENERICS_DOMAIN_FILE', `PUSHDIVERT(5)FG$1 +POPDIVERT`'dnl') define(`_OPTINS', `ifdef(`$1', `$2$1$3')') m4wrap(`include(_CF_DIR_`m4/proto.m4')') # set up default values for options +define(`ALIAS_FILE', `/etc/aliases') define(`confMAILER_NAME', ``MAILER-DAEMON'') define(`confFROM_LINE', `From $g $d') define(`confOPERATORS', `.:%@!^/[]+') define(`confSMTP_LOGIN_MSG', `$j Sendmail $v/$Z; $b') -define(`confRECEIVED_HEADER', `$?sfrom $s $.$?_($?s$|from $.$_) $.by $j ($v/$Z)$?r with $r$. id $i$?u for $u$.; $b') +define(`confRECEIVED_HEADER', `$?sfrom $s $.$?_($?s$|from $.$_) + $.by $j ($v/$Z)$?r with $r$. + id $i$?u for $u$.; $b') define(`confSEVEN_BIT_INPUT', `False') define(`confEIGHT_BIT_HANDLING', `pass8') define(`confALIAS_WAIT', `10') @@ -144,4 +156,4 @@ define(`confMIME_FORMAT_ERRORS', `True') define(`confFORWARD_PATH', `$z/.forward.$w:$z/.forward') divert(0)dnl -VERSIONID(`@(#)cfhead.m4 8.3 (Berkeley) 9/15/95') +VERSIONID(`@(#)cfhead.m4 8.7 (Berkeley) 11/20/96') diff --git a/usr.sbin/sendmail/cf/m4/nullrelay.m4 b/usr.sbin/sendmail/cf/m4/nullrelay.m4 index 799f3ab7919..86c0356e2c5 100644 --- a/usr.sbin/sendmail/cf/m4/nullrelay.m4 +++ b/usr.sbin/sendmail/cf/m4/nullrelay.m4 @@ -34,7 +34,7 @@ divert(-1) # divert(0) -VERSIONID(`@(#)nullrelay.m4 8.10 (Berkeley) 9/29/95') +VERSIONID(`@(#)nullrelay.m4 8.12 (Berkeley) 10/12/96') # # This configuration applies only to relay-only hosts. They send @@ -74,25 +74,30 @@ R$* ; $: $1 strip trailing semi R$@ $@ :; <@> # basic textual canonicalization -- note RFC733 heuristic here -R$*<$*>$*<$*>$* $2$3<$4>$5 strip multiple <> <> -R$*<$*<$+>$*>$* <$3>$5 2-level <> nesting -R$*<>$* $@ <@> MAIL FROM:<> case -R$*<$+>$* $2 basic RFC821/822 parsing +R$* $: < $1 > housekeeping <> +R$+ < $* > < $2 > strip excess on left +R< $* > $+ < $1 > strip excess on right +R<> $@ < @ > MAIL FROM:<> case +R< $+ > $: $1 remove housekeeping <> ifdef(`_NO_CANONIFY_', `dnl', `# eliminate local host if present R@ $=w $=: $+ $@ @ $M $2 $3 @thishost ... R@ $+ $@ @ $1 @somewhere ... +R$=E @ $=w $@ $1 @ $2 leave exposed R$+ @ $=w $@ $1 @ $M ...@thishost R$+ @ $+ $@ $1 @ $2 ...@somewhere +R$=w ! $=E $@ $2 @ $1 leave exposed R$=w ! $+ $@ $2 @ $M thishost!... R$+ ! $+ $@ $1 ! $2 @ $M somewhere ! ... +R$=E % $=w $@ $1 @ $2 leave exposed R$+ % $=w $@ $1 @ $M ...%thishost R$+ % $+ $@ $1 @ $2 ...%somewhere +R$=E $@ $1 @ $j leave exposed R$+ $@ $1 @ $M unadorned user') diff --git a/usr.sbin/sendmail/cf/m4/proto.m4 b/usr.sbin/sendmail/cf/m4/proto.m4 index 89b3215e5ce..676aa35ca58 100644 --- a/usr.sbin/sendmail/cf/m4/proto.m4 +++ b/usr.sbin/sendmail/cf/m4/proto.m4 @@ -34,12 +34,12 @@ divert(-1) # divert(0) -VERSIONID(`@(#)proto.m4 8.100 (Berkeley) 12/3/95') +VERSIONID(`@(#)proto.m4 8.136 (Berkeley) 11/24/96') MAILER(local)dnl -# level 6 config file format -V6/Berkeley +# level 7 config file format +V7/Berkeley divert(-1) # do some sanity checking @@ -47,7 +47,7 @@ ifdef(`__OSTYPE__',, `errprint(`*** ERROR: No system type defined (use OSTYPE macro)')') # pick our default mailers -ifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `smtp')') +ifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')') ifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')') ifdef(`confRELAY_MAILER',, `define(`confRELAY_MAILER', @@ -94,7 +94,7 @@ Fw`'confCW_FILE', `dnl') # my official domain name -# ... define this only if sendmail cannot automatically determine your domain +# ... `define' this only if sendmail cannot automatically determine your domain ifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') ifdef(`_NULL_CLIENT_ONLY_', `divert(-1)')dnl @@ -142,6 +142,9 @@ CO @ % ifdef(`_NO_UUCP_', `', `!') # a class with just dot (for identifying canonical names) C.. +# a class with just a left bracket (for identifying domain literals) +C[[ + # Mailer table (overriding domains) ifdef(`MAILER_TABLE', `Kmailertable MAILER_TABLE', @@ -152,6 +155,16 @@ ifdef(`DOMAIN_TABLE', `Kdomaintable DOMAIN_TABLE', `#Kdomaintable dbm /etc/domaintable') +# Generics table (mapping outgoing addresses) +ifdef(`GENERICS_TABLE', + `Kgenerics GENERICS_TABLE', + `#Kgenerics dbm /etc/genericstable') + +# Virtual user table (maps incoming users) +ifdef(`VIRTUSER_TABLE', + `Kvirtuser VIRTUSER_TABLE', + `#Kvirtuser dbm /etc/virtusertable') + # who I send unqualified names to (null means deliver locally) DR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY) @@ -193,7 +206,7 @@ ifdef(`_NULL_CLIENT_ONLY_', `dnl', ` _OPTION(AliasWait, `confALIAS_WAIT', 5m) # location of alias file -O AliasFile=ifdef(`ALIAS_FILE', `ALIAS_FILE', /etc/aliases) +_OPTION(AliasFile, `ALIAS_FILE', /etc/aliases) ') # minimum number of free blocks on filesystem _OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', 100) @@ -255,6 +268,12 @@ _OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', 2) # open connection cache timeout _OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', 5m) +# persistent host status directory +_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', .hoststat) + +# single thread deliveries (requires HostStatusDirectory)? +_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY') + # use Errors-To: header? _OPTION(UseErrorsTo, `confUSE_ERRORS_TO') @@ -287,6 +306,8 @@ O QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, /var/spool/mqueue) # timeouts (many of these) _OPTION(Timeout.initial, `confTO_INITIAL', 5m) +_OPTION(Timeout.connect, `confTO_CONNECT', 5m) +_OPTION(Timeout.iconnect, `confTO_ICONNECT', 5m) _OPTION(Timeout.helo, `confTO_HELO', 5m) _OPTION(Timeout.mail, `confTO_MAIL', 10m) _OPTION(Timeout.rcpt, `confTO_RCPT', 1h) @@ -307,6 +328,7 @@ _OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', 4h) _OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', 4h) _OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', 1h) _OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', 12h) +_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', 30m) # should we not prune routes in route-addr syntax addresses? _OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES') @@ -343,6 +365,12 @@ _OPTION(QueueLA, `confQUEUE_LA', 8) # load average at which we refuse connections _OPTION(RefuseLA, `confREFUSE_LA', 12) +# maximum number of children we allow at one time +_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', 12) + +# maximum number of new connections per second +_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', 3) + # work recipient factor _OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', 30000) @@ -400,6 +428,15 @@ _OPTION(OperatorChars, `confOPERATORS') # shall I avoid calling initgroups(3) because of high NIS costs? _OPTION(DontInitGroups, `confDONT_INIT_GROUPS') +# are group-writable `:include:' and .forward files (un)trustworthy? +_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES') + +# where do errors that occur when sending errors get sent? +_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS') + +# what user id do we assume for the majority of the processing? +_OPTION(RunAsUser, `confRUN_AS_USER', sendmail) + ########################### # Message precedences # ########################### @@ -418,7 +455,7 @@ Pjunk=-100 ifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `/etc/sendmail.ct') Troot Tdaemon -Tuucp +ifdef(`_NO_UUCP_', `dnl', `Tuucp') ifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') ######################### @@ -426,14 +463,13 @@ ifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') ######################### ifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl -H?P?Return-Path: $g +H?P?Return-Path: <$g> HReceived: confRECEIVED_HEADER H?D?Resent-Date: $a H?D?Date: $a H?F?Resent-From: confFROM_HEADER H?F?From: confFROM_HEADER H?x?Full-Name: $x -HSubject: # HPosted-Date: $a # H?l?Received-Date: $b H?M?Resent-Message-Id: <$t.$i@$j> @@ -450,11 +486,9 @@ ifdef(`_NULL_CLIENT_ONLY_', ###################################################################### ###################################################################### -undivert(9)dnl - -########################################### -### Rulset 3 -- Name Canonicalization ### -########################################### +############################################ +### Ruleset 3 -- Name Canonicalization ### +############################################ S3 # handle null input (translate to <@> special case) @@ -463,8 +497,11 @@ R$@ $@ <@> # strip group: syntax (not inside angle brackets!) and trailing semicolon R$* $: $1 <@> mark addresses R$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> +R@ $* <@> $: @ $1 unmark @host:... R$* :: $* <@> $: $1 :: $2 unmark node::addr R:`include': $* <@> $: :`include': $1 unmark :`include':... +R$* [ $* : $* ] <@> $: $1 [ $2 : $3 ] unmark IPv6 addrs +R$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon R$* : $* <@> $: $2 strip colon if marked R$* <@> $: $1 unmark R$* ; $: $1 strip trailing semi @@ -559,18 +596,17 @@ ifdef(`_CLASS_Y_', R$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 R$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') ') -ifdef(`_NO_CANONIFY_', `dnl', -`# pass to name server to make hostname canonical -R$* < @ $* $~P > $* $: $1 < @ $[ $2 $3 $] > $4') +# pass to name server to make hostname canonical +ifdef(`_NO_CANONIFY_', `#')dnl +R$* < @ $* $~P > $* $: $1 < @ $[ $2 $3 $] > $4 # local host aliases and pseudo-domains are always canonical R$* < @ $=w > $* $: $1 < @ $2 . > $3 +R$* < @ $j > $* $: $1 < @ $j . > $2 +R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4 R$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 R$* < @ $* . . > $* $1 < @ $2 . > $3 -# if this is the local hostname, make sure we treat is as canonical -R$* < @ $j > $* $: $1 < @ $j . > $2 - ################################################## ### Ruleset 4 -- Final Output Post-rewriting ### @@ -599,7 +635,7 @@ ifdef(`_USE_DECNET_SYNTAX_', R$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', `dnl') # delete duplicate local names -R$+ % $=w @ $=w $1 @ $j u%host@host => u@host +R$+ % $=w @ $=w $1 @ $2 u%host@host => u@host @@ -622,8 +658,11 @@ S0 R<@> $#_LOCAL_ $: <@> special case error msgs R$* : $* ; <@> $#error $@ 5.1.3 $: "list:; syntax illegal for recipient addresses" R<@ $+> $#error $@ 5.1.1 $: "user address required" -R$* <$* : $* > $* $#error $@ 5.1.1 $: "colon illegal in host name part" -R$* < @ . > $* $#error $@ 5.1.2 $: "invalid host name" +R$* $: <> $1 +R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 +R<> $* <$* : $* > $* $#error $@ 5.1.1 $: "colon illegal in host name part" +R<> $* $1 +R$* < @ . $* > $* $#error $@ 5.1.2 $: "invalid host name" ifdef(`_MAILER_smtp_', `# handle numeric address spec @@ -635,15 +674,24 @@ R$* < @ [ $+ ] > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 still numeric: send', R$* < @ > $* $@ $>97 $1 user@ => user R< @ $=w . > : $* $@ $>97 $2 @here:... -> ... R$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here +R< @ $+ > $#error $@ 5.1.1 $: "user address required" R$* $=O $* < @ $=w . > $@ $>97 $1 $2 $3 ...@here -> ... # handle local hacks R$* $: $>98 $1 +# handle virtual users +define(`X', ifdef(`VIRTUSER_TABLE', `', `#'))dnl +X`'R$+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > +X`'R< @ > $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > +X`'R< @ > $+ $: $1 +X`'R< error : $- $+ > $* $#error $@ $1 $: $2 +X`'R< $+ > $+ < @ $+ > $: $>97 $1 +undefine(`X')dnl + # short circuit local delivery so forwarded email works -ifdef(`_MAILER_usenet_', -`R$+ . USENET < @ $=w . > $#usenet $: $1 handle usenet specially', - `dnl') +ifdef(`_MAILER_usenet_', `', `#')dnl +R$+ . USENET < @ $=w . > $#usenet $: $1 handle usenet specially ifdef(`_STICKY_LOCAL_DOMAIN_', `R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub R< $+ > $+ < $+ > $>95 < $1 > $2 < $3 > yep .... @@ -657,8 +705,7 @@ define(`X', ifdef(`MAILER_TABLE', `', `#'))dnl X`'R$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name X`'R< $+ . > $* $: < $1 > $2 strip trailing dot X`'R< $+ > $* $: < $(mailertable $1 $) > $2 lookup -X`'R< error : $- $+ > $* $#error $@ $1 $: $2 check -- error? -X`'R< $- : $+ > $* $# $1 $@ $2 $: $3 check -- resolved? +X`'R< $~[ : $+ > $* $>95 < $1 : $2 > $3 check -- resolved? X`'R< $+ > $* $: $>90 <$1> $2 try domain undefine(`X')dnl undivert(4)dnl @@ -759,40 +806,63 @@ R< $+ > $+ $@ $>95 < $1 > $2 < @ $1 > ################################################################### define(`X', ifdef(`MAILER_TABLE', `', `#'))dnl -X`'S90 +S90 X`'R$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 -X`'R$* <$- : $+ > $* $# $2 $@ $3 $: $4 check -- resolved? -X`'R$* < . $+ > $* $@ $>90 $1 . <$2> $3 no -- strip & try again +X`'R$* <$~[ : $+ > $* $>95 < $2 : $3 > $4 check -- resolved? +X`'R$* < . $+ > $* $@ $>90 $1 . <$2> $3 no -- strip & try again X`'R$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." -X`'R<$- : $+ > $* $# $1 $@ $2 $: $3 "." found? -X`'R< $* > $* $@ $2 no mailertable match +X`'R< $~[ : $+ > $* $>95 < $1 : $2 > $3 "." found? +X`'R< $* > $* $@ $2 no mailertable match undefine(`X')dnl ################################################################### -### Ruleset 95 -- canonify mailer:host syntax to triple ### +### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### ################################################################### S95 -R< > $* $@ $1 strip off null relay -R< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer -R< $=w > $* $@ $2 delete local host -R< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer +R< > $* $@ $1 strip off null relay +R< error : $- $+ > $* $#error $@ $1 $: $2 special case errors +R< local : > $* < @ $* > $#local $@ $1@$2 $: $1 no host: use old user +R< local : $+ > $* <@ $* . > $* $#local $@ $2@$3 $: $1 special case local +R< $- : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user +R< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer +R< $=w > $* $@ $2 delete local host +R< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer ################################################################### ### Ruleset 93 -- convert header names to masqueraded form ### ################################################################### S93 + +# handle generics database +define(`X', ifdef(`GENERICS_TABLE', `', `#'))dnl +X`'R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark +X`'R$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark +X`'R< $+ > $+ < $* > @ $: < $(generics $1 $: $) > $2 < $3 > +X`'R< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > +X`'R< $* @ $* > $* < $* > $@ $>3 $1 @ $2 found qualified +X`'R< $+ > $* < $* > $: $>3 $1 @ *LOCAL* found unqualified +X`'R< > $* $: $1 not found +undefine(`X')dnl + +# special case the users that should be exposed R$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed -R$=E < @ $=M . > $@ $1 < @ $2 . > +ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', +`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', +`R$=E < @ $=M . > $@ $1 < @ $2 . >') ifdef(`_LIMITED_MASQUERADE_', `#')dnl R$=E < @ $=w . > $@ $1 < @ $2 . > -R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms + +# handle domain-specific masquerading +ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', +`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', +`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') ifdef(`_LIMITED_MASQUERADE_', `#')dnl R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3 R$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 -R$* < @ $+ @ > $* $@ $1 < @ $2 > $3 $M is null -R$* < @ $+ @ $+ > $* $@ $1 < @ $3 . > $4 $M is not null +R$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null +R$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null ################################################################### ### Ruleset 94 -- convert envelope names to masqueraded form ### @@ -810,6 +880,7 @@ R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2 S98 undivert(3)dnl +undivert(9)dnl # ###################################################################### ###################################################################### diff --git a/usr.sbin/sendmail/cf/m4/version.m4 b/usr.sbin/sendmail/cf/m4/version.m4 index fb8e96e144f..b3ee9a7bc6e 100644 --- a/usr.sbin/sendmail/cf/m4/version.m4 +++ b/usr.sbin/sendmail/cf/m4/version.m4 @@ -32,8 +32,8 @@ divert(-1) # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -VERSIONID(`@(#)version.m4 8.7.3.1 (Berkeley) 12/3/95') +VERSIONID(`@(#)version.m4 8.8.4.2 (Berkeley) 11/26/96') # divert(0) # Configuration version number -DZ8.7.3`'ifdef(`confCF_VERSION', `/confCF_VERSION') +DZ8.8.4`'ifdef(`confCF_VERSION', `/confCF_VERSION') diff --git a/usr.sbin/sendmail/cf/mailer/cyrus.m4 b/usr.sbin/sendmail/cf/mailer/cyrus.m4 index f5311371b53..47a4a5afd6a 100644 --- a/usr.sbin/sendmail/cf/mailer/cyrus.m4 +++ b/usr.sbin/sendmail/cf/mailer/cyrus.m4 @@ -26,6 +26,7 @@ PUSHDIVERT(-1) ifdef(`CYRUS_MAILER_FLAGS',, `define(`CYRUS_MAILER_FLAGS', `A5@')') ifdef(`CYRUS_MAILER_PATH',, `define(`CYRUS_MAILER_PATH', /usr/cyrus/bin/deliver)') ifdef(`CYRUS_MAILER_ARGS',, `define(`CYRUS_MAILER_ARGS', `deliver -e -m $h -- $u')') +ifdef(`CYRUS_MAILER_USER',, `define(`CYRUS_MAILER_USER', `cyrus:mail')') ifdef(`CYRUS_BB_MAILER_FLAGS',, `define(`CYRUS_BB_MAILER_FLAGS', `')') ifdef(`CYRUS_BB_MAILER_ARGS',, `define(`CYRUS_BB_MAILER_ARGS', `deliver -e -m $u')') @@ -35,10 +36,12 @@ POPDIVERT ### Cyrus Mailer specification ### ################################################## -VERSIONID(`@(#)cyrus.m4 8.2 (Carnegie Mellon) 9/12/95') +VERSIONID(`@(#)cyrus.m4 8.4 (Carnegie Mellon) 9/2/96') -Mcyrus, P=CYRUS_MAILER_PATH, F=CONCAT(`lsDFMnP', CYRUS_MAILER_FLAGS), S=10, R=20/40, T=X-Unix, - ifdef(`CYRUS_MAILER_MAX', `M=CYRUS_MAILER_MAX, ')A=CYRUS_MAILER_ARGS +Mcyrus, P=CYRUS_MAILER_PATH, F=CONCAT(`lsDFMnPq', CYRUS_MAILER_FLAGS), S=10, R=20/40, T=X-Unix, + ifdef(`CYRUS_MAILER_MAX', `M=CYRUS_MAILER_MAX, ')U=CYRUS_MAILER_USER, + A=CYRUS_MAILER_ARGS -Mcyrusbb, P=CYRUS_MAILER_PATH, F=CONCAT(`lsDFMnP', CYRUS_MAILER_FLAGS), S=10, R=20/40, T=X-Unix, - ifdef(`CYRUS_MAILER_MAX', `M=CYRUS_MAILER_MAX, ')A=CYRUS_BB_MAILER_ARGS +Mcyrusbb, P=CYRUS_MAILER_PATH, F=CONCAT(`lsDFMnP', CYRUS_BB_MAILER_FLAGS), S=10, R=20/40, T=X-Unix, + ifdef(`CYRUS_MAILER_MAX', `M=CYRUS_MAILER_MAX, ')U=CYRUS_MAILER_USER, + A=CYRUS_BB_MAILER_ARGS diff --git a/usr.sbin/sendmail/cf/mailer/fax.m4 b/usr.sbin/sendmail/cf/mailer/fax.m4 index 777fe01cf36..726c83a2dce 100644 --- a/usr.sbin/sendmail/cf/mailer/fax.m4 +++ b/usr.sbin/sendmail/cf/mailer/fax.m4 @@ -35,6 +35,8 @@ PUSHDIVERT(-1) # SUCH DAMAGE. # +ifdef(`FAX_MAILER_ARGS',, + `define(`FAX_MAILER_ARGS', mailfax $u $h $f)') ifdef(`FAX_MAILER_PATH',, `define(`FAX_MAILER_PATH', /usr/local/lib/fax/mailfax)') ifdef(`FAX_MAILER_MAX',, @@ -44,10 +46,10 @@ POPDIVERT ### FAX Mailer specification ### #################################### -VERSIONID(`@(#)fax.m4 8.4 (Berkeley) 10/10/95') +VERSIONID(`@(#)fax.m4 8.5 (Berkeley) 5/10/96') Mfax, P=FAX_MAILER_PATH, F=DFMhu, S=14, R=24, M=FAX_MAILER_MAX, T=X-Phone/X-FAX/X-Unix, - A=mailfax $u $h $f + A=FAX_MAILER_ARGS LOCAL_CONFIG CPFAX diff --git a/usr.sbin/sendmail/cf/mailer/local.m4 b/usr.sbin/sendmail/cf/mailer/local.m4 index 124cbba7528..998778a0d0c 100644 --- a/usr.sbin/sendmail/cf/mailer/local.m4 +++ b/usr.sbin/sendmail/cf/mailer/local.m4 @@ -32,10 +32,10 @@ PUSHDIVERT(-1) # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -ifdef(`LOCAL_MAILER_FLAGS',, `define(`LOCAL_MAILER_FLAGS', `rmn')') +ifdef(`LOCAL_MAILER_FLAGS',, `define(`LOCAL_MAILER_FLAGS', `rmn9')') ifdef(`LOCAL_MAILER_PATH',, `define(`LOCAL_MAILER_PATH', /bin/mail)') ifdef(`LOCAL_MAILER_ARGS',, `define(`LOCAL_MAILER_ARGS', `mail -d $u')') -ifdef(`LOCAL_SHELL_FLAGS',, `define(`LOCAL_SHELL_FLAGS', `eu')') +ifdef(`LOCAL_SHELL_FLAGS',, `define(`LOCAL_SHELL_FLAGS', `eu9')') ifdef(`LOCAL_SHELL_PATH',, `define(`LOCAL_SHELL_PATH', /bin/sh)') ifdef(`LOCAL_SHELL_ARGS',, `define(`LOCAL_SHELL_ARGS', `sh -c $u')') ifdef(`LOCAL_SHELL_DIR',, `define(`LOCAL_SHELL_DIR', `$z:/')') @@ -45,12 +45,12 @@ POPDIVERT ### Local and Program Mailer specification ### ################################################## -VERSIONID(`@(#)local.m4 8.21 (Berkeley) 11/6/95') +VERSIONID(`@(#)local.m4 8.23 (Berkeley) 5/31/96') -Mlocal, P=LOCAL_MAILER_PATH, F=CONCAT(`lsDFMAw5:/|@', LOCAL_MAILER_FLAGS), S=10/30, R=20/40, +Mlocal, P=LOCAL_MAILER_PATH, F=CONCAT(`lsDFMAw5:/|@q', LOCAL_MAILER_FLAGS), S=10/30, R=20/40, _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')_OPTINS(`LOCAL_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/X-Unix, A=LOCAL_MAILER_ARGS -Mprog, P=LOCAL_SHELL_PATH, F=CONCAT(`lsDFMo', LOCAL_SHELL_FLAGS), S=10/30, R=20/40, D=LOCAL_SHELL_DIR, +Mprog, P=LOCAL_SHELL_PATH, F=CONCAT(`lsDFMoq', LOCAL_SHELL_FLAGS), S=10/30, R=20/40, D=LOCAL_SHELL_DIR, _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')T=X-Unix, A=LOCAL_SHELL_ARGS diff --git a/usr.sbin/sendmail/cf/mailer/pop.m4 b/usr.sbin/sendmail/cf/mailer/pop.m4 index 210a3c83a6f..7e8ec0d2293 100644 --- a/usr.sbin/sendmail/cf/mailer/pop.m4 +++ b/usr.sbin/sendmail/cf/mailer/pop.m4 @@ -43,9 +43,9 @@ POPDIVERT ### POP Mailer specification ### #################################### -VERSIONID(`@(#)pop.m4 8.5 (Berkeley) 4/23/95') +VERSIONID(`@(#)pop.m4 8.6 (Berkeley) 2/12/96') -Mpop, P=POP_MAILER_PATH, F=CONCAT(`lsDFM', POP_MAILER_FLAGS), S=10, R=20/40, T=DNS/RFC822/X-Unix, +Mpop, P=POP_MAILER_PATH, F=CONCAT(`lsDFMq', POP_MAILER_FLAGS), S=10, R=20/40, T=DNS/RFC822/X-Unix, A=POP_MAILER_ARGS LOCAL_CONFIG diff --git a/usr.sbin/sendmail/cf/mailer/procmail.m4 b/usr.sbin/sendmail/cf/mailer/procmail.m4 index d1293b9ceff..a170e58a471 100644 --- a/usr.sbin/sendmail/cf/mailer/procmail.m4 +++ b/usr.sbin/sendmail/cf/mailer/procmail.m4 @@ -33,8 +33,10 @@ PUSHDIVERT(-1) # SUCH DAMAGE. # -ifdef(`PROCMAIL_PATH',, - `define(`PROCMAIL_PATH', /usr/local/bin/procmail)') +ifdef(`PROCMAIL_MAILER_PATH',, + `ifdef(`PROCMAIL_PATH', + `define(`PROCMAIL_MAILER_PATH', PROCMAIL_PATH)', + `define(`PROCMAIL_MAILER_PATH', /usr/local/bin/procmail)')') ifdef(`PROCMAIL_MAILER_FLAGS',, `define(`PROCMAIL_MAILER_FLAGS', `Shu')') ifdef(`PROCMAIL_MAILER_ARGS',, @@ -46,7 +48,7 @@ POPDIVERT ### PROCMAIL Mailer specification ### ##################*****################## -VERSIONID(`@(#)procmail.m4 8.4 (Berkeley) 4/23/95') +VERSIONID(`@(#)procmail.m4 8.5 (Berkeley) 12/28/95') -Mprocmail, P=PROCMAIL_PATH, F=CONCAT(`DFMm', PROCMAIL_MAILER_FLAGS), S=11/31, R=21/31, T=DNS/RFC822/X-Unix, +Mprocmail, P=PROCMAIL_MAILER_PATH, F=CONCAT(`DFMm', PROCMAIL_MAILER_FLAGS), S=11/31, R=21/31, T=DNS/RFC822/X-Unix, ifdef(`PROCMAIL_MAILER_MAX', `M=PROCMAIL_MAILER_MAX, ')A=PROCMAIL_MAILER_ARGS diff --git a/usr.sbin/sendmail/cf/mailer/smtp.m4 b/usr.sbin/sendmail/cf/mailer/smtp.m4 index 6b59574e61e..c816c736001 100644 --- a/usr.sbin/sendmail/cf/mailer/smtp.m4 +++ b/usr.sbin/sendmail/cf/mailer/smtp.m4 @@ -44,7 +44,7 @@ POPDIVERT ### SMTP Mailer specification ### ##################################### -VERSIONID(`@(#)smtp.m4 8.32 (Berkeley) 11/20/95') +VERSIONID(`@(#)smtp.m4 8.33 (Berkeley) 7/9/96') Msmtp, P=[IPC], F=CONCAT(mDFMuX, SMTP_MAILER_FLAGS), S=11/31, R=ifdef(`_ALL_MASQUERADE_', `21/31', `21'), E=\r\n, L=990, _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, @@ -114,7 +114,9 @@ R$+ < @ $* > $* $@ $1 < @ $2 > $3 not UUCP form R< $&h ! > $- ! $+ $@ $2 < @ $1 .UUCP. > R< $&h ! > $-.$+ ! $+ $@ $3 < @ $1.$2 > R< $&h ! > $+ $@ $1 < @ $&h .UUCP. > -R< $+ ! > $+ $: $1 ! $2 < @ *LOCAL* >') +R< $+ ! > $+ $: $1 ! $2 < @ $Y > use UUCP_RELAY +R$+ < @ $+ : $+ > $@ $1 < @ $3 > strip mailer: part +R$+ < @ > $: $1 < @ *LOCAL* > if no UUCP_RELAY') # diff --git a/usr.sbin/sendmail/contrib/bsdi.mc b/usr.sbin/sendmail/contrib/bsdi.mc index 7c7553f48e3..dde20161674 100644 --- a/usr.sbin/sendmail/contrib/bsdi.mc +++ b/usr.sbin/sendmail/contrib/bsdi.mc @@ -35,7 +35,7 @@ and examples describing most of the common things people need to setup. # See /usr/share/sendmail/README for help in building a configuration file. # include(`../m4/cf.m4') -VERSIONID(`@(#)$Id: bsdi.mc,v 1.1 1996/01/29 01:42:36 dm Exp $') +VERSIONID(`@(#)$Id: bsdi.mc,v 1.2 1996/12/14 21:16:32 downsj Exp $') dnl # Specify your OS type below OSTYPE(`bsd4.4') diff --git a/usr.sbin/sendmail/contrib/expn.pl b/usr.sbin/sendmail/contrib/expn.pl index eec3b9abce2..039782e458a 100644 --- a/usr.sbin/sendmail/contrib/expn.pl +++ b/usr.sbin/sendmail/contrib/expn.pl @@ -13,7 +13,7 @@ $sockaddr = 'S n a4 x8'; # system requirements: # must have 'nslookup' and 'hostname' programs. -# Header: /home/muir/bin/RCS/expn,v 3.6 1994/02/23 22:26:19 muir Exp muir +# $Header: /cvs/OpenBSD/src/usr.sbin/sendmail/contrib/Attic/expn.pl,v 1.3 1996/12/14 21:16:35 downsj Exp $ # TODO: # less magic should apply to command-line addresses diff --git a/usr.sbin/sendmail/contrib/mailprio b/usr.sbin/sendmail/contrib/mailprio index cdbc3b06c26..58feba7c22e 100644 --- a/usr.sbin/sendmail/contrib/mailprio +++ b/usr.sbin/sendmail/contrib/mailprio @@ -1,280 +1,540 @@ -Message-Id: <199412081919.NAA23234@austin.BSDI.COM> -To: Eric Allman <eric@cs.berkeley.edu> -Subject: Re: sorting mailings lists with fastest delivery users first -In-reply-to: Your message of Thu, 08 Dec 1994 06:08:33 PST. -References: <199412081408.GAA06210@mastodon.CS.Berkeley.EDU> -From: Tony Sanders <sanders@bsdi.com> +Received: from austin.bsdi.com (root{9l9gVDC7v8t3dlv0OtXTlby6X1zBWd56}@austin.BSDI.COM [205.230.224.49]) by knecht.Sendmail.ORG (8.8.2/8.8.2) with ESMTP id JAA05023 for <eric@sendmail.org>; Thu, 31 Oct 1996 09:29:47 -0800 (PST) +Received: from austin.bsdi.com (localhost [127.0.0.1]) by austin.bsdi.com (8.7.4/8.7.3) with ESMTP id KAA19250; Thu, 31 Oct 1996 10:28:18 -0700 (MST) +Message-Id: <199610311728.KAA19250@austin.bsdi.com> +To: Eric Allman <eric@sendmail.org> +cc: marc@xfree86.org +Subject: Updated mailprio_0_93.shar +From: Tony Sanders <sanders@earth.com> Organization: Berkeley Software Design, Inc. -Date: Thu, 08 Dec 1994 13:19:39 -0600 -Sender: sanders@austin.BSDI.COM +Date: Thu, 31 Oct 1996 10:28:14 -0700 +Sender: sanders@austin.bsdi.com -Eric Allman writes: -> Nope, that's a new one, so far as I know. Any interest in -> contributing it? For small lists it seems overkill, but for -> large lists it could be a major win. +Eric, please update contrib/mailprio in the sendmail distribution +to this version at your convenience. Thanks. -Sure, I will contribute it; after I sent you mail last night I went ahead -and finished up what I thought needed to be done. I would like to get -some feedback from you on a few items, if you have time. +I've also made this available in: + ftp://ftp.earth.com/pub/postmaster/ -There are two programs, mailprio_mkdb and mailprio (source below). +mailprio_0_93.shar follows... -mailprio_mkdb reads maillog files and creates a DB file of address vs. -delay. I'm not too happy with how it does the averages right now but this -is just a quick hack. However, it should at least order sites that take -days vs. those that deliver on the first pass through. One thing that -would make this information a lot more accurate is if sendmail could log -a "transaction delay" (on failures also), as well as total delivery delay. -Perhaps, as an option, it could maintain the DB file itself? - -mailprio then simply reads a list of addresses from stdin (the mailing -list), and tries to prioritize them according to the info the database. -It collects comment lines and other junk at the top of the file; all -mailprio does is reorder lines, the actual text of the file should -be unchanged to the extent that you can verify it with: - sort sorted_list > checkit; sort mailing-list | diff - checkit -Users with no delay information are put next. The prioritized list is last. -Of course, this function could also be built-into sendmail (eventually). - -Putting "new account" info at the top with the current averaging function -probably adversly affects the prioritized list (at least in the short -term), but putting it at the bottom would not really give the new accounts -a fair chance. I suspect this isn't that big of a problem. I'm running -this here on a list with 461 accounts and about 10 messages per day so -I'll see how it goes. I'll keep some stats on delay times and see what -happens. - -Another thing that would help this situation, is if sendmail had the queue -ordered by site (but you already know this). If you ever get to do per -site queuing you should consider "blocking" a queue for some short period -of time if a connection fails to that site [sendmail does this inside a -single process on a per account basis now right?]; this would allow multiple -sendmails to quickly skip over those sites for people like me that run: - - for i in 1 2 3 4 5 6 7 8 ; do daemon sendmail -q; done - -to flush a queue that has gotten behind. You could also do this inside -sendmail with a parallelism option (when it is time to run the queue, how -many processes to start). - -#! /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: mailprio mailprio_mkdb -# Wrapped by sanders@austin.BSDI.COM on Fri Dec 9 18:07:02 1994 -PATH=/bin:/usr/bin:/usr/ucb ; export PATH -if test -f 'mailprio' -a "${1}" != "-c" ; then - echo shar: Will not clobber existing file \"'mailprio'\" +#!/bin/sh +# This is a shell archive (produced by GNU sharutils 4.1). +# To extract the files from this archive, save it to some FILE, remove +# everything before the `!/bin/sh' line above, then type `sh FILE'. +# +# Made on 1996-10-31 10:07 MST by <sanders@earth.com>. +# +# Existing files will *not* be overwritten unless `-c' is specified. +# +# This shar contains: +# length mode name +# ------ ---------- ------------------------------------------ +# 8260 -rwxr-xr-x mailprio +# 3402 -rw-r--r-- mailprio.README +# 4182 -rwxr-xr-x mailprio_mkdb +# +touch -am 1231235999 $$.touch >/dev/null 2>&1 +if test ! -f 1231235999 && test -f $$.touch; then + shar_touch=touch else -echo shar: Extracting \"'mailprio'\" \(3093 characters\) -sed "s/^X//" >'mailprio' <<'END_OF_FILE' -X#!/usr/bin/perl -X# -X# mailprio -- setup mail priorities for a mailing list -X# -X# Sort mailing list by mailprio database: -X# mailprio < mailing-list > sorted_list -X# Double check against orig: -X# sort sorted_list > checkit; sort mailing-list | diff - checkit -X# If it checks out, install it. -X# -X# TODO: -X# option to process mqueue files so we can reorder files in the queue! -X$usage = "Usage: mailprio [-p priodb]\n"; -X$home = "/home/sanders/lists"; -X$priodb = "$home/mailprio"; -X -Xif ($main'ARGV[0] =~ /^-/) { -X $args = shift; -X if ($args =~ m/\?/) { print $usage; exit 0; } -X if ($args =~ m/p/) { -X $priodb = shift || die $usage, "-p requires argument\n"; } -X} -X -X# In shell script, it goes something like this: -X# old_mailprio > /tmp/a -X# fgrep -f lists/inet-access /tmp/a | sed -e 's/^.......//' > /tmp/b -X# ; /tmp/b contains list of known users, faster delivery first -X# fgrep -v -f /tmp/b lists/inet-access > /tmp/c -X# ; put all unknown stuff at the top of new list for now -X# echo '# -----' >> /tmp/c -X# cat /tmp/b >> /tmp/c -X -X# Setup %list and @list -Xlocal($addr, $canon); -Xwhile ($addr = <STDIN>) { -X chop $addr; -X next if $addr =~ /^# ----- /; # that's our line -X push(@list, $addr), next if $addr =~ /^\s*#/; # save comments -X $canon = &canonicalize((&simplify_address($addr))[0]); -X unless (defined $canon) { -X warn "no address found: $addr\n"; -X push(@list, $addr); # save it anyway -X next; + shar_touch=: + echo + echo 'WARNING: not restoring timestamps. Consider getting and' + echo "installing GNU \`touch', distributed in GNU File Utilities..." + echo +fi +rm -f 1231235999 $$.touch +# +# ============= mailprio ============== +if test -f 'mailprio' && test X"$1" != X"-c"; then + echo 'x - skipping mailprio (file already exists)' +else + echo 'x - extracting mailprio (text)' + sed 's/^X//' << 'SHAR_EOF' > 'mailprio' && +#!/usr/bin/perl +# +# mailprio,v 1.4 1996/10/31 17:03:52 sanders Exp +# Version 0.93 -- Thu Oct 31 09:42:25 MST 1996 +# +# mailprio -- setup mail priorities for a mailing list +# +# Copyright 1994, 1996, Tony Sanders <sanders@earth.com> +# Rights are hereby granted to download, use, modify, sell, copy, and +# redistribute this software so long as the original copyright notice +# and this list of conditions remain intact and modified versions are +# noted as such. +# +# I would also very much appreciate it if you could send me a copy of +# any changes you make so I can possibly integrate them into my version. +# +# Options: +# -p priority_database -- Specify database to use if not default +# -q -- Process sendmail V8.8.X queue format files +# +# Sort mailing lists or sendmail queue files by mailprio database. +# Files listed on the command line are locked and then sorted in place, in +# the absence of any file arguments it will read STDIN and write STDOUT. +# +# Examples: +# mailprio < mailing-list > sorted_list +# mailprio mailing-list1 mailing-list2 mailing-list3 ... +# mailprio -q /var/spool/mqueue/qf* +# To double check results: +# sort sorted_list > checkit; sort orig-mailing-list | diff - checkit +# +# To get the maximum value from a transaction delay based priority +# function you need to reorder the distribution list (and the mail +# queue files for that matter) fairly often; you could even have +# your mailing list software reorder the list before each outgoing +# message. +# +$usage = "Usage: mailprio [-p priodb] [-q] [mailinglists ...]\n"; +$home = "/home/sanders/lists"; +$priodb = "$home/mailprio"; +$locking = "flock"; # "flock" or "fcntl" +X +# In shell, it would go more or less like this: +# old_mailprio > /tmp/a +# fgrep -f lists/inet-access /tmp/a | sed -e 's/^.......//' > /tmp/b +# ; /tmp/b contains list of known users, faster delivery first +# fgrep -v -f /tmp/b lists/inet-access > /tmp/c +# ; put all unknown stuff at the top of new list for now +# echo '# -----' >> /tmp/c +# cat /tmp/b >> /tmp/c +X +$qflag = 0; +while ($main'ARGV[0] =~ /^-/) { +X $args = shift; +X if ($args =~ m/\?/) { print $usage; exit 0; } +X if ($args =~ m/q/) { $qflag = 1; } +X if ($args =~ m/p/) { +X $priodb = shift || die $usage, "-p requires argument\n"; } +} +X +push(@main'ARGV, '-') if ($#ARGV < 0); +while ($file = shift @ARGV) { +X if ($file eq "-") { +X $source = "main'STDIN"; +X $sink = "main'STDOUT"; +X } else { +X $sink = $source = "FH"; +X open($source, "+< $file") || do { warn "$file: $!\n"; next; }; +X if (!defined &seize($source, &LOCK_EX | &LOCK_NB)) { +X # couldn't get lock, just skip it +X close($source); +X next; +X } X } -X if (defined $list{$canon}) { -X warn "duplicate: ``$addr -> $canon''\n"; -X push(@list, $addr); # save it anyway -X next; +X +X local(*list); +X &process($source, *list); +X +X # setup to write output +X if ($file ne "-") { +X # zero the file (FH is hardcoded because truncate requires it, sigh) +X seek(FH, 0, 0) || die "$file: seek: $!\n"; +X truncate(FH, 0) || die "$file: truncate: $!\n"; +X } +X +X # do the dirty work +X &output($sink, *list); +X +X close($sink) || warn "$file: $!\n"; # close clears the lock +X close($source); +} +X +sub process { +X # Setup %list and @list +X local($source, *list) = @_; +X local($addr, $canon); +X while ($addr = <$source>) { +X chop $addr; +X next if $addr =~ /^# ----- /; # that's our line +X push(@list, $addr), next if $addr =~ /^\s*#/; # save comments +X if ($qflag) { +X next if $addr =~ m/^\./; +X push(@list, $addr), next if !($addr =~ s/^(R[^:]*:)//); +X $Rflags = $1; +X } +X $canon = &canonicalize((&simplify_address($addr))[0]); +X unless (defined $canon) { +X warn "$file: no address found: $addr\n"; +X push(@list, ($qflag?$Rflags:'') . $addr); # save it as is +X next; +X } +X if (defined $list{$canon}) { +X warn "$file: duplicate: ``$addr -> $canon''\n"; +X push(@list, ($qflag?$Rflags:'') . $addr); # save it as is +X next; +X } +X $list{$canon} = $addr; X } -X $list{$canon} = $addr; -X} -X -Xlocal(*prio); -Xdbmopen(%prio, $priodb, 0644) || die "$priodb: $!\n"; -Xforeach $to (keys %list) { -X if (defined $prio{$to}) { -X # add to list of found users (%userprio) and remove from %list -X # so that we know what users were not yet prioritized -X $userprio{$to} = $prio{$to}; # priority -X $useracct{$to} = $list{$to}; # string -X delete $list{$to}; +} +X +sub output { +X local($sink, *list) = @_; +X +X local($to, *prio, *userprio, *useracct); +X dbmopen(%prio, $priodb, 0644) || die "$priodb: $!\n"; +X foreach $to (keys %list) { +X if (defined $prio{$to}) { +X # add to list of found users (%userprio) and remove from %list +X # so that we know what users were not yet prioritized +X $userprio{$to} = $prio{$to}; # priority +X $useracct{$to} = $list{$to}; # string +X delete $list{$to}; +X } X } -X} -Xdbmclose(%prio); +X dbmclose(%prio); +X +X # Put all the junk we found at the very top +X # (this might not always be a feature) +X print $sink join("\n", @list), "\n" if int(@list); X -X# Put all the junk we found at the very top -X# (this might not always be a feature) -Xprint join("\n", @list), "\n"; +X # prioritized list of users +X if (int(keys %userprio)) { +X print $sink '# ----- prioritized users', "\n" unless $qflag; +X foreach $to (sort by_userprio keys %userprio) { +X die "Opps! Something is seriously wrong with useracct: $to\n" +X unless defined $useracct{$to}; +X print $sink 'RFD:' if $qflag; +X print $sink $useracct{$to}, "\n"; +X } +X } X -X# unprioritized users go next, slow accounts will get moved down quickly -Xprint '# ----- unprioritized users', "\n"; -Xforeach $to (keys %list) { print $list{$to}, "\n"; } +X # unprioritized users go last, fast accounts will get moved up eventually +X # XXX: should go before the "really slow" prioritized users? +X if (int(keys %list)) { +X print $sink '# ----- unprioritized users', "\n" unless $qflag; +X foreach $to (keys %list) { +X print $sink 'RFD:' if $qflag; +X print $sink $list{$to}, "\n"; +X } +X } X -X# finally, our prioritized list of users -Xprint '# ----- prioritized users', "\n"; -Xforeach $to (sort { $userprio{$a} <=> $userprio{$b}; } keys %userprio) { -X die "Opps! Something is seriously wrong with useracct: $to\n" -X unless defined $useracct{$to}; -X print $useracct{$to}, "\n"; -X} +X print $sink ".\n" if $qflag; +} X -Xexit(0); +sub by_userprio { +X # sort first by priority, then by key. +X $userprio{$a} <=> $userprio{$b} || $a cmp $b; +} X -X# REPL-LIB --------------------------------------------------------------- +# REPL-LIB --------------------------------------------------------------- X -Xsub canonicalize { +sub canonicalize { X local($addr) = @_; X # lowercase, strip leading/trailing whitespace X $addr =~ y/A-Z/a-z/; $addr =~ s/^\s+//; $addr =~ s/\s+$//; $addr; -X} +} X -X# @addrs = simplify_address($addr); -Xsub simplify_address { +# @addrs = simplify_address($addr); +sub simplify_address { X local($_) = shift; -X 1 while s/\([^\(\)]*\)//g; # strip comments -X 1 while s/"[^"]*"//g; # strip comments -X split(/,/); # split into parts +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 1 while s/.*<(.*)>.*/\1/; +X s/^\s+//; +X s/\s+$//; X } X @_; -X} -END_OF_FILE -if test 3093 -ne `wc -c <'mailprio'`; then - echo shar: \"'mailprio'\" unpacked with wrong size! +} +X +### ---- ### +# +# Error codes +# +do 'errno.ph'; +eval 'sub ENOENT {2;}' unless defined &ENOENT; +eval 'sub EINTR {4;}' unless defined &EINTR; +eval 'sub EINVAL {22;}' unless defined &EINVAL; +X +# +# File locking +# +do 'sys/unistd.ph'; +eval 'sub SEEK_SET {0;}' unless defined &SEEK_SET; +X +do 'sys/file.ph'; +eval 'sub LOCK_SH {0x01;}' unless defined &LOCK_SH; +eval 'sub LOCK_EX {0x02;}' unless defined &LOCK_EX; +eval 'sub LOCK_NB {0x04;}' unless defined &LOCK_NB; +eval 'sub LOCK_UN {0x08;}' unless defined &LOCK_UN; +X +do 'fcntl.ph'; +eval 'sub F_GETFD {1;}' unless defined &F_GETFD; +eval 'sub F_SETFD {2;}' unless defined &F_SETFD; +eval 'sub F_GETFL {3;}' unless defined &F_GETFL; +eval 'sub F_SETFL {4;}' unless defined &F_SETFL; +eval 'sub O_NONBLOCK {0x0004;}' unless defined &O_NONBLOCK; +eval 'sub F_SETLK {8;}' unless defined &F_SETLK; # nonblocking +eval 'sub F_SETLKW {9;}' unless defined &F_SETLKW; # lockwait +eval 'sub F_RDLCK {1;}' unless defined &F_RDLCK; +eval 'sub F_UNLCK {2;}' unless defined &F_UNLCK; +eval 'sub F_WRLCK {3;}' unless defined &F_WRLCK; +$s_flock = "sslll"; # struct flock {type, whence, start, len, pid} +X +# return undef on failure +sub seize { +X local ($FH, $lock) = @_; +X local ($ret); +X if ($locking eq "flock") { +X $ret = flock($FH, $lock); +X return ($ret == 0 ? undef : 1); +X } else { +X local ($flock, $type) = 0; +X if ($lock & &LOCK_SH) { $type = &F_RDLCK; } +X elsif ($lock & &LOCK_EX) { $type = &F_WRLCK; } +X elsif ($lock & &LOCK_UN) { $type = &F_UNLCK; } +X else { $! = &EINVAL; return undef; } +X $flock = pack($s_flock, $type, &SEEK_SET, 0, 0, 0); +X $ret = fcntl($FH, ($lock & &LOCK_NB) ? &F_SETLK : &F_SETLKW, $flock); +X return ($ret == -1 ? undef : 1); +X } +} +SHAR_EOF + $shar_touch -am 1031100396 'mailprio' && + chmod 0755 'mailprio' || + echo 'restore of mailprio failed' + shar_count="`wc -c < 'mailprio'`" + test 8260 -eq "$shar_count" || + echo "mailprio: original size 8260, current size $shar_count" fi -chmod +x 'mailprio' -# end of 'mailprio' +# ============= mailprio.README ============== +if test -f 'mailprio.README' && test X"$1" != X"-c"; then + echo 'x - skipping mailprio.README (file already exists)' +else + echo 'x - extracting mailprio.README (text)' + sed 's/^X//' << 'SHAR_EOF' > 'mailprio.README' && +mailprio README +X +mailprio.README,v 1.2 1996/10/31 17:03:54 sanders Exp +Version 0.93 -- Thu Oct 31 09:42:25 MST 1996 +X +Copyright 1994, 1996, Tony Sanders <sanders@earth.com> +Rights are hereby granted to download, use, modify, sell, copy, and +redistribute this software so long as the original copyright notice +and this list of conditions remain intact and modified versions are +noted as such. +X +I would also very much appreciate it if you could send me a copy of +any changes you make so I can possibly integrate them into my version. +X +The current version of this and other related mail tools are available in: +X ftp://ftp.earth.com/pub/postmaster/ +X +Even with the new persistent host status in sendmail V8.8.X this +function can still reduce the lag time distributing mail to a large +group of people. It also makes it a little more likely that everyone +will get mailing list mail in the order sent which can help reduce +duplicate postings. Basically, the goal is to put slow hosts at +the bottom of the list so that as many fast hosts are delivered +as quickly as possible. +X +CONTENTS +======== +X +X mailprio.README -- simple docs +X mailprio -- the address sorter +X mailprio_mkdb -- builds the database for the sorter +X +X +CHANGES +======= +X Version 0.92 +X Initial public release. +X +X Version 0.93 +X Updated to make use of the (somewhat) new xdelay statistic. +X Changed -q flag to support new sendmail queue file format (RFD:<addr>). +X Fixed argument parsing bug. +X Fixed bug with database getting "garbage" in it. +X +X +CONFIGURATION +============= +X +X You need to edit each script and ensure proper configuration. +X +X In mailprio check: #!perl path, $home, $priodb, $locking +X +X In mailprio_mkdb check: #!perl path, $home, $priodb, $maillog +X +X +USAGE: mailprio +=============== +X +X Usage: mailprio [-p priodb] [-q] [mailinglists ...] +X -p priority_database -- Specify database to use if not default +X -q -- Process sendmail queue format files +X [USE WITH CAUTION] +X +X Sort mailing lists or sendmail V8 queue files by mailprio database. +X Files listed on the command line are locked and then sorted in place, in +X the absence of any file arguments it will read STDIN and write STDOUT. +X +X Examples: +X mailprio < mailing-list > sorted_list +X mailprio mailing-list1 mailing-list2 mailing-list3 ... +X mailprio -q /var/spool/mqueue/qf* [not recommended] +X To double check results: +X sort sorted_list > checkit; sort orig-mailing-list | diff - checkit +X +X NOTE: +X To get the maximum value from a transaction delay based priority +X function you need to reorder the distribution list (and the mail +X queue files for that matter) fairly often; you could even have +X your mailing list software reorder the list before each outgoing +X message. +X +X +USAGE: mailprio_mkdb +==================== +X +X Usage: mailprio_mkdb [-l maillog] [-p priodb] +X -l maillog -- Specify maillog to process if not default +X -p priority_database -- Specify database to use if not default +X +X Builds the mail priority database using information from the maillog. +X +X Run at least nightly before you rotate the maillog. If you are +X going to run mailprio more often than that then you will need to +X load the current maillog information before that will do any good +X (and to keep from reloading the same information you will need +X some kind of incremental maillog information to load from). +SHAR_EOF + $shar_touch -am 1031100396 'mailprio.README' && + chmod 0644 'mailprio.README' || + echo 'restore of mailprio.README failed' + shar_count="`wc -c < 'mailprio.README'`" + test 3402 -eq "$shar_count" || + echo "mailprio.README: original size 3402, current size $shar_count" fi -if test -f 'mailprio_mkdb' -a "${1}" != "-c" ; then - echo shar: Will not clobber existing file \"'mailprio_mkdb'\" +# ============= mailprio_mkdb ============== +if test -f 'mailprio_mkdb' && test X"$1" != X"-c"; then + echo 'x - skipping mailprio_mkdb (file already exists)' else -echo shar: Extracting \"'mailprio_mkdb'\" \(3504 characters\) -sed "s/^X//" >'mailprio_mkdb' <<'END_OF_FILE' -X#!/usr/bin/perl -X# -X# mailprio_mkdb -- make mail priority database based on delay times -X# -X$usage = "Usage: mailprio_mkdb [-l maillog] [-p priodb]\n"; -X$home = "/home/sanders/lists"; -X$maillog = "/var/log/maillog"; -X$priodb = "$home/mailprio"; -X -Xif ($main'ARGV[0] =~ /^-/) { + echo 'x - extracting mailprio_mkdb (text)' + sed 's/^X//' << 'SHAR_EOF' > 'mailprio_mkdb' && +#!/usr/bin/perl +# +# mailprio_mkdb,v 1.5 1996/10/31 17:03:53 sanders Exp +# Version 0.93 -- Thu Oct 31 09:42:25 MST 1996 +# +# mailprio_mkdb -- make mail priority database based on delay times +# +# Copyright 1994, 1996, Tony Sanders <sanders@earth.com> +# Rights are hereby granted to download, use, modify, sell, copy, and +# redistribute this software so long as the original copyright notice +# and this list of conditions remain intact and modified versions are +# noted as such. +# +# I would also very much appreciate it if you could send me a copy of +# any changes you make so I can possibly integrate them into my version. +# +# The average function moves the value around quite rapidly (half-steps) +# which may or may not be a feature. This version uses the new xdelay +# statistic (new as of sendmail V8) which is per transaction. We also +# weight the result based on the overall delay. +# +# Something that might be worth doing for systems that don't support +# xdelay would be to compute an approximation of the transaction delay +# by sorting by messages-id and delay then computing the difference +# between adjacent delay values. +# +# To get the maximum value from a transaction delay based priority +# function you need to reorder the distribution list (and the mail +# queue files for that matter) fairly often; you could even have +# your mailing list software reorder the list before each outgoing +# message. +X +$usage = "Usage: mailprio_mkdb [-l maillog] [-p priodb]\n"; +$home = "/home/sanders/lists"; +$maillog = "/var/log/maillog"; +$priodb = "$home/mailprio"; +X +while ($ARGV[0] =~ /^-/) { X $args = shift; X if ($args =~ m/\?/) { print $usage; exit 0; } X if ($args =~ m/l/) { X $maillog = shift || die $usage, "-l requires argument\n"; } X if ($args =~ m/p/) { X $priodb = shift || die $usage, "-p requires argument\n"; } -X} -X -Xlocal(*prio); -X# We'll merge with existing information if it's already there. -Xdbmopen(%prio, $priodb, 0644) || die "$priodb: $!\n"; -X&getlog_stats($maillog, *prio); -X# foreach $addr (sort { $prio{$a} <=> $prio{$b}; } keys %prio) { -X# printf("%06d %s\n", $prio{$addr}, $addr); } -Xdbmclose(%prio); -Xexit(0); -X -Xsub getlog_stats { +} +X +$SIG{'PIPE'} = 'handle_pipe'; +X +# will merge with existing information +dbmopen(%prio, $priodb, 0644) || die "$priodb: $!\n"; +&getlog_stats($maillog, *prio); +dbmclose(%prio); +exit(0); +X +sub handle_pipe { +X dbmclose(%prio); +} +X +sub getlog_stats { X local($maillog, *stats) = @_; X local($to, $delay); X local($h, $m, $s); X open(MAILLOG, "< $maillog") || die "$maillog: $!\n"; X while (<MAILLOG>) { -X ($delay) = (m/, delay=([^,]*), /); -X $delay || next; -X ($h, $m, $s) = split(/:/, $delay); -X $delay = ($h * 60 * 60) + ($m * 60) + $s; -X -X # deleting everything after ", " seems safe enough, though -X # it is possible that it was inside "..."'s and that we will -X # miss some addresses because of it. However, I'm not willing -X # to do full parsing just for that case. If this bothers you -X # you could do something like: s/, (delay|ctladdr)=.*//; -X # but you have to make sure you catch all the possible names. -X $to = $_; $to =~ s/^.* to=//; $to =~ s/, .*//; +X next unless / to=/ && / stat=/; +X next if / stat=queued/; +X if (/ stat=sent/i) { +X # read delay and xdelay and convert to seconds +X ($delay) = (m/ delay=([^,]*),/); +X next unless $delay; +X ($h, $m, $s) = split(/:/, $delay); +X $delay = ($h * 60 * 60) + ($m * 60) + $s; +X +X ($xdelay) = (m/ xdelay=([^,]*),/); +X next unless $xdelay; +X ($h, $m, $s) = split(/:/, $xdelay); +X $xdelay = ($h * 60 * 60) + ($m * 60) + $s; +X +X # Now weight the delay factor by the transaction delay (xdelay). +X $xdelay /= 300; # [0 - 1(@5 min)] +X $xdelay += 0.5; # [0.5 - 1.5] +X $xdelay = 1.5 if $xdelay > 1.5; # clamp +X $delay *= $xdelay; # weight delay by xdelay +X } +X elsif (/, stat=/) { +X # delivery failure of some sort (i.e. bad) +X $delay = 432000; # force 5 days +X } +X $delay = 1000000 if $delay > 1000000; +X +X # filter the address(es); isn't perfect but is "good enough" +X $to = $_; $to =~ s/^.* to=//; +X 1 while $to =~ s/\([^\(\)]*\)//g; # strip comments +X 1 while $to =~ s/"[^"]*"//g; # strip comments +X $to =~ s/, .*//; # remove other stat info X foreach $addr (&simplify_address($to)) { X next unless $addr; X $addr = &canonicalize($addr); -X # print $delay, " ", $addr, "\n"; X $stats{$addr} = $delay unless defined $stats{$addr}; # init -X -X # This average function moves the value around quite rapidly -X # which may or may not be a feature. -X # -X # This has at least one odd behavior because we currently only -X # use the delay information from maillog which is only logged -X # on actual delivery. This works backwards from what we really -X # want to happen when a fast host goes down for a while and then -X # comes back up. -X # -X # I spoke with Eric and he suggested adding an xdelay statistic -X # for a per transaction delay which would help that situation -X # a lot. What I believe you want in that cases something like: -X # delay fast, xdelay fast: smokin', these hosts go first -X # delay slow, xdelay fast: put host high on the list (back up?) -X # delay fast, xdelay slow: host is down/having problems/slow -X # delay slow, xdelay slow: poorly connected sites, very last -X # Of course, you have to reorder the distribution list fairly -X # often for that to help. Come to think of it, you should -X # also reorder /var/spool/mqueue files also (if they aren't -X # locked of course). Hmmm.... +X # pseudo-average in the new delay (half-steps) +X # simple, moving average X $stats{$addr} = int(($stats{$addr} + $delay) / 2); X } X } X close(MAILLOG); -X} +} X -X# REPL-LIB --------------------------------------------------------------- +# REPL-LIB --------------------------------------------------------------- X -Xsub canonicalize { +sub canonicalize { X local($addr) = @_; X # lowercase, strip leading/trailing whitespace X $addr =~ y/A-Z/a-z/; $addr =~ s/^\s+//; $addr =~ s/\s+$//; $addr; -X} +} X -X# @addrs = simplify_address($addr); -Xsub simplify_address { +# @addrs = simplify_address($addr); +sub simplify_address { X local($_) = shift; X 1 while s/\([^\(\)]*\)//g; # strip comments X 1 while s/"[^"]*"//g; # strip comments @@ -285,13 +545,13 @@ X s/^\s+//; X s/\s+$//; X } X @_; -X} -END_OF_FILE -if test 3504 -ne `wc -c <'mailprio_mkdb'`; then - echo shar: \"'mailprio_mkdb'\" unpacked with wrong size! -fi -chmod +x 'mailprio_mkdb' -# end of 'mailprio_mkdb' +} +SHAR_EOF + $shar_touch -am 1031100396 'mailprio_mkdb' && + chmod 0755 'mailprio_mkdb' || + echo 'restore of mailprio_mkdb failed' + shar_count="`wc -c < 'mailprio_mkdb'`" + test 4182 -eq "$shar_count" || + echo "mailprio_mkdb: original size 4182, current size $shar_count" fi -echo shar: End of shell archive. exit 0 diff --git a/usr.sbin/sendmail/doc/op/op.me b/usr.sbin/sendmail/doc/op/op.me index 6fd40ad866e..42374974087 100644 --- a/usr.sbin/sendmail/doc/op/op.me +++ b/usr.sbin/sendmail/doc/op/op.me @@ -30,7 +30,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)op.me 8.70 (Berkeley) 11/3/95 +.\" @(#)op.me 8.100 (Berkeley) 12/1/96 .\" .\" eqn op.me | pic | troff -me .eh 'SMM:08-%''Sendmail Installation and Operation Guide' @@ -65,12 +65,12 @@ .sp .r Eric Allman -Pang\(aea Reference Systems +InReference, Inc. eric@Sendmail.ORG .sp -Version 8.70 +Version 8.100 .sp -For Sendmail Version 8.7 +For Sendmail Version 8.8 .)l .sp 2 .pp @@ -105,17 +105,12 @@ RFC822 (Internet Mail Format Protocol), RFC1123 (Internet Host Requirements), RFC1521 (MIME), RFC1651 (SMTP Service Extensions), -and a series of as-yet-draft standards describing -Delivery Status Notifications (DSNs), -available from the internet drafts sites as -draft-ietf-notary-mime-delivery-\fIXX\fP.txt, -draft-ietf-notary-mime-report-\fIXX\fP.txt, -draft-ietf-notary-smtp-drpt-\fIXX\fP.txt, +RFC1891 (SMTP Delivery Status Notifications), +RFC1892 (Multipart/Report), +RFC1893 (Mail System Status Codes), +RFC1894 (Delivery Status Notifications), and -draft-ietf-notary-status-\fIXX\fP.txt -(replace -.i XX -by the latest draft number). +RFC1985 (SMTP Service Extension for Remote Message Queue Starting). However, since .i sendmail is designed to work in a wider world, @@ -446,8 +441,7 @@ Shell files used by the build process. You shouldn't have to mess with these. .ip siteconfig -Local site configuration information, -such as UUCP connectivity. +Local UUCP connectivity information. They normally contain lists of site information, for example: .(b SITE(contessa) @@ -466,6 +460,9 @@ It can be U (indicating locally connected hosts) or one of W, X, or Y for up to three remote UUCP hubs. +This directory has been supplanted by the mailertable feature; +any new configurations should use that feature to do UUCP +(and other) routing. .pp If you are in a new domain (e.g., a company), @@ -586,6 +583,26 @@ ln \-s /usr/\*(SD/sendmail /usr/\*(SB/newaliases .)b This can be installed in whatever search path you prefer for your system. +.sh 3 "/usr/\*(SB/hoststat" +.pp +The +.i hoststat +command should just be a link to +.i sendmail , +in a fashion similar to +.i newaliases . +This command lists the status of the last mail transaction +with all remote hosts. +It functions only when the +.b HostStatusDirectory +option is set. +.sh 3 "/usr/\*(SB/purgestat" +.pp +This command is also a link to +.i sendmail . +It flushes all information that is stored in the +.b HostStatusDirectory +tree. .sh 3 "/var/spool/mqueue" .pp The directory @@ -600,6 +617,15 @@ is defined in the option of the .i sendmail.cf file. +.sh 3 "/var/spool/mqueue/.hoststat" +.pp +This is a typical value for the +.b HostStatusDirectory +option, +containing one file per host +that this sendmail has chatted with recently. +It is normally a subdirectory of +.i mqueue . .sh 3 "/etc/aliases*" .pp The system aliases are held in @@ -1022,6 +1048,80 @@ you can remove the directory: .(b rmdir /var/spool/omqueue .)b +.sh 2 "Disk Based Connection Information" +.pp +.i Sendmail +stores a large amount of information about each remote system it +has connected to in memory. It is now possible to preserve some +of this information on disk as well, by using the +.b HostStatusDirectory +option, so that it may be shared between several invocations of +.i sendmail . +This allows mail to be queued immediately or skipped during a queue run if +there has been a recent failure in connecting to a remote machine. +.pp +Additionally enabling +.b SingleThreadDelivery +has the added effect of single-threading mail delivery to a destination. +This can be quite helpful +if the remote machine is running an SMTP server that is easily overloaded +or cannot accept more than a single connection at a time, +but can cause some messages to be punted to a future queue run. +It also applies to +.i all +hosts, so setting this because you have one machine on site +that runs some software that is easily overrun +can cause mail to other hosts to be slowed down. +If this option is set, +you probably want to set the +.b MinQueueAge +option as well and run the queue fairly frequently; +this will cause hosts that are skipped because another +.i sendmail +instance is talking to it to be tried again soon. +.pp +The disk based host information is stored in a subdirectory of of the +.b mqueue +directory called +.b \&.hoststat \**. +.(f +\**This is the usual value of the +.b HostStatusDirectory +option; +it can, of course, go anywhere you like in your filesystem. +.)f +Removing this directory and its subdirectories has an effect similar to +the +.i purgestat +command and is completely safe. +The information in these directories can +be perused with the +.i hoststat +command, which will indicate the host name, the last access, and the +status of that access. +An asterisk in the left most column indicates that a +.i sendmail +process currently has the host locked for mail delivery. +.pp +The disk based connection information is treated the same way as memory based +connection information for the purpose of timeouts. +By default, information about host failures is valid for 30 minutes. +This can be adjusted with +the +.b Timeout.hoststatus +option. +.pp +The connection information stored on disk may be purged at any time +with the +.i purgestat +command or by invoking sendmail with the +.b \-bH +switch. +The connection information may be viewed with the +.i hoststat +command or by invoking sendmail with the +.b \-bh +switch. .sh 2 "The Service Switch" .pp The implementation of certain system services @@ -1592,7 +1692,7 @@ sets the for this run only; the equivalent line using the long option name is .(b -/usr/\*(SD/sendmail -OQueueTimeout=2m +/usr/\*(SD/sendmail -OTimeout.queuereturn=2m .)b .pp Some options have security implications. @@ -1748,6 +1848,28 @@ dumps the contents of the indicated ruleset. .bu \-d\|debug-spec is equivalent to the command-line flag. +.sh 2 "Persistent Host Status Information" +.pp +When +.b HostStatusDirectory +is enabled, +information about the status of hosts is maintained on disk +and can thus be shared between different instantiations of +.i sendmail . +The status of the last connection with each remote host +may be viewed with the command: +.(b +sendmail \-bh +.)b +This information may be flushed with the command: +.(b +sendmail \-bH +.)b +Flushing the information prevents new +.i sendmail +processes from loading it, +but does not prevent existing processes from using the status information +that they already have. .sh 1 "TUNING" .pp There are a number of configuration parameters @@ -1836,6 +1958,16 @@ In no case can this option extend the timeout longer than the kernel provides, but it can shorten it. This is to get around kernels that provide an absurdly long connection timeout (90 minutes in one case). +.ip iconnect +The same as +.i connect, +except it applies only to the initial attempt to connect to a host +for a given message +[0, unspecified]. +The concept is that this should be very short (a few seconds); +hosts that are well connected and responsive will thus be serviced immediately. +Hosts that are slow will not hold up other deliveries in the initial +delivery attempt. .ip initial The wait for the initial 220 greeting message [5m, 5m]. @@ -2211,6 +2343,8 @@ Messages being deferred (due to a host being down, etc.). .ip 10 Database expansion (alias, forward, and userdb lookups). +.ip 12 +Log all incoming and outgoing SMTP commands. .ip 20 Logs attempts to run locked queue files. These are not errors, @@ -2586,7 +2720,7 @@ and disables the EXPN command. .pp The flags are detailed in section .\"XREF -5.1.6. +5.6. .sh 2 "Send to Me Too" .pp Normally, @@ -2667,7 +2801,7 @@ The syntax of these two commands are: Sets the current ruleset being collected to .i n . If you begin a ruleset more than once -it deletes the old definition. +it appends to the old definition. .(b F .b R \c .i lhs @@ -2894,10 +3028,9 @@ is later rewritten by the mailer-specific envelope rewriting set and assigned to the .b $u macro. -As a special case, if the value to -.b $# -is -.q local +As a special case, if the mailer specified has the +.b F=@ +flag specified and the first character of the .b $: value is @@ -3078,6 +3211,69 @@ Ruleset four is applied to all addresses in the message. It is typically used to translate internal to external form. +.pp +In addition, +ruleset 5 is applied to all local addresses +(specifically, those that resolve to a mailer with the `F=5' +flag set) +that do not have aliases. +This allows a last minute hook for local names. +.sh 3 "Ruleset hooks" +.pp +A few extra rulesets are defined as +.q hooks +that can be defined to get special features. +They are all named rulesets. +The +.q check_* +forms all give accept/reject status; +falling off the end or returning normally is an accept, +and resolving to $#error +is a reject. +.sh 4 "check_relay" +.pp +The +.i check_relay +ruleset is called after a connection is accepted. +It is passed +.(b +client.host.name $| client.host.address +.)b +where +.b $| +is a metacharacter separating the two parts. +This ruleset can reject connections from various locations. +.sh 4 "check_mail" +.pp +The +.i check_mail +ruleset is passed the user name parameter of the +.sm "SMTP MAIL" +command. +It can accept or reject the address. +.sh 4 "check_rcpt" +.pp +The +.i check_rcpt +ruleset is passed the user name parameter of the +.sm "SMTP RCPT" +command. +It can accept or reject the address. +.sh 4 "check_compat" +.pp +The +.i check_compat +ruleset is passed +.(b +sender-address $| recipient-address +.)b +where +.b $| +is a metacharacter separating the addresses. +It can accept or reject mail transfer between these two addresses +much like the +.i checkcompat() +function. .sh 3 "IPC mailers" .pp Some special processing occurs @@ -3365,6 +3561,25 @@ The full name of the sender. The home directory of the recipient. .ip $_ The validated sender address. +.ip ${bodytype} +The message body type +(7BIT or 8BITMIME), +as determined from the envelope. +.ip ${client_addr} +The IP address of the SMTP client. +Defined in the SMTP server only. +.ip ${client_name} +The host name of the SMTP client. +Defined in the SMTP server only. +.ip ${client_port} +The port number of the SMTP client. +Defined in the SMTP server only. +.ip ${envid} +The envelope id passed to sendmail as part of the envelope. +.ip ${opMode} +The current operation mode (from the +.b \-b +flag). .pp There are three types of dates that can be used. The @@ -3560,6 +3775,22 @@ is set to a validated sender host name. If the sender is running an RFC 1413 compliant IDENT server and the receiver has the IDENT protocol turned on, it will include the user name on that host. +.pp +The +.b ${client_name} , +.b ${client_addr} , +and +.b ${client_port} +macros +are set to the name, address, and port number of the SMTP client +who is invoking +.i sendmail +as a server. +These can be used in the +.i check_* +rulesets (using the +.b $& +deferred evaluation form, of course!). .sh 2 "C and F \*- Define Classes" .pp Classes of phrases may be defined @@ -3620,35 +3851,40 @@ The only matches a single word; multi-word entries in the class are ignored in this context. .pp -The class -.b $=w -is set to be the set of all names -this host is known by. -This can be used to match local hostnames. -.pp -The class -.b $=k -is set to be the same as +Some classes have internal meaning to +.i sendmail : +.nr ii 0.5i +.\".ip $=b +.\"A set of Content-Types that will not have the newline character +.\"translated to CR-LF before encoding into base64 MIME. +.\"The class can have major times +.\"(e.g., +.\".q image ) +.\"or full types +.\"(such as +.\".q application/octet-stream ). +.\"The class is initialized with +.\".q application/octet-stream , +.\".q image , +.\".q audio , +.\"and +.\".q video . +.ip $=e +contains the Content-Transfer-Encodings that can be 8\(->7 bit encoded. +It is predefined to contain +.q 7bit , +.q 8bit , +and +.q binary . +.ip $=k +set to be the same as .b $k , that is, the UUCP node name. -.pp -The class -.b $=m -is set to the set of domains by which this host is known, +.ip $=m +set to the set of domains by which this host is known, initially just .b $m . -.pp -The class -.b $=t -is set to the set of trusted users by the -.b T -configuration line. -If you want to read trusted users from a file use -.b Ft \c -.i /file/name . -.pp -The class -.b $=n +.ip $=n can be set to the set of MIME body types that can never be eight to seven bit encoded. It defaults to @@ -3662,16 +3898,19 @@ Multipart messages are always handled recursively. The handling of message/* messages are controlled by class .b $=s . -The class -.b $=e -contains the Content-Transfer-Encodings that can be 8\(->7 bit encoded. -It is predefined to contain -.q 7bit , -.q 8bit , -and -.q binary . -The class -.b $=s +.ip $=q +A set of Content-Types that will never be encoded as base64 +(if they have to be encoded, they will be encoded as quoted-printable). +It can have primary types +(e.g., +.q text ) +or full types +(such as +.q text/plain ). +The class is initialized to have +.q text/plain +only. +.ip $=s contains the set of subtypes of message that can be treated recursively. By default it contains only .q rfc822 . @@ -3681,6 +3920,17 @@ types cannot be 8\(->7 bit encoded. If a message containing eight bit data is sent to a seven bit host, and that message cannot be encoded into seven bits, it will be stripped to 7 bits. +.ip $=t +set to the set of trusted users by the +.b T +configuration line. +If you want to read trusted users from a file use +.b Ft \c +.i /file/name . +.ip $=w +set to be the set of all names +this host is known by. +This can be used to match local hostnames. .pp .i Sendmail can be compiled to allow a @@ -3797,6 +4047,10 @@ To: userb@hostb, userc@hosta .)b automatically. However, it doesn't really work reliably. +.ip d +Do not include angle brackets around route-address syntax addresses. +This is useful on mailers that are going to pass addresses to a shell +that might interpret angle brackets as I/O redirection. .ip D\(dg This mailer wants a .q Date: @@ -3853,6 +4107,8 @@ This option is not required (i.e., if this option is omitted the transmission will still operate successfully, although perhaps not as efficiently as possible). +.ip j +Do User Database rewriting on recipients as well as senders. .ip k Normally when .i sendmail @@ -3928,12 +4184,25 @@ Reverse-paths are officially discouraged by RFC 1123. This mailer wants a .q Return-Path: line. +.ip q +When an address that resolves to this mailer is verified +(SMTP VRFY command), +generate 250 responses instead of 252 responses. +This will imply that the address is local. .ip r Same as .b f , but sends a .b \-r flag. +.ip R +Open SMTP connections from a +.q secure +port. +Secure ports aren't +(secure, that is) +except on UNIX machines, +so it is unclear that this adds anything. .ip s Strip quote characters (" and \e) off of the address before calling the mailer. @@ -3982,6 +4251,13 @@ will have an extra dot prepended (to be stripped at the other end). This insures that lines in the message containing a dot will not terminate the message prematurely. +.ip 0 +Don't look up MX records for hosts sent via SMTP. +.ip 3 +Extend the list of characters converted to =XX notation +when converting to Quoted-Printable +to include those that don't map cleanly between ASCII and EBCDIC. +Useful if you have IBM mainframes on site. .ip 5 If no aliases are found for this address, pass the address through ruleset 5 for possible alternate resolution. @@ -4004,6 +4280,12 @@ that didn't have 8\(->7 bit MIME conversions performed. If set, it is acceptable to send eight bit data to this mailer; the usual attempt to do 8\(->7 bit MIME conversions will be bypassed. +.ip 9 +If set, +do +.i limited +7\(->8 bit MIME conversions. +These conversions are limited to text/plain data. .ip : Check addresses to see if they begin .q :include: ; @@ -4035,7 +4317,10 @@ The (optional) host field is an exit status to be returned, and the user field is a message to be printed. The exit status may be numeric or one of the values USAGE, NOUSER, NOHOST, UNAVAILABLE, SOFTWARE, TEMPFAIL, PROTOCOL, or CONFIG -to return the corresponding EX_ exit code. +to return the corresponding EX_ exit code, +or an enhanced error code as described in RFC 1893, +.ul +Enhanced Mail System Status Codes. For example, the entry: .(b $#error $@ NOHOST $: Host unknown in this domain @@ -4046,7 +4331,8 @@ and the .q "Host unknown" exit status to be returned if the LHS matches. -This mailer is only functional in rulesets zero or five. +This mailer is only functional in rulesets 0, 5, +or one of the check_* rulesets. .pp The mailer named .q local @@ -4140,8 +4426,7 @@ The Type= field sets the type information used in MIME error messages as defined by -RFC XXX -(not yet published). +RFC 1894. It is actually three values separated by slashes: the MTA-type (that is, the description of how hosts are named), the address type (the description of e-mail addresses), @@ -4293,6 +4578,12 @@ rebuild the database .b AutoRebuildAliases option is also set) or issue a warning. +.ip AllowBogusHELO +[no short name] +If set, allow HELO SMTP commands that don't include a host name. +Setting this violates RFC 1123 section 5.2.5, +but is necessary to interoperate with several SMTP clients. +If there is a value, it is still checked for legitimacy. .ip AutoRebuildAliases [D] If set, @@ -4384,6 +4675,15 @@ The point of this option is to be a good network neighbor and avoid using up excessive resources on the other end. The default is five minutes. +.ip ConnectionRateThrottle=\fIN\fP +[no short name] +If set to a positive value, +allow no more than +.i N +incoming daemon connections in a one second period. +This is intended to flatten out peaks +and allow the load average checking to cut in. +Defaults to zero (no limits). .ip DaemonPortOptions=\fIoptions\fP [O] Set server SMTP options. @@ -4532,6 +4832,19 @@ option is set, this will be disabled, and the mail will be sent to the first address in the route, even if later addresses are known. This may be useful if you are caught behind a firewall. +.ip DoubleBounceAddress=\fIerror-address\fP +[no short name] +If an error occurs when sending an error message, +send the error report +(termed a +.q "double bounce" +because it is an error +.q bounce +that occurs when trying to send another error +.q bounce ) +to the indicated address. +If not set, defaults to +.q postmaster . .ip EightBitMode=\fIaction\fP [8] Set handling of eight-bit data. @@ -4643,6 +4956,42 @@ don't connect immediately. This requires that queueing be compiled in, since it will depend on a queue run process to actually send the mail. +.ip HostsFile=\fIpath\fP +[no short name] +The path to the hosts database, +normally +.q /etc/hosts . +This option is only consulted when sendmail +is canonifying addresses, +and then only when +.q files +is in the +.q hosts +service switch entry. +In particular, this file is +.i never +used when looking up host addresses; +that is under the control of the system +.i gethostbyname (3) +routine. +.ip HostStatusDirectory=\fIpath\fP +[no short name] +The location of the long term host status information. +When set, +information about the status of hosts +(e.g., host down or not accepting connections) +will be shared between all +.i sendmail +processes; +normally, this information is only held within a single queue run. +This option requires a connection cache of at least 1 to function. +If the option begins with a leading `/', +it is an absolute pathname; +otherwise, +it is relative to the mail queue directory. +A suggested value for sites desiring persistent host status is +.q \&.hoststat +(i.e., a subdirectory of the queue directory). .ip IgnoreDots [i] Ignore dots in incoming messages. @@ -4676,6 +5025,16 @@ for a matching entry in the GECOS field. This also requires that MATCHGECOS be turned on during compilation. This option is not recommended. +.ip MaxDaemonChildren=\fIN\fP +[no short name] +If set, +.i sendmail +will refuse connections when it has more than +.i N +children processing incoming mail. +This does not limit the number of outgoing connections. +If not set, there is no limit to the number of children -- +that is, the system load averaging controls this. .ip MaxHopCount=\fIN\fP [h] The maximum hop count. @@ -4690,6 +5049,11 @@ This option specifies how long host status information will be retained. For example, if a host is found to be down, connections to that host will not be retried for this interval. The units default to minutes. +.ip MaxMessageSize=\fIN\fP +[no short name] +Specify the maximum message size +to be advertised in the ESMTP EHLO response. +Messages larger than this will be rejected. .ip MaxQueueRunSize=\fIN\fP [no short name] The maximum number of jobs that will be processed @@ -4709,11 +5073,6 @@ jobs that happen to fall late in the queue directory. [m] Send to me too, even if I am in an alias expansion. -.ip MaxMessageSize=\fIN\fP -[no short name] -Specify the maximum message size -to be advertised in the ESMTP EHLO response. -Messages larger than this will be rejected. .ip MinFreeBlocks=\fIN\fP [b] Insist on at least @@ -4733,10 +5092,18 @@ This is intended to allow you to get responsiveness by processing the queue fairly frequently without thrashing your system by trying jobs too often. The default units are minutes. +.ip MustQuoteChars=\fIs\fP +[no short name] +Sets the list of characters that must be quoted if used in a full name +that is in the phrase part of a ``phrase <address>'' syntax. +The default is ``\'.''. +The characters ``@,;:\e()[]'' are always added to this list. .ip NoRecipientAction [no short name] The action to take when you receive a message that has no valid -recipient headers (To:, Cc:, Bcc:). +recipient headers (To:, Cc:, Bcc:, or Apparently-To: \(em +the last included for back compatibility with old +.i sendmail s). It can be .b None to pass the message on unmodified, @@ -4871,16 +5238,29 @@ used for sorting the queue. Only the first character of the value is used. Legal values are .q host -(to order by the name of the first host name of the first recipient) +(to order by the name of the first host name of the first recipient), +.q time +(to order by the submission time), and .q priority -(to order strictly by message priority). +(to order by message priority). Host ordering makes better use of the connection cache, but may tend to process low priority messages that go to a single host over high priority messages that go to several hosts; it probably shouldn't be used on slow network links. +Time ordering is almost always a bad idea, +since it allows large, bulk mail to go out +before smaller, personal mail, +but may have applicability on some hosts with very fast connections. Priority ordering is the default. +.ip QueueTimeout=\fItimeout\fP +[T] +A synonym for +.q Timeout.queuereturn . +Use that form instead of the +.q QueueTimeout +form. .ip ResolverOptions=\fIoptions\fP [I] Set resolver options. @@ -4921,61 +5301,49 @@ if the method is listed in the service switch entry for the .q hosts service. -.ip SmtpGreetingMessage=\fImessage\fP -[$e macro] -The message printed when the SMTP server starts up. -Defaults to -.q "$j Sendmail $v ready at $b". -.ip Timeout.\fItype\fP=\|\fItimeout\fP -[r; subsumes old T option as well] -Set timeout values. -The actual timeout is indicated by the -.i type . -The recognized timeouts and their default values, and their -minimum values specified in RFC 1123 section 5.3.2 are: -.(b -.ta \w'datafinal'u+3n -initial wait for initial greeting message [5m, 5m] -helo reply to HELO or EHLO command [5m, none] -mail reply to MAIL command [10m, 5m] -rcpt reply to RCPT command [1h, 5m] -datainit reply to DATA command [5m, 2m] -datablock data block read [1h, 3m] -datafinal reply to final ``.'' in data [1h, 10m] -rset reply to RSET command [5m, none] -quit reply to QUIT command [2m, none] -misc reply to NOOP and VERB commands [2m, none] -ident IDENT protocol timeout [30s, none] -fileopen\(dg timeout on opening .forward and :include: files [60s, none] -command\(dg command read [1h, 5m] -queuereturn\(dg how long until a message is returned [5d, 5d] -queuewarn\(dg how long until a warning is sent [none, none] -.)b -All but those marked with a dagger (\(dg) -apply to client SMTP. -If the message is submitted using the -.sm NOTIFY +.ip RunAsUser=\fIuser\fP +[no short name] +The +.i user +parameter may be a user name +(looked up in +.i /etc/passwd ) +or a numeric user id; +either form can have +.q ":group" +attached +(where group can be numeric or symbolic). +If set to a non-zero (non-root) value, +.i sendmail +will change to this user id shortly after startup\**. +.(f +\**When running as a daemon, +it changes to this user after accepting a connection +but before reading any .sm SMTP -extension, -warning messages will only be sent if -.sm NOTIFY=DELAY -is specified. -The queuereturn and queuewarn timeouts -can be further qualified with a tag based on the Precedence: field -in the message; -they must be one of -.q urgent -(indicating a positive non-zero precedence) -.q normal -(indicating a zero precedence), or -.q non-urgent -(indicating negative precedences). -For example, setting -.q Timeout.queuewarn.urgent=1h -sets the warning timeout for urgent messages only -to one hour. -The default if no precedence is indicated -is to set the timeout for all precedences. +commands. +.)f +This avoids a certain class of security problems. +However, this means that all +.q \&.forward +and +.q :include: +files must be readable by the indicated +.i user , +and on systems that don't support the saved uid bit properly, +all files to be written must be writable by +.i user +and all programs will be executed by +.i user . +It is also incompatible with the +.b SafeFileEnvironment +option. +In other words, it may not actually add much to security on an average system, +and may in fact detract from security +(because other file permissions must be loosened). +However, it should be useful on firewalls and other +places where users don't have accounts and the aliases file is +well constrained. .ip RecipientFactor=\fIfact\fP [y] The indicated @@ -5004,6 +5372,29 @@ its priority will be decreased by the indicated value. In most environments this should be positive, since hosts that are down are all too often down for a long time. Defaults to 90000. +.ip SafeFileEnvironment=\fIdir\fP +[no short name] +If this option is set, +.i sendmail +will do a +.i chroot (2) +call into the indicated +.i dir ectory +before doing any file writes. +If the file name specified by the user begins with +.i dir , +that partial path name will be stripped off before writing, +so (for example) +if the SafeFileEnvironment variable is set to +.q /safe +then aliases of +.q /safe/logs/file +and +.q /logs/file +actually indicate the same file. +Additionally, if this option is set, +.i sendmail +refuses to deliver to symbolic links. .ip SaveFromLine [f] Save @@ -5016,6 +5407,11 @@ and discarded. [j] If set, send error messages in MIME format (see RFC1521 and RFC1344 for details). +If disabled, +.i sendmail +will not return the DSN keyword in response to an EHLO +and will not do Delivery Status Notification processing as described in +RFC1891. .ip ServiceSwitchFile=\fIfilename\fP [no short name] If your host operating system has a service switch abstraction @@ -5055,6 +5451,43 @@ The default file is [7] Strip input to seven bits for compatibility with old systems. This shouldn't be necessary. +.ip SingleLineFromHeader +[no short name] +If set, From: lines that have embedded newlines are unwrapped +onto one line. +This is to get around a botch in Lotus Notes +that apparently cannot understand legally wrapped RFC822 headers. +.ip SingleThreadDelivery +[no short name] +If set, a client machine will never try to open two SMTP connections +to a single server machine at the same time, +even in different processes. +That is, if another +.i sendmail +is already talking to some host a new +.i sendmail +will not open another connection. +This property is of mixed value; +although this reduces the load on the other machine, +it can cause mail to be delayed +(for example, if one +.i sendmail +is delivering a huge message, other +.i sendmail s +won't be able to send even small messages). +Also, it requires another file descriptor +(for the lock file) +per connection, so you may have to reduce the +.b ConnectionCacheSize +option to avoid running out of per-process file descriptors. +Requires the +.b HostStatusDirectory +option. +.ip SmtpGreetingMessage=\fImessage\fP +[$e macro] +The message printed when the SMTP server starts up. +Defaults to +.q "$j Sendmail $v ready at $b". .ip StatusFile=\fIfile\fP [S] Log summary statistics in the named @@ -5083,6 +5516,57 @@ be set. The file mode for queue files. It is interpreted in octal by default. Defaults to 0600. +.ip Timeout.\fItype\fP=\|\fItimeout\fP +[r; subsumes old T option as well] +Set timeout values. +The actual timeout is indicated by the +.i type . +The recognized timeouts and their default values, and their +minimum values specified in RFC 1123 section 5.3.2 are: +.(b +.ta \w'datafinal'u+3n +initial wait for initial greeting message [5m, 5m] +helo reply to HELO or EHLO command [5m, none] +mail reply to MAIL command [10m, 5m] +rcpt reply to RCPT command [1h, 5m] +datainit reply to DATA command [5m, 2m] +datablock data block read [1h, 3m] +datafinal reply to final ``.'' in data [1h, 10m] +rset reply to RSET command [5m, none] +quit reply to QUIT command [2m, none] +misc reply to NOOP and VERB commands [2m, none] +ident IDENT protocol timeout [30s, none] +fileopen\(dg timeout on opening .forward and :include: files [60s, none] +command\(dg command read [1h, 5m] +queuereturn\(dg how long until a message is returned [5d, 5d] +queuewarn\(dg how long until a warning is sent [none, none] +hoststatus\(dg how long until host status is ``stale'' [30m, none] +.)b +All but those marked with a dagger (\(dg) +apply to client SMTP. +If the message is submitted using the +.sm NOTIFY +.sm SMTP +extension, +warning messages will only be sent if +.sm NOTIFY=DELAY +is specified. +The queuereturn and queuewarn timeouts +can be further qualified with a tag based on the Precedence: field +in the message; +they must be one of +.q urgent +(indicating a positive non-zero precedence) +.q normal +(indicating a zero precedence), or +.q non-urgent +(indicating negative precedences). +For example, setting +.q Timeout.queuewarn.urgent=1h +sets the warning timeout for urgent messages only +to one hour. +The default if no precedence is indicated +is to set the timeout for all precedences. .ip TimeZoneSpec=\fItzinfo\fP [t] Set the local time zone info to @@ -5128,6 +5612,15 @@ Defaults to .q "From $g $d" . Don't change this unless your system uses a different UNIX mailbox format (very unlikely). +.ip UnsafeGroupWrites +[no short name] +If set, +:include: and .forward files that are group writable are considered +.q unsafe , +that is, +they cannot reference programs or write directly to files. +World writable :include: and .forward files +are always unsafe.. .ip UseErrorsTo [l] If there is an @@ -5141,6 +5634,16 @@ This option is disrecommended and deprecated. .ip UserDatabaseSpec=\fIudbspec\fP [U] The user database specification. +.ip UserSubmission +[no short name] +This is an initial submission directly from a Mail User Agent. +This can be set in the configuration file if you have +MUAs that don't pass the +.b \-U +flag or use the +XUSR +ESMTP extension, +but some relayed mail may get inappropriately rewritten if you do. .ip Verbose [v] Run in verbose mode. @@ -5342,7 +5845,7 @@ to the list of recognized vendors by editing the routine .i setvendor in .i conf.c . -Please send e-mail to sendmail@CS.Berkeley.EDU +Please send e-mail to sendmail@Sendmail.ORG to register your vendor dialect. .)f You may use @@ -5395,16 +5898,20 @@ is specified, the replaces the input. Otherwise, the input is unchanged. .pp -During replacement of either a map value or default -the string +The +.i arguments +are passed to the map for arbitrary use. +Most map classes can interpolate these arguments +into their values using the syntax .q %\fIn\fP (where .i n is a digit) -is replaced by the corresponding +to indicate the corresponding .i argument . -Argument zero -is always the database key. +Argument +.q %0 +indicates the database key. For example, the rule .(b .ta 1.5i @@ -5419,6 +5926,9 @@ The database might contain records like: decvax %1@%0.DEC.COM research %1@%0.ATT.COM .)b +Note that +.i default +clauses never do this mapping. .pp The built in map with both name and class .q host @@ -5476,6 +5986,16 @@ Hesiod lookups. must be compiled with .b HESIOD defined. +.ip ldapx +LDAP X500 directory lookups. +.i Sendmail +must be compiled with +.b LDAPMAP +defined. +The map supports most of the standard arguments +and most of the command line arguments of the +.i ldapsearch +program. .ip netinfo NeXT NetInfo lookups. .i Sendmail @@ -5648,9 +6168,15 @@ and the default is still taken if the match fails. .ip "\-k\fIkeycol\fP" The key column name (for NIS+) or number (for text lookups). +For LDAP maps this is a filter string +passed to printf with a %s where the string to be +.q "mapped" +is inserted. .ip "\-v\fIvalcol\fP" The value column name (for NIS+) or number (for text lookups). +For LDAP maps this is the name of the +attribute to be returned. .ip "\-z\fIdelim\fP" The column delimiter (for text lookups). It can be a single character or one of the special strings @@ -5660,6 +6186,28 @@ or to indicate newline or tab respectively. If omitted entirely, the column separator is any sequence of whitespace. +.ip "\-t" +Normally, when a map attempts to do a lookup +and the server fails +(e.g., +.i sendmail +couldn't contact any name server; +this is +.i not +the same as an entry not being found in the map), +the message being processed is queued for future processing. +The +.b \-t +flag turns off this behaviour, +letting the temporary failure (server down) +act as though it were a permanent failure (entry not found). +It is particularly useful for DNS lookups, +where someone else's misconfigured name server can cause problems +on your machine. +However, care must be taken to ensure that you don't bounce mail +that would be resolved correctly if you tried again. +A common strategy is to forward such mail +to another, possibly better connected, mail server. .ip "\-s\fIspacesub\fP For the dequote map only, the character to use to replace space characters @@ -5924,6 +6472,10 @@ program used on YP masters. Compile in support for NIS+. .ip NETINFO Compile in support for NetInfo (NeXT stations). +.ip LDAPMAP +Compile in support for LDAP X500 queries. +Requires libldap and liblber +from the Umich LDAP 3.2 or 3.3 release. .ip HESIOD Compile in support for Hesiod. .ip _PATH_SENDMAILCF @@ -6003,7 +6555,7 @@ line in sendmail.cf). .ip "MAXUSERENVIRON [100]" The maximum number of items in the user environment that will be passed to subordinate mailers. -.ip "MAXMXHOSTS [20]" +.ip "MAXMXHOSTS [100]" The maximum number of MX records we will accept for any single host. .ip "MAXALIASDB [12]" The maximum number of alias databases that can be open at any time. @@ -6067,12 +6619,12 @@ you can set this flag to turn off special processing of UNIX-style .q "From " lines. -.ip QUEUE +.ip QUEUE\(dg This flag should be set to compile in the queueing code. If this is not set, mailers must accept the mail immediately or it will be returned to the sender. -.ip SMTP +.ip SMTP\(dg If set, the code to handle user and server SMTP will be compiled in. This is only necessary if your machine has some mailer @@ -6604,7 +7156,7 @@ If you are porting to a new environment you may need to add some new tweaks.\** .(f \**If you do, please send updates to -sendmail@CS.Berkeley.EDU. +sendmail@Sendmail.ORG. .)f .sh 2 "Configuration in src/daemon.c" .pp @@ -6815,7 +7367,7 @@ for debugging. .pp The .b \-O -flag simplies setting long-form options. +flag implies setting long-form options. .sh 2 "Enhanced Command Line Flags" .pp The @@ -6856,7 +7408,7 @@ Several new options have been added, many to support new features, others to allow tuning that was previously available only by recompiling. -They are described in detail in Section 5.1.5. +They are described in detail in Section 5.6. Briefly, .nr ii 0.5i .ip b @@ -7134,7 +7686,7 @@ I appreciate their contribution as well. .pp Special thanks are reserved for Michael Corrigan and Christophe Wolfhugel, who besides being wonderful guinea pigs and contributors -have also consented to be added to the ``sendmail@CS.Berkeley.EDU'' list +have also consented to be added to the ``sendmail@Sendmail.ORG'' list and, by answering the bulk of the questions sent to that list, have freed me up to do other work. .++ A @@ -7153,7 +7705,8 @@ Operation modes are: m Deliver mail (default) s Speak SMTP on input side a\(dg ``Arpanet'' mode (get envelope sender information from header) -d Run as a daemon +d Run as a daemon in background +D Run as a daemon in foreground t Run in test mode v Just verify addresses, don't collect or deliver i Initialize the alias database @@ -7195,6 +7748,21 @@ MAXHOP throws away the message with an error. .ip \-n Don't do aliasing or forwarding. +.ip "\-N \fInotifications\fP" +Tag all addresses being sent as wanting the indicated +.i notifications , +which consists of the word +.q NEVER +or a comma-separated list of +.q SUCCESS , +.q FAILURE , +and +.q DELAY +for successful delivery, +failure, +and a message that is stuck in a queue somewhere. +The default is +.q FAILURE,DELAY . .ip "\-r\ \fIaddr\fP" An obsolete form of .b \-f . @@ -7255,6 +7823,16 @@ to limit based on sender. A particular queued job is accepted if one of the corresponding addresses contains the indicated .i string . +.ip "\-R ret" +What information you want returned if the message bounces; +.i ret +can be +.q HDRS +for headers only or +.q FULL +for headers plus body. +This is a request only; +the other end is not required to honor the parameter. .ip \-t Read the header for .q To: , @@ -7267,6 +7845,15 @@ The line will be deleted before sending. Any addresses in the argument vector will be deleted from the send list. +.ip "\-U" +Indicate that this is an initial User Agent submission. +In future releases, sendmail may complain about syntactically invalid messages +rather than fixing them when this flag is not set. +.ip "\-V envid" +The indicated +.i envid +is passed with the envelope of the message +and returned if the message bounces. .ip "\-X \fIlogfile\fP" Log all traffic in and out of .i sendmail @@ -7561,9 +8148,9 @@ A transcript of the current session. .\".sp .\".sz 10 .\"Eric Allman -.\"Britton-Lee, Inc. +.\"InReference, Inc. .\".sp -.\"Version 8.70 +.\"Version 8.100 .\".ce 0 .bp 2 .rs diff --git a/usr.sbin/sendmail/mailstats/Makefile b/usr.sbin/sendmail/mailstats/Makefile index d6a04f0bdc1..350cf5a2327 100644 --- a/usr.sbin/sendmail/mailstats/Makefile +++ b/usr.sbin/sendmail/mailstats/Makefile @@ -1,8 +1,9 @@ -# @(#)Makefile 8.1 (Berkeley) 6/7/93 +# $OpenBSD: Makefile,v 1.2 1996/12/14 21:16:45 downsj Exp $ +# @(#)Makefile 8.2 (Berkeley) 9/21/96 PROG= mailstats +MAN= mailstats.8 CFLAGS+=-I${.CURDIR}/../src -NOMAN= noman .include "../../Makefile.inc" .include <bsd.prog.mk> diff --git a/usr.sbin/sendmail/mailstats/Makefile.dist b/usr.sbin/sendmail/mailstats/Makefile.dist new file mode 100644 index 00000000000..5bf0f2048d8 --- /dev/null +++ b/usr.sbin/sendmail/mailstats/Makefile.dist @@ -0,0 +1,78 @@ +# +# This Makefile is designed to work on the old "make" program. It does +# not use the obj subdirectory. It also does not install documentation +# automatically -- think of it as a quick start for sites that have the +# old make program (I recommend that you get and port the new make if you +# are going to be doing any signficant work on sendmail). +# +# @(#)Makefile.dist 8.2 (Berkeley) 9/21/96 +# + +# use O=-O (usual) or O=-g (debugging) +O= -O + +# location of sendmail source directory +SRCDIR= ../src + +# environment definitions (e.g., -D_AIX3) +ENVDEF= + +# see also conf.h for additional compilation flags + +# include directories +INCDIRS=-I${SRCDIR} -I/usr/sww/include + +# loader options +LDOPTS= + +# library directories +LIBDIRS=-L/usr/sww/lib + +# libraries required on your system +LIBS= + +# location of mailstats binary (usually /usr/sbin or /usr/etc) +BINDIR= ${DESTDIR}/usr/sbin + +# additional .o files needed +OBJADD= + +################### end of user configuration flags ###################### + +CFLAGS= -I. $O ${INCDIRS} ${ENVDEF} + +OBJS= mailstats.o ${OBJADD} + +LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq +BINOWN= bin +BINGRP= bin +BINMODE=555 + +ALL= mailstats mailstats.0 + +all: ${ALL} + +mailstats: ${BEFORE} ${OBJS} + ${CC} -o mailstats ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS} + +#NROFF= nroff -h +NROFF= groff -Tascii +MANDOC= -mandoc + +mailstats.0: mailstats.8 + ${NROFF} ${MANDOC} mailstats.8 > mailstats.0 + +install: install-mailstats install-docs + +install-mailstats: mailstats + install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} mailstats ${BINDIR} + +# doesn't actually install them -- you may want to install pre-nroff versions +install-docs: mailstats.0 + +clean: + rm -f ${OBJS} mailstats mailstats.0 + +# dependencies +# gross overkill, and yet still not quite enough.... +${OBJS}: ${SRCDIR}/sendmail.h ${SRCDIR}/mailstats.h ${SRCDIR}/conf.h diff --git a/usr.sbin/sendmail/mailstats/mailstats.c b/usr.sbin/sendmail/mailstats/mailstats.c index 97ec33be7e9..83082bacb75 100644 --- a/usr.sbin/sendmail/mailstats/mailstats.c +++ b/usr.sbin/sendmail/mailstats/mailstats.c @@ -40,9 +40,10 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mailstats.c 8.4 (Berkeley) 8/14/94"; +static char sccsid[] = "@(#)mailstats.c 8.8 (Berkeley) 9/25/96"; #endif /* not lint */ +#define NOT_SENDMAIL #include <sendmail.h> #include <mailstats.h> #include <pathnames.h> @@ -91,7 +92,8 @@ main(argc, argv) case '?': default: usage: - fputs("usage: mailstats [-C cffile] [-f stfile]\n", stderr); + fputs("usage: mailstats [-C cffile] [-f stfile] -o\n", + stderr); exit(EX_USAGE); } } @@ -189,13 +191,24 @@ main(argc, argv) exit (EX_OSFILE); } - if ((fd = open(sfile, O_RDONLY)) < 0) { + if ((fd = open(sfile, O_RDONLY)) < 0 || + (i = read(fd, &stat, sizeof stat)) < 0) + { fputs("mailstats: ", stderr); perror(sfile); exit(EX_NOINPUT); } - if (read(fd, &stat, sizeof(stat)) != sizeof(stat) || - stat.stat_size != sizeof(stat)) + if (i == 0) + { + sleep(1); + i = read(fd, &stat, sizeof stat); + if (i == 0) + { + bzero((ARBPTR_T) &stat, sizeof stat); + (void) time(&stat.stat_itime); + } + } + else if (i != sizeof stat || stat.stat_size != sizeof(stat)) { fputs("mailstats: file size changed.\n", stderr); exit(EX_OSERR); diff --git a/usr.sbin/sendmail/makemap/Makefile b/usr.sbin/sendmail/makemap/Makefile index a8592fec10a..94f11f9c061 100644 --- a/usr.sbin/sendmail/makemap/Makefile +++ b/usr.sbin/sendmail/makemap/Makefile @@ -1,8 +1,9 @@ +# $OpenBSD: Makefile,v 1.2 1996/12/14 21:16:49 downsj Exp $ # @(#)Makefile 8.1 (Berkeley) 6/7/93 PROG= makemap MAN= makemap.8 -CFLAGS+=-I${.CURDIR}/../src -DNDBM -DNEWDB +CFLAGS+=-I${.CURDIR}/../src -DNEWDB .include "../../Makefile.inc" .include <bsd.prog.mk> diff --git a/usr.sbin/sendmail/makemap/Makefile.dist b/usr.sbin/sendmail/makemap/Makefile.dist new file mode 100644 index 00000000000..a812b585494 --- /dev/null +++ b/usr.sbin/sendmail/makemap/Makefile.dist @@ -0,0 +1,85 @@ +# +# This Makefile is designed to work on the old "make" program. It does +# not use the obj subdirectory. It also does not install documentation +# automatically -- think of it as a quick start for sites that have the +# old make program (I recommend that you get and port the new make if you +# are going to be doing any signficant work on sendmail). +# +# @(#)Makefile.dist 8.4 (Berkeley) 9/1/95 +# + +# use O=-O (usual) or O=-g (debugging) +O= -O + +# location of sendmail source directory +SRCDIR= ../src + +# define the database mechanisms available for map & alias lookups: +# -DNDBM -- use new DBM +# -DNEWDB -- use new Berkeley DB +# The really old (V7) DBM library is no longer supported. +# +DBMDEF= -DNDBM -DNEWDB + +# environment definitions (e.g., -D_AIX3) +ENVDEF= + +# see also conf.h for additional compilation flags + +# include directories +INCDIRS=-I${SRCDIR} -I/usr/sww/include + +# loader options +LDOPTS= + +# library directories +LIBDIRS=-L/usr/sww/lib + +# libraries required on your system +LIBS= -ldb -ldbm + +# location of makemap binary (usually /usr/sbin or /usr/etc) +BINDIR= ${DESTDIR}/usr/sbin + +# additional .o files needed +OBJADD= + +################### end of user configuration flags ###################### + +CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF} + +OBJS= makemap.o ${OBJADD} + +LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq +BINOWN= bin +BINGRP= bin +BINMODE=555 + +ALL= makemap makemap.0 + +all: ${ALL} + +makemap: ${BEFORE} ${OBJS} + ${CC} -o makemap ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS} + +#NROFF= nroff -h +NROFF= groff -Tascii +MANDOC= -mandoc + +makemap.0: makemap.8 + ${NROFF} ${MANDOC} makemap.8 > makemap.0 + +install: install-makemap install-docs + +install-makemap: makemap + install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} makemap ${BINDIR} + +# doesn't actually install them -- you may want to install pre-nroff versions +install-docs: makemap.0 + +clean: + rm -f ${OBJS} makemap makemap.0 + +# dependencies +# gross overkill, and yet still not quite enough.... +${OBJS}: ${SRCDIR}/conf.h diff --git a/usr.sbin/sendmail/makemap/makemap.c b/usr.sbin/sendmail/makemap/makemap.c index 371b229a217..2e289a81641 100644 --- a/usr.sbin/sendmail/makemap/makemap.c +++ b/usr.sbin/sendmail/makemap/makemap.c @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)makemap.c 8.14 (Berkeley) 11/5/95"; +static char sccsid[] = "@(#)makemap.c 8.19 (Berkeley) 11/18/96"; #endif /* not lint */ #include <stdio.h> @@ -45,6 +45,7 @@ static char sccsid[] = "@(#)makemap.c 8.14 (Berkeley) 11/5/95"; #ifndef ISC_UNIX # include <sys/file.h> #endif +#define NOT_SENDMAIL #include "useful.h" #include "conf.h" @@ -95,6 +96,8 @@ main(argc, argv) int lineno; int st; int mode; + int putflags; + long dbcachesize = 1024 * 1024; enum type type; int fd; union @@ -110,6 +113,7 @@ main(argc, argv) union dbent key, val; #ifdef NEWDB BTREEINFO bti; + HASHINFO hinfo; #endif char ibuf[BUFSIZE]; char fbuf[MAXNAME]; @@ -120,7 +124,12 @@ main(argc, argv) progname = argv[0]; - while ((opt = getopt(argc, argv, "Ndforv")) != EOF) +#ifdef FFR_CFLAG +#define OPTIONS "Nc:dforv" +#else +#define OPTIONS "Ndforv" +#endif + while ((opt = getopt(argc, argv, OPTIONS)) != EOF) { switch (opt) { @@ -128,6 +137,12 @@ main(argc, argv) inclnull = TRUE; break; +#ifdef FFR_CFLAG + case 'c': + dbcachesize = atol(optarg); + break; +#endif + case 'd': allowdups = TRUE; break; @@ -187,7 +202,11 @@ main(argc, argv) switch (type) { case T_ERR: +#ifdef FFR_CFLAG + fprintf(stderr, "Usage: %s [-N] [-c cachesize] [-d] [-f] [-o] [-r] [-v] type mapname\n", progname); +#else fprintf(stderr, "Usage: %s [-N] [-d] [-f] [-o] [-r] [-v] type mapname\n", progname); +#endif exit(EX_USAGE); case T_UNKNOWN: @@ -211,20 +230,34 @@ main(argc, argv) bzero(&bti, sizeof bti); if (allowdups) bti.flags |= R_DUP; + if (allowdups || allowreplace) + putflags = 0; + else + putflags = R_NOOVERWRITE; break; case T_HASH: + bzero(&hinfo, sizeof hinfo); + if (allowreplace) + putflags = 0; + else + putflags = R_NOOVERWRITE; + break; #endif #ifdef NDBM case T_DBM: -#endif if (allowdups) { fprintf(stderr, "%s: Type %s does not support -d (allow dups)\n", progname, typename); exit(EX_UNAVAILABLE); } + if (allowreplace) + putflags = DBM_REPLACE; + else + putflags = DBM_INSERT; break; +#endif } /* @@ -279,7 +312,11 @@ main(argc, argv) #ifdef NEWDB case T_HASH: - dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL); + /* tweak some parameters for performance */ + hinfo.nelem = 4096; + hinfo.cachesize = dbcachesize; + + dbp.db = dbopen(mapname, mode, 0644, DB_HASH, &hinfo); if (dbp.db != NULL) { # if OLD_NEWDB @@ -291,6 +328,9 @@ main(argc, argv) break; case T_BTREE: + /* tweak some parameters for performance */ + bti.cachesize = dbcachesize; + dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); if (dbp.db != NULL) { @@ -386,16 +426,14 @@ main(argc, argv) { #ifdef NDBM case T_DBM: - st = dbm_store(dbp.dbm, key.dbm, val.dbm, - allowreplace ? DBM_REPLACE : DBM_INSERT); + st = dbm_store(dbp.dbm, key.dbm, val.dbm, putflags); break; #endif #ifdef NEWDB case T_BTREE: case T_HASH: - st = (*dbp.db->put)(dbp.db, &key.db, &val.db, - allowreplace ? 0 : R_NOOVERWRITE); + st = (*dbp.db->put)(dbp.db, &key.db, &val.db, putflags); break; #endif } diff --git a/usr.sbin/sendmail/praliases/Makefile b/usr.sbin/sendmail/praliases/Makefile index 18015f888be..d3b4478f1fa 100644 --- a/usr.sbin/sendmail/praliases/Makefile +++ b/usr.sbin/sendmail/praliases/Makefile @@ -1,7 +1,8 @@ +# $OpenBSD: Makefile,v 1.3 1996/12/14 21:16:51 downsj Exp $ # @(#)Makefile 8.1 (Berkeley) 6/7/93 PROG= praliases -CFLAGS+=-I${.CURDIR}/../src +CFLAGS+=-I${.CURDIR}/../src -DNEWDB MAN= praliases.1 .include "../../Makefile.inc" diff --git a/usr.sbin/sendmail/praliases/Makefile.dist b/usr.sbin/sendmail/praliases/Makefile.dist new file mode 100644 index 00000000000..093f6abbe53 --- /dev/null +++ b/usr.sbin/sendmail/praliases/Makefile.dist @@ -0,0 +1,85 @@ +# +# This Makefile is designed to work on the old "make" program. It does +# not use the obj subdirectory. It also does not install documentation +# automatically -- think of it as a quick start for sites that have the +# old make program (I recommend that you get and port the new make if you +# are going to be doing any signficant work on sendmail). +# +# @(#)Makefile.dist 8.2 (Berkeley) 9/21/96 +# + +# use O=-O (usual) or O=-g (debugging) +O= -O + +# location of sendmail source directory +SRCDIR= ../src + +# define the database mechanisms available for map & alias lookups: +# -DNDBM -- use new DBM +# -DNEWDB -- use new Berkeley DB +# The really old (V7) DBM library is no longer supported. +# +DBMDEF= -DNDBM -DNEWDB + +# environment definitions (e.g., -D_AIX3) +ENVDEF= + +# see also conf.h for additional compilation flags + +# include directories +INCDIRS=-I${SRCDIR} -I/usr/sww/include/db + +# loader options +LDOPTS= + +# library directories +LIBDIRS=-L/usr/sww/lib + +# libraries required on your system +LIBS= -ldb -ldbm + +# location of praliases binary (usually /usr/sbin or /usr/etc) +BINDIR= ${DESTDIR}/usr/sbin + +# additional .o files needed +OBJADD= + +################### end of user configuration flags ###################### + +CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF} + +OBJS= praliases.o ${OBJADD} + +LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq +BINOWN= bin +BINGRP= bin +BINMODE=555 + +ALL= praliases praliases.0 + +all: ${ALL} + +praliases: ${BEFORE} ${OBJS} + ${CC} -o praliases ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS} + +#NROFF= nroff -h +NROFF= groff -Tascii +MANDOC= -mandoc + +praliases.0: praliases.8 + ${NROFF} ${MANDOC} praliases.8 > praliases.0 + +install: install-praliases install-docs + +install-praliases: praliases + install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} praliases ${BINDIR} + +# doesn't actually install them -- you may want to install pre-nroff versions +install-docs: praliases.0 + +clean: + rm -f ${OBJS} praliases praliases.0 + +# dependencies +# gross overkill, and yet still not quite enough.... +${OBJS}: ${SRCDIR}/conf.h diff --git a/usr.sbin/sendmail/praliases/praliases.c b/usr.sbin/sendmail/praliases/praliases.c index 2c22279205e..2c1cc0a07de 100644 --- a/usr.sbin/sendmail/praliases/praliases.c +++ b/usr.sbin/sendmail/praliases/praliases.c @@ -39,10 +39,11 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)praliases.c 8.3 (Berkeley) 3/6/94"; +static char sccsid[] = "@(#)praliases.c 8.4 (Berkeley) 9/25/96"; #endif /* not lint */ #include <ndbm.h> +#define NOT_SENDMAIL #include <sendmail.h> #ifdef NEWDB #include <db.h> diff --git a/usr.sbin/sendmail/smrsh/Makefile.dist b/usr.sbin/sendmail/smrsh/Makefile.dist new file mode 100644 index 00000000000..52b4a20baab --- /dev/null +++ b/usr.sbin/sendmail/smrsh/Makefile.dist @@ -0,0 +1,76 @@ +# +# This Makefile is designed to work on the old "make" program. It does +# not use the obj subdirectory. It also does not install documentation +# automatically -- think of it as a quick start for sites that have the +# old make program (I recommend that you get and port the new make if you +# are going to be doing any signficant work on sendmail). +# +# @(#)Makefile.dist 8.2 (Berkeley) 9/25/96 +# + +# use O=-O (usual) or O=-g (debugging) +O= -O + +# location of sendmail source directory +SRCDIR= ../src + +# environment definitions (e.g., -D_AIX3) +ENVDEF= + +# include directories +INCDIRS=-I${SRCDIR} -I/usr/sww/include + +# loader options +LDOPTS= + +# library directories +LIBDIRS=-L/usr/sww/lib + +# libraries required on your system +LIBS= + +# location of smrsh binary (usually /usr/libexec or /usr/etc) +BINDIR= ${DESTDIR}/usr/libexec + +# additional .o files needed +OBJADD= + +################### end of user configuration flags ###################### + +CFLAGS= -I. $O ${INCDIRS} ${ENVDEF} + +OBJS= smrsh.o ${OBJADD} + +BINOWN= bin +BINGRP= bin +BINMODE=555 + +ALL= smrsh smrsh.0 + +all: ${ALL} + +smrsh: ${BEFORE} ${OBJS} + ${CC} -o smrsh ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS} + +# Which *roff program has -mandoc support +NROFF= groff -Tascii +#NROFF= nroff -h +MANDOC= -mandoc + +smrsh.0: smrsh.8 + ${NROFF} ${MANDOC} smrsh.8 > smrsh.0 + +install: install-smrsh install-docs + +install-smrsh: smrsh + install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} smrsh ${BINDIR} + +# doesn't actually install them -- you may want to install pre-nroff versions +install-docs: smrsh.0 + +clean: + rm -f ${OBJS} smrsh smrsh.0 + +# dependencies +# gross overkill, and yet still not quite enough.... +${OBJS}: ${SRCDIR}/conf.h diff --git a/usr.sbin/sendmail/src/READ_ME b/usr.sbin/sendmail/src/READ_ME index 264b2ebaac9..72e9a18c36d 100644 --- a/usr.sbin/sendmail/src/READ_ME +++ b/usr.sbin/sendmail/src/READ_ME @@ -1,4 +1,4 @@ -# Copyright (c) 1983, 1995 Eric P. Allman +# Copyright (c) 1983, 1995, 1996 Eric P. Allman # Copyright (c) 1988 The Regents of the University of California. # All rights reserved. # @@ -30,7 +30,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)READ_ME 8.113 (Berkeley) 11/29/95 +# @(#)READ_ME 8.132 (Berkeley) 12/1/96 # This directory contains the source files for sendmail. @@ -144,46 +144,60 @@ There are several database formats that can be used for the alias files and for general maps. When used for alias files they interact in an attempt to be back compatible. -The three options are NEWDB (the new Berkeley DB package), NDBM (the -older DBM implementation -- the very old V7 implementation is no -longer supported), and NIS (Network Information Services). Used alone -these just include the support they indicate. [If you are using NEWDB, -get the latest version from FTP.CS.Berkeley.EDU in /ucb/4bsd/db.tar.Z -(or db.tar.gz). DO NOT use the version from the Net2 distribution! -However, if you are on BSD/386 or 386BSD-based systems, use the one -that already exists on your system. You may need to #define OLD_NEWDB -1 to do this.] - -[NOTE WELL: it is CRITICAL that you remove ndbm.o from libdb.a and -ndbm.h from the appropriate include directories if you want to get -ndbm support. These files OVERRIDE calls to ndbm routines -- in -particular, if you leave ndbm.h in, you can find yourself using -the new db package even if you don't define NEWDB.] +The options are: + +NEWDB The new Berkeley DB package. Some systems (e.g., BSD/OS and + Digital UNIX 4.0) have this package pre-installed. If your + system does not have NEWDB installed, get the latest version + from FTP.CS.Berkeley.EDU in /ucb/4bsd/db.tar.gz (or db.tar.Z). + DO NOT use the version from the Net2 distribution. If you are + still running BSD/386 1.x, you will also need to define + OLD_NEWDB. +NDBM The older NDBM implementation -- the very old V7 DBM + implementation is no longer supported. +NIS Network Information Services. To use this you must have + NIS support on your system. +NISPLUS NIS+ (the revised NIS released with Solaris 2). You must + have NIS+ support on your system to use this flag. +HESIOD Support for Hesiod (from the DEC/Athena distribution). You + must already have Hesiod support on your system for this to + work. You may be able to get this to work with the MIT/Athena + version of Hesiod, but that's likely to be a lot of work. +LDAPMAP Lightweight Directory Lookup Protocol support. You will + have to install the UMich ldap and lber libraries to use + this flag. + +>>> NOTE WELL for NEWDB support: it is CRITICAL that you remove ndbm.o +>>> from libdb.a before you install it and DO NOT install ndbm.h if +>>> you want to get ndbm support. If you don't delete these, there is +>>> absolutely no point to including -DNDBM, since it will just get you +>>> another (inferior) API to the same format database. These files +>>> OVERRIDE calls to ndbm routines -- in particular, if you leave ndbm.h +>>> in, you can find yourself using the new db package even if you don't +>>> define NEWDB. +>>> +>>> Further note: DO NOT remove your existing /usr/include/ndbm.h -- +>>> you need that one. But do not install an updated ndbm.h in +>>> /usr/include, /usr/local/include, or anywhere else. If NEWDB and NDBM are defined (but not NIS), then sendmail will read NDBM format alias files, but the next time a newaliases is run the format will be converted to NEWDB; that format will be used forever -more. This is intended as a transition feature. [Note however that -the NEWDB library also catches and maps NDBM calls; you will have to -back out this feature to get this to work. See ``Quirks'' section -below for details.] +more. This is intended as a transition feature. -If all three are defined and the name of the file includes the string -"/yp/", sendmail will rebuild BOTH the NEWDB and NDBM format alias -files. However, it will only read the NEWDB file; the NDBM format file -is used only by the NIS subsystem. +If NEWDB, NDBM, and NIS are all defined and the name of the file includes +the string "/yp/", sendmail will rebuild BOTH the NEWDB and NDBM format +alias files. However, it will only read the NEWDB file; the NDBM format +file is used only by the NIS subsystem. This is needed because the NIS +maps on an NIS server are built directly from the NDBM files. If NDBM and NIS are defined (regardless of the definition of NEWDB), and the filename includes the string "/yp/", sendmail adds the special tokens "YP_LAST_MODIFIED" and "YP_MASTER_NAME", both of which are required if the NDBM file is to be used as an NIS map. -There is also preliminary support for NIS+ (-DNISPLUS), Hesiod -(-DHESIOD), and NetInfo (-DNETINFO). These have not been well -tested. - -All of -DNEWDB, -DNDBM, -DNIS, -DNISPLUS, -DHESIOD, and -DNETINFO are -normally defined in the DBMDEF line in the Makefile. +All of these flags are normally defined in the DBMDEF line in the +Makefile. If you define NEWDB or HESIOD you get the User Database (USERDB) automatically. Generally you do want to have NEWDB for it to do @@ -191,6 +205,11 @@ anything interesting. See above for getting the Berkeley "db" package (i.e., NEWDB). There is no separate "user database" package -- don't bother searching for it on the net. +Hesiod and LDAP require libraries that may not be installed with your +system. These are outside of my ability to provide support. See the +"Quirks" section for more information. + + +---------------+ | COMPILE FLAGS | @@ -340,11 +359,20 @@ LA_TYPE The type of load average your kernel supports. These the dg_sys_info system call. LA_HPUX (10) is an HP-UX specific version that uses the pstat_getdynamic system call. + LA_IRIX6 (11) is an IRIX 6.x specific version that adapts + to 32 or 64 bit kernels; it is otherwise very similar + to LA_INT. + LA_KSTAT (12) uses the (Solaris-specific) kstat(3k) + implementation. + LA_DEVSHORT (13) reads a short from a system file (default: + /dev/table/avenrun) and scales it in the same manner + as LA_SHORT. LA_INT, LA_SHORT, LA_FLOAT, and LA_READKSYM have several other parameters that they try to divine: the name of your kernel, the name of the variable in the kernel to examine, the number of bits of precision in a fixed point load average, - and so forth. + and so forth. LA_DEVSHORT uses _PATH_AVENRUN to find the + device to be read to find the load average. In desperation, use LA_ZERO. The actual code is in conf.c -- it can be tweaked if you are brave. FSHIFT For LA_INT, LA_SHORT, and LA_READKSYM, this is the number @@ -462,7 +490,7 @@ IP_SRCROUTE Define this to 1 to get IP source routing information it won't compile properly (that is, no support for fetching IP_OPTIONs), or it compiles but source-routed TCP connections either refuse to open or open and hang for no apparent reason. - Ultrix and AIX are known to fail this way. + Ultrix and AIX3 are known to fail this way. LOG Set this to get syslog(3) support. Defined by default in conf.h. You want this if at all possible. NETINET Set this to get TCP/IP support. Defined by default @@ -500,6 +528,19 @@ HES_GETMAILHOST Define this to 1 if you are using Hesiod with the Hesiod distribution, but not with the DEC Hesiod distribution. XDEBUG Do additional internal checking. These don't cost too much; you might as well leave this on. +TCPWRAPPERS Turns on support for the TCP wrappers library (-lwrap). + This library is available on ftp.win.tue.nl in /pub/security; + grab tcp_wrappers_<VER>.tar.gz (where <VER> is the highest + numbered version). +SECUREWARE Enable calls to the SecureWare luid enabling/changing routines. + SecureWare is a C2 security package added to several UNIX's + (notably ConvexOS) to get a C2 Secure system. This + option causes mail delivery to be done with the luid of the + recipient. +SHARE_V1 Support for the fair share scheduler, version 1. Setting to + 1 causes final delivery to be done using the recipients + resource limitations. So far as I know, this is only + supported on ConvexOS. +---------------------+ @@ -515,7 +556,10 @@ dn_skipname. Some people have had a problem with BIND 4.9; it uses some routines that it expects to be externally defined such as strerror(). It may -help to link with "-l44bsd" to solve this problem. +help to link with "-l44bsd" to solve this problem. This has apparently +been fixed in later versions of BIND, starting around 4.9.3. In other +words, if you use 4.9.0 through 4.9.2, you need -l44bsd; for earlier or +later versions, you do not. !PLEASE! be sure to link with the same version of the resolver as the header files you used -- some people have used the 4.9 headers @@ -587,6 +631,13 @@ Configuration file location vendor location rather than changing the location in the sendmail binary. +ld: fatal: library -l44bsd: not found + Most of the Makefiles include -l44bsd in the LIBS= definition; + this is because several versions of BIND (4.9.0, 4.9.1, 4.9.2) + require this library. If you are running one of these versions, + install this library. Otherwise, just delete "-l44bsd" from the + LIBS= line in the Makefile. + SunOS 4.x (Solaris 1.x) You may have to use -lresolv on SunOS. However, beware that this links in a new version of gethostbyname that does not @@ -631,17 +682,18 @@ SunOS 4.0.2 (Sun 386i) (and change the Makefile to use this library). Note that the sendmail.cf and aliases files are found in /etc. -SunOS 4.1.3_U1 - Sendmail causes crashes on SunOS 4.1.3_U1. According to Sun - bug number 1077939: +SunOS 4.1.3, 4.1.3_U1 + Sendmail causes crashes on SunOS 4.1.3 and 4.1.3_U1. According + to Sun bug number 1077939: If an application does a getsockopt() on a SOCK_STREAM (TCP) socket after the other side of the connection has sent a TCP RESET for the stream, the kernel gets a Bus Trap in the tcp_ctloutput() or ip_ctloutput() routine. - This is fixed in patch 101790-01 (SunOS 4.1.3_U1: TCP socket and - reset problems). + For 4.1.3, this is fixed in patch 100584-08, available on the + Sunsolve 2.7.1 or later CDs. For 4.1.3_U1, this is fixed in patch + 101790-01 (SunOS 4.1.3_U1: TCP socket and reset problems). Solaris 2.x (SunOS 5.x) To compile for Solaris, be sure you use -DSOLARIS. @@ -742,6 +794,23 @@ Ultrix IDENT on in the configuration file by setting the "ident" timeout to 30 seconds. +Solaris 2.5.1 (SunOS 5.5.1) + Apparently patch 103663-01 installs a new /usr/include/resolv.h + file that defines the __P macro without checking to see if it is + already defined. This causes compile warnings such as: + + In file included from daemon.c:51: + /usr/include/resolv.h:208: warning: `__P' redefined + cdefs.h:58: warning: this is the location of the previous definition + + If you are running with this patch, create a file in the + obj.SunOS.5.5.1.* directory that reads: + + #undef __P + #include "/usr/include/resolv.h" + + ... And then file a bug report with Sun. + OSF/1 If you are compiling on OSF/1 (DEC Alpha), you must use -L/usr/shlib (otherwise it core dumps on startup). You may also @@ -751,6 +820,10 @@ OSF/1 Also, the enclosed makefile removed /usr/sbin/smtpd; if you need it, just create the link to the sendmail binary. + On DEC OSF/1 3.2 or earlier, the MatchGECOS option doesn't work + properly due to a bug in the getpw* routines. If you want to use + this, use -DDEC_OSF_BROKEN_GETPWENT=1. The problem is fixed in 3.2C. + IRIX The header files on SGI IRIX are completely prototyped, and as a result you can sometimes get some warning messages during @@ -766,6 +839,26 @@ IRIX the developers' option in order to get the necessary include files. + If you compile with -lmalloc (the fast memory allocator), you may + get warning messages such as the following: + + ld32: WARNING 85: definition of _calloc in /usr/lib32/libmalloc.so + preempts that definition in /usr/lib32/mips3/libc.so. + ld32: WARNING 85: definition of _malloc in /usr/lib32/libmalloc.so + preempts that definition in /usr/lib32/mips3/libc.so. + ld32: WARNING 85: definition of _realloc in /usr/lib32/libmalloc.so + preempts that definition in /usr/lib32/mips3/libc.so. + ld32: WARNING 85: definition of _free in /usr/lib32/libmalloc.so + preempts that definition in /usr/lib32/mips3/libc.so. + ld32: WARNING 85: definition of _cfree in /usr/lib32/libmalloc.so + preempts that definition in /usr/lib32/mips3/libc.so. + + These are unavoidable and innocuous -- just ignore them. + + According to Dave Sill <de5@ornl.gov>, there is a version of the + Berkeley db library patched to run on Irix 6.2 available from + http://reality.sgi.com/ariel/db-1.85-irix.tar.Z . + NeXT or NEXTSTEP NEXTSTEP 3.3 and earlier ship with the old DBM library. You will need to acquire the new Berkeley DB from ftp.cs.berkeley.edu. @@ -931,7 +1024,22 @@ Linux of libc between 4.4.4 and 4.7.0 (snprintf improves security, so you want to use this if at all possible). -AIX + NOTE ON LINUX & BIND: By default, the Makefiles for linux include + header files in /usr/local/include and libraries in /usr/local/lib. + If you've installed BIND on your system, the header files typically + end up in the search path and you need to add "-lresolv" to the + LIBS line in your Makefile. Really old versions may need to include + "-l44bsd" as well (particularly if the link phase complains about + missing strcasecmp, strncasecmp or strpbrk). Complaints about an + undefined reference to `__dn_skipname' in domain.o are a sure sign + that you need to add -lresolv to LIBS. Newer versions of linux + are basically threaded BIND, so you may or may not see complaints + if you accidentally mix BIND headers/libraries with virginal libc. + If you have BIND headers in /usr/local/include (resolv.h, etc) + you *should* be adding -lresolv to LIBS. Data structures may change + and you'd be asking for a core dump. + +AIX 3.x This version of sendmail does not support MB, MG, and MR resource records, which are supported by AIX sendmail. @@ -940,6 +1048,56 @@ AIX necessary to replace the resolver, which will simplify installation. A new BIND resolver can be found at http://www.isc.org/isc/. +AIX 3.1.x + The supplied load average code only works correctly for AIX 3.2.x. + For 3.1, use -DLA_TYPE=LA_SUBR and get the latest ``monitor'' + package by Jussi Maki <jmaki@hut.fi> from ftp.funet.fi in the + directory pub/unix/AIX/rs6000/monitor-1.12.tar.Z; use the loadavgd + daemon, and the getloadavg subroutine supplied with that package. + If you don't care about load average throttling, just turn off + load average checking using -DLA_TYPE=LA_ZERO. + +AIX 2.2.1 + Date: Mon Dec 4 14:14:56 CST 1995 + From: Mark Whetzel <markw@antimatr.houston.tx.us> + Subject: Porting sendmail 8.7.2 to AIX V2 on the RT. + + This version of sendmail does not support MB, MG, and MR resource + records, which are supported by AIX sendmail. + + AIX V2 on the RT does not have 'paths.h'. Create a null + file in the 'obj' directory to remove this compile error. + + A patch file is needed to get the BSD 'db' library to compile + for AIX/RT. I have sent the necessary updates to the author, + but they may not be immediately available. + + The original AIX/RT resolver libraries are very old, and you + should get the latest BIND to replace it. The 4.8.3 version + has been tested, but 4.9.x is out and should work. + + To make the load average code work correctly requires an + external routine, as the kernel does not maintain system + load averages, similar to AIX V3.1.x. A reverse port of the + older 1.05 'monitor' load average daemon code written by + Jussi Maki that will work on AIX V2 for the RT is available + by E-mail to Mark Whetzel <markw@antimatr.houston.tx.us>. + That code depends on an external daemon to collect system + load information, and the external routine 'getloadavg', + that will return that information. The 'LA_SUBR' define + will handle this for AIX V2 on the RT. + + Note: You will have to change the Makefile.AIX.2 to correctly + point to the locatons of the updated BIND source tree and + the location of the 'newdb' tree and library location. + You will also have to change the Makefile.AIX.2 to know + about the location of the 'getloadavg' routine if you use + the LA_SUBR define. + + + Manual pages will format correctly if given the mandoc macros + and used with nroff. I have not tried groff. + RISC/os RISC/os from MIPS is a merged AT&T/Berkeley system. When you compile on that platform you will get duplicate definitions @@ -1081,7 +1239,7 @@ Listproc 6.0c From: alansz@mellers1.psych.berkeley.edu (Alan Schwartz) Subject: Listproc 6.0c + Sendmail 8.7 [Helpful hint] - Just upgraded to sendmail 8.7, and discovered that listproc 6.0c + Just upgraded to sendmail 8.7, and discovered that listproc 6.0c breaks, because it, by default, sends a blank "HELO" rather than a "HELO hostname" when using the 'system' or 'telnet' mailmethod. @@ -1089,6 +1247,56 @@ Listproc 6.0c cause it to use "HELO hostname" (which Z-mail apparently requires as well. :) +LDAP + LDAP was provided by Booker Bense <bbense@networking.stanford.edu> of + Stanford University. From Booker: + + - The patch attached to this message implements an Ldap map class. + Currently we are using this at stanford to support campus-wide + email addressing. This project is discussed at + http://www-leland.stanford.edu/group/networking/project/sunetid.html + + - Currently we are using the ldap map as follows: + + Kluser ldapx + -h"localhost borax.stanford.edu borate.stanford.edu boron.stanford.edu" + -k"mailacceptinggeneralid=%s" -v maildrop + + and in Rule set S5 + + # Now attempt to lookup in luser (ldap map) + R< $L > $+ $: < $L > $( luser $1 $) + R< $* > $+ @ $+ $: < $3 > $2 Rewrite if forward + + - The map definition supports most of the standard Map args plus most + of the command line options of ldapsearch. The software is currently + limited to only accepting the first entry returned. It expects that + the map defines an ldap filter that returns at most 1 valid entry. + It requires the ldap and lber libraries from the Umich Ldap3.2 + release. + + - KNOWN BUGS: It does not work under Digital Unix 3.2c, with gcc and + ldap3.2 or ldap3.3. It dumps core after attempting to take strlen + of a garbage string pointer in the lber libraries routine + ber_printf. + + The string pointer in question is set to 0x50000000, when the + program crashes. If anyone recognizes where this magic number comes + from that would be really helpful. + + I've tested the software on Solaris.2.4 with gcc and on NeXTStep3.2 + and it runs without problems. If you have any questions, please + send them along. + +TCP Wrappers + If you are using -DTCPWRAPPERS to get TCP Wrappers support, you will + also need to install libwrap.a (you can get it from ftp.win.tue.nl) + and modify the Makefile to include -lwrap in the LIBS line. + + If you have alternate MX sites for your site, be sure that all of + your MX sites reject the same set of hosts. If not, a bad guy whom + you reject will connect to your site, fail, and move on to the next + MX site, which will accept the mail for your and forward it on to you. +--------------+ @@ -1190,4 +1398,4 @@ version.c The version number and information about this Eric Allman -(Version 8.113, last update 11/29/95 11:05:14) +(Version 8.132, last update 12/1/96 09:34:37) diff --git a/usr.sbin/sendmail/src/TRACEFLAGS b/usr.sbin/sendmail/src/TRACEFLAGS index f2499aac091..a5b25656e76 100644 --- a/usr.sbin/sendmail/src/TRACEFLAGS +++ b/usr.sbin/sendmail/src/TRACEFLAGS @@ -62,9 +62,11 @@ 53 util.c xfclose 54 err.c putoutmsg 55 conf.c lockfile -59 Extended Load Average implementation from Christophe Wolfhugel +56 mci.c persistent host status +57 util.c snprintf 60 map.c 61 conf.c sm_gethostbyname +62 multiple file descriptor checking 80 content length 81 sun remote mode 91 mci.c syslogging of MCI cache information diff --git a/usr.sbin/sendmail/src/alias.c b/usr.sbin/sendmail/src/alias.c index 62b6af96de4..95de1ee8ff6 100644 --- a/usr.sbin/sendmail/src/alias.c +++ b/usr.sbin/sendmail/src/alias.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -35,7 +35,7 @@ # include "sendmail.h" #ifndef lint -static char sccsid[] = "@(#)alias.c 8.52.1.3 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)alias.c 8.66 (Berkeley) 9/20/96"; #endif /* not lint */ @@ -152,8 +152,6 @@ alias(a, sendq, aliaslevel, e) (void) strcat(obuf, "owner"); else (void) strcat(obuf, a->q_user); - if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) - makelower(obuf); owner = aliaslookup(obuf, &stat, e); if (owner == NULL) return; @@ -207,6 +205,11 @@ aliaslookup(name, pstat, e) } if (!bitset(MF_OPEN, map->map_mflags)) return NULL; + + /* special case POstMastER -- always use lower case */ + if (strcasecmp(name, "postmaster") == 0) + name = "postmaster"; + return (*map->map_class->map_lookup)(map, name, NULL, pstat); } /* @@ -292,8 +295,7 @@ setalias(spec) s = stab(class, ST_MAPCLASS, ST_FIND); if (s == NULL) { - if (tTd(27, 1)) - printf("Unknown alias class %s\n", class); + syserr("setalias: unknown alias class %s", class); } else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) { @@ -494,7 +496,7 @@ rebuildaliases(map, automatic) !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) { /* yes, they are -- wait until done */ - message("Alias file %s is already being rebuilt", + message("Alias file %s is locked (maybe being rebuilt)", map->map_file); if (OpMode != MD_INITALIAS) { @@ -710,10 +712,12 @@ readaliases(map, af, announcestats, logstats) } /* - ** Insert alias into symbol table or DBM file + ** Insert alias into symbol table or database file. + ** + ** Special case pOStmaStER -- always make it lower case. */ - if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) + if (strcasecmp(al.q_user, "postmaster") == 0) makelower(al.q_user); lhssize = strlen(al.q_user); @@ -776,6 +780,7 @@ forward(user, sendq, aliaslevel, e) { char *pp; char *ep; + bool got_transient; if (tTd(27, 1)) printf("forward(%s)\n", user->q_paddr); @@ -786,7 +791,7 @@ forward(user, sendq, aliaslevel, e) if (user->q_home == NULL) { syserr("554 forward: no home"); - user->q_home = "/nosuchdirectory"; + user->q_home = "/no/such/directory"; } /* good address -- look for .forward file in home */ @@ -796,11 +801,11 @@ forward(user, sendq, aliaslevel, e) if (ForwardPath == NULL) ForwardPath = newstr("\201z/.forward"); + got_transient = FALSE; for (pp = ForwardPath; pp != NULL; pp = ep) { int err; char buf[MAXPATHLEN+1]; - extern int include(); ep = strchr(pp, ':'); if (ep != NULL) @@ -808,6 +813,8 @@ forward(user, sendq, aliaslevel, e) expand(pp, buf, sizeof buf, e); if (ep != NULL) *ep++ = ':'; + if (buf[0] == '\0') + continue; if (tTd(27, 3)) printf("forward: trying %s\n", buf); @@ -816,7 +823,8 @@ forward(user, sendq, aliaslevel, e) break; else if (transienterror(err)) { - /* we have to suspend this message */ + /* we may have to suspend this message */ + got_transient = TRUE; if (tTd(27, 2)) printf("forward: transient error on %s\n", buf); #ifdef LOG @@ -825,9 +833,18 @@ forward(user, sendq, aliaslevel, e) e->e_id == NULL ? "NOQUEUE" : e->e_id, buf, errstring(err)); #endif - message("%s: %s: message queued", buf, errstring(err)); - user->q_flags |= QQUEUEUP; - return; } } + if (pp == NULL && got_transient) + { + /* + ** There was no successful .forward open and at least one + ** transient open. We have to defer this address for + ** further delivery. + */ + + message("transient .forward open error: message queued"); + user->q_flags |= QQUEUEUP; + return; + } } diff --git a/usr.sbin/sendmail/src/arpadate.c b/usr.sbin/sendmail/src/arpadate.c index b207654f313..418fd262e55 100644 --- a/usr.sbin/sendmail/src/arpadate.c +++ b/usr.sbin/sendmail/src/arpadate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)arpadate.c 8.4.1.1 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)arpadate.c 8.6 (Berkeley) 9/16/96"; #endif /* not lint */ # include "sendmail.h" diff --git a/usr.sbin/sendmail/src/clock.c b/usr.sbin/sendmail/src/clock.c index 1490137170e..281ee606b92 100644 --- a/usr.sbin/sendmail/src/clock.c +++ b/usr.sbin/sendmail/src/clock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)clock.c 8.12 (Berkeley) 5/23/95"; +static char sccsid[] = "@(#)clock.c 8.16 (Berkeley) 11/27/96"; #endif /* not lint */ # include "sendmail.h" @@ -98,8 +98,8 @@ setevent(intvl, func, arg) *evp = ev; if (tTd(5, 5)) - printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n", - intvl, now + intvl, func, arg, ev); + printf("setevent: intvl=%ld, for=%ld, func=%lx, arg=%d, ev=%lx\n", + intvl, now + intvl, (u_long) func, arg, (u_long) ev); tick(0); return (ev); @@ -124,7 +124,7 @@ clrevent(ev) register EVENT **evp; if (tTd(5, 5)) - printf("clrevent: ev=%x\n", ev); + printf("clrevent: ev=%lx\n", (u_long) ev); if (ev == NULL) return; @@ -191,8 +191,9 @@ tick(arg) ev = EventQueue; EventQueue = EventQueue->ev_link; if (tTd(5, 6)) - printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, - ev->ev_func, ev->ev_arg, ev->ev_pid); + printf("tick: ev=%lx, func=%lx, arg=%d, pid=%d\n", + (u_long) ev, (u_long) ev->ev_func, + ev->ev_arg, ev->ev_pid); /* we must be careful in here because ev_func may not return */ f = ev->ev_func; @@ -211,17 +212,7 @@ tick(arg) /* restore signals so that we can take ticks while in ev_func */ (void) setsignal(SIGALRM, tick); -#ifdef SIG_UNBLOCK - /* unblock SIGALRM signal */ - sigemptyset(&ss); - sigaddset(&ss, SIGALRM); - sigprocmask(SIG_UNBLOCK, &ss, NULL); -#else -#if HASSIGSETMASK - /* reset 4.2bsd signal mask to allow future alarms */ - (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); -#endif /* HASSIGSETMASK */ -#endif /* SIG_UNBLOCK */ + (void) releasesignal(SIGALRM); /* call ev_func */ errno = olderrno; @@ -262,12 +253,17 @@ SLEEP_T sleep(intvl) unsigned int intvl; { + int was_held; + if (intvl == 0) return (SLEEP_T) 0; SleepDone = FALSE; (void) setevent((time_t) intvl, endsleep, 0); + was_held = releasesignal(SIGALRM); while (!SleepDone) pause(); + if (was_held > 0) + blocksignal(SIGALRM); return (SLEEP_T) 0; } diff --git a/usr.sbin/sendmail/src/collect.c b/usr.sbin/sendmail/src/collect.c index 7e43c5f5ffa..c5e1cebcfbd 100644 --- a/usr.sbin/sendmail/src/collect.c +++ b/usr.sbin/sendmail/src/collect.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)collect.c 8.49 (Berkeley) 10/29/95"; +static char sccsid[] = "@(#)collect.c 8.61 (Berkeley) 11/24/96"; #endif /* not lint */ # include <errno.h> @@ -90,19 +90,19 @@ collect(fp, smtpmode, requeueflag, hdrp, e) HDR **hdrp; register ENVELOPE *e; { - register FILE *tf; - bool ignrdot = smtpmode ? FALSE : IgnrDot; - time_t dbto = smtpmode ? TimeOuts.to_datablock : 0; - register char *bp; - int c = '\0'; - bool inputerr = FALSE; + register FILE *volatile tf; + volatile bool ignrdot = smtpmode ? FALSE : IgnrDot; + volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0; + register char *volatile bp; + volatile int c = '\0'; + volatile bool inputerr = FALSE; bool headeronly; - char *buf; - int buflen; - int istate; - int mstate; - char *pbp; - char peekbuf[8]; + char *volatile buf; + volatile int buflen; + volatile int istate; + volatile int mstate; + u_char *volatile pbp; + u_char peekbuf[8]; char dfname[20]; char bufbuf[MAXLINE]; extern bool isheader(); @@ -170,9 +170,10 @@ collect(fp, smtpmode, requeueflag, hdrp, e) if (setjmp(CtxCollectTimeout) != 0) { #ifdef LOG - syslog(LOG_NOTICE, - "timeout waiting for input from %s during message collect", - CurHostName ? CurHostName : "<local machine>"); + if (LogLevel > 2) + syslog(LOG_NOTICE, + "timeout waiting for input from %s during message collect", + CurHostName ? CurHostName : "<local machine>"); #endif errno = 0; usrerr("451 timeout waiting for input during message collect"); @@ -204,7 +205,7 @@ collect(fp, smtpmode, requeueflag, hdrp, e) { if (istate == IS_BOL) fprintf(TrafficLogFile, "%05d <<< ", - getpid()); + (int) getpid()); if (c == EOF) fprintf(TrafficLogFile, "[EOF]\n"); else @@ -216,8 +217,6 @@ collect(fp, smtpmode, requeueflag, hdrp, e) c &= 0x7f; else HasEightBits |= bitset(0x80, c); - if (!headeronly) - e->e_msgsize++; } if (tTd(30, 94)) printf("istate=%d, c=%c (0x%x)\n", @@ -253,7 +252,7 @@ collect(fp, smtpmode, requeueflag, hdrp, e) break; case IS_DOTCR: - if (c == '\n') + if (c == '\n' && !ignrdot) goto readerr; else { @@ -287,6 +286,8 @@ collect(fp, smtpmode, requeueflag, hdrp, e) istate = IS_NORM; bufferchar: + if (!headeronly) + e->e_msgsize++; if (mstate == MS_BODY) { /* just put the character out */ @@ -316,7 +317,13 @@ bufferchar: if (obuf != bufbuf) free(obuf); } - if (c != '\0') + if (c >= 0200 && c <= 0237) + { +#if 0 /* causes complaints -- figure out something for 8.9 */ + usrerr("Illegal character 0x%x in header", c); +#endif + } + else if (c != '\0') *bp++ = c; if (istate == IS_BOL) break; @@ -481,7 +488,7 @@ readerr: ** Examples are who is the from person & the date. */ - eatheader(e, !requeueflag); + eatheader(e, TRUE); if (GrabTo && e->e_sendqueue == NULL) usrerr("No recipient addresses found in header"); @@ -550,6 +557,7 @@ readerr: /* check for message too large */ if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) { + e->e_flags |= EF_NO_BODY_RETN; e->e_status = "5.2.3"; usrerr("552 Message exceeds maximum fixed size (%ld)", MaxMessageSize); @@ -564,7 +572,8 @@ readerr: if (HasEightBits) { e->e_flags |= EF_HAS8BIT; - if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode)) + if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && + !bitset(EF_IS_MIME, e->e_flags)) { e->e_status = "5.6.1"; usrerr("554 Eight bit data not allowed"); @@ -625,6 +634,7 @@ tferror(tf, e) struct stat st; long avail; long bsize; + extern long freediskspace __P((char *, long *)); e->e_flags |= EF_NO_BODY_RETN; if (fstat(fileno(tf), &st) < 0) @@ -637,7 +647,7 @@ tferror(tf, e) st.st_size); else fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n", - st.st_size); + (long) st.st_size); fprintf(tf, "*** at %s due to lack of disk space for temp file.\n", MyHostName); avail = freediskspace(QueueDir, &bsize); @@ -729,7 +739,6 @@ eatfrom(fm, e) if (*p != '\0') { char *q; - extern char *arpadate(); /* we have found a date */ q = xalloc(25); diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c index cc20e45f3cf..3c4722b9785 100644 --- a/usr.sbin/sendmail/src/conf.c +++ b/usr.sbin/sendmail/src/conf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)conf.c 8.243.1.9 (Berkeley) 9/17/96"; +static char sccsid[] = "@(#)conf.c 8.325 (Berkeley) 12/1/96"; #endif /* not lint */ # include "sendmail.h" @@ -78,49 +78,50 @@ static char sccsid[] = "@(#)conf.c 8.243.1.9 (Berkeley) 9/17/96"; struct hdrinfo HdrInfo[] = { /* originator fields, most to least significant */ - "resent-sender", H_FROM|H_RESENT, - "resent-from", H_FROM|H_RESENT, - "resent-reply-to", H_FROM|H_RESENT, - "sender", H_FROM, - "from", H_FROM, - "reply-to", H_FROM, - "full-name", H_ACHECK, - "return-receipt-to", H_FROM|H_RECEIPTTO, - "errors-to", H_FROM|H_ERRORSTO, + { "resent-sender", H_FROM|H_RESENT }, + { "resent-from", H_FROM|H_RESENT }, + { "resent-reply-to", H_FROM|H_RESENT }, + { "sender", H_FROM }, + { "from", H_FROM }, + { "reply-to", H_FROM }, + { "errors-to", H_FROM|H_ERRORSTO }, + { "full-name", H_ACHECK }, + { "return-receipt-to", H_RECEIPTTO }, /* destination fields */ - "to", H_RCPT, - "resent-to", H_RCPT|H_RESENT, - "cc", H_RCPT, - "resent-cc", H_RCPT|H_RESENT, - "bcc", H_RCPT|H_BCC, - "resent-bcc", H_RCPT|H_BCC|H_RESENT, - "apparently-to", H_RCPT, + { "to", H_RCPT }, + { "resent-to", H_RCPT|H_RESENT }, + { "cc", H_RCPT }, + { "resent-cc", H_RCPT|H_RESENT }, + { "bcc", H_RCPT|H_BCC }, + { "resent-bcc", H_RCPT|H_BCC|H_RESENT }, + { "apparently-to", H_RCPT }, /* message identification and control */ - "message-id", 0, - "resent-message-id", H_RESENT, - "message", H_EOH, - "text", H_EOH, + { "message-id", 0 }, + { "resent-message-id", H_RESENT }, + { "message", H_EOH }, + { "text", H_EOH }, /* date fields */ - "date", 0, - "resent-date", H_RESENT, + { "date", 0 }, + { "resent-date", H_RESENT }, /* trace fields */ - "received", H_TRACE|H_FORCE, - "x400-received", H_TRACE|H_FORCE, - "via", H_TRACE|H_FORCE, - "mail-from", H_TRACE|H_FORCE, + { "received", H_TRACE|H_FORCE }, + { "x400-received", H_TRACE|H_FORCE }, + { "via", H_TRACE|H_FORCE }, + { "mail-from", H_TRACE|H_FORCE }, /* miscellaneous fields */ - "comments", H_FORCE, - "return-path", H_FORCE|H_ACHECK, - "content-transfer-encoding", H_CTE, - "content-type", H_CTYPE, - "content-length", H_ACHECK, - - NULL, 0, + { "comments", H_FORCE|H_ENCODABLE }, + { "return-path", H_FORCE|H_ACHECK }, + { "content-transfer-encoding", H_CTE }, + { "content-type", H_CTYPE }, + { "content-length", H_ACHECK }, + { "subject", H_ENCODABLE }, + + { NULL, 0 } }; @@ -139,18 +140,18 @@ char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ struct prival PrivacyValues[] = { - "public", PRIV_PUBLIC, - "needmailhelo", PRIV_NEEDMAILHELO, - "needexpnhelo", PRIV_NEEDEXPNHELO, - "needvrfyhelo", PRIV_NEEDVRFYHELO, - "noexpn", PRIV_NOEXPN, - "novrfy", PRIV_NOVRFY, - "restrictmailq", PRIV_RESTRICTMAILQ, - "restrictqrun", PRIV_RESTRICTQRUN, - "authwarnings", PRIV_AUTHWARNINGS, - "noreceipts", PRIV_NORECEIPTS, - "goaway", PRIV_GOAWAY, - NULL, 0, + { "public", PRIV_PUBLIC }, + { "needmailhelo", PRIV_NEEDMAILHELO }, + { "needexpnhelo", PRIV_NEEDEXPNHELO }, + { "needvrfyhelo", PRIV_NEEDVRFYHELO }, + { "noexpn", PRIV_NOEXPN }, + { "novrfy", PRIV_NOVRFY }, + { "restrictmailq", PRIV_RESTRICTMAILQ }, + { "restrictqrun", PRIV_RESTRICTQRUN }, + { "authwarnings", PRIV_AUTHWARNINGS }, + { "noreceipts", PRIV_NORECEIPTS }, + { "goaway", PRIV_GOAWAY }, + { NULL, 0 } }; @@ -227,12 +228,15 @@ setdefaults(e) TimeOuts.to_q_warning[i] = 0; /* option T */ } ServiceSwitchFile = "/etc/service.switch"; + ServiceCacheMaxAge = (time_t) 10; HostsFile = _PATH_HOSTS; MustQuoteChars = "@,;:\\()[].'"; MciInfoTimeout = 30 MINUTES; MaxRuleRecursion = MAXRULERECURSION; MaxAliasRecursion = 10; + MaxMacroRecursion = 10; ColonOkInAddr = TRUE; + DoubleBounceAddr = "postmaster"; setdefuser(); setupmaps(); setupmailers(); @@ -278,6 +282,14 @@ host_map_init(map, args) case 'a': map->map_app = ++p; break; + + case 'm': + map->map_mflags |= MF_MATCHONLY; + break; + + case 't': + map->map_mflags |= MF_NODEFER; + break; } while (*p != '\0' && !(isascii(*p) && isspace(*p))) p++; @@ -298,13 +310,13 @@ setupmailers() char buf[100]; extern void makemailer(); - strcpy(buf, "prog, P=/bin/sh, F=lsoD, T=DNS/RFC822/X-Unix, A=sh -c \201u"); + strcpy(buf, "prog, P=/bin/sh, F=lsoDq9, T=DNS/RFC822/X-Unix, A=sh -c \201u"); makemailer(buf); - strcpy(buf, "*file*, P=[FILE], F=lsDFMPEou, T=DNS/RFC822/X-Unix, A=FILE"); + strcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=DNS/RFC822/X-Unix, A=FILE \201u"); makemailer(buf); - strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); + strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u"); makemailer(buf); } /* @@ -361,6 +373,11 @@ setupmaps() map_parseargs, nisplus_map_open, null_map_close, nisplus_map_lookup, null_map_store); #endif +#ifdef LDAPMAP + MAPDEF("ldapx", NULL, 0, + ldap_map_parseargs, ldap_map_open, ldap_map_close, + ldap_map_lookup, null_map_store); +#endif #ifdef HESIOD MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY, @@ -568,7 +585,7 @@ inithostmaps() else if (strcmp(maptype[i], "netinfo") == 0 && stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL) { - strcpy(buf, "aliases.netinfo netinfo /aliases"); + strcpy(buf, "aliases.netinfo netinfo -z, /aliases"); (void) makemapentry(buf); } #endif @@ -672,15 +689,12 @@ switch_map_find(service, maptype, mapreturn) char *maptype[MAXMAPSTACK]; short mapreturn[MAXMAPACTIONS]; { - register FILE *fp; int svcno; - static char buf[MAXLINE]; #ifdef _USE_SUN_NSSWITCH_ struct __nsw_switchconfig *nsw_conf; enum __nsw_parse_err pserr; struct __nsw_lookup *lk; - int nsw_rc; static struct __nsw_lookup lkp0 = { "files", {1, 0, 0, 0}, NULL, NULL }; static struct __nsw_switchconfig lkp_default = @@ -761,44 +775,85 @@ switch_map_find(service, maptype, mapreturn) ** Fall-back mechanism. */ + STAB *st; + time_t now = curtime(); + for (svcno = 0; svcno < MAXMAPACTIONS; svcno++) mapreturn[svcno] = 0; - svcno = 0; - fp = fopen(ServiceSwitchFile, "r"); - if (fp != NULL) + if ((now - ServiceCacheTime) > (time_t) ServiceCacheMaxAge) { - while (fgets(buf, sizeof buf, fp) != NULL) + /* (re)read service switch */ + register FILE *fp; + + if (ConfigFileRead) + ServiceCacheTime = now; + fp = fopen(ServiceSwitchFile, "r"); + if (fp != NULL) { - register char *p; - - p = strpbrk(buf, "#\n"); - if (p != NULL) - *p = '\0'; - p = strpbrk(buf, " \t"); - if (p != NULL) - *p++ = '\0'; - if (strcmp(buf, service) != 0) - continue; - - /* got the right service -- extract data */ - do + char buf[MAXLINE]; + + while (fgets(buf, sizeof buf, fp) != NULL) { + register char *p; + + p = strpbrk(buf, "#\n"); + if (p != NULL) + *p = '\0'; + p = strpbrk(buf, " \t"); + if (p != NULL) + *p++ = '\0'; + if (buf[0] == '\0') + continue; while (isspace(*p)) p++; if (*p == '\0') - break; - maptype[svcno++] = p; - p = strpbrk(p, " \t"); - if (p != NULL) + continue; + + /* + ** Find/allocate space for this service entry. + ** Space for all of the service strings + ** are allocated at once. This means + ** that we only have to free the first + ** one to free all of them. + */ + + st = stab(buf, ST_SERVICE, ST_ENTER); + if (st->s_service[0] != NULL) + free((void *) st->s_service[0]); + p = newstr(p); + for (svcno = 0; svcno < MAXMAPSTACK; ) + { + if (*p == '\0') + break; + st->s_service[svcno++] = p; + p = strpbrk(p, " \t"); + if (p == NULL) + break; *p++ = '\0'; - } while (p != NULL); + while (isspace(*p)) + p++; + } + if (svcno < MAXMAPSTACK) + st->s_service[svcno] = NULL; + } fclose(fp); - return svcno; } + } - /* service was not found -- use compiled in default */ - fclose(fp); + /* look up entry in cache */ + st = stab(service, ST_SERVICE, ST_FIND); + if (st != NULL && st->s_service[0] != NULL) + { + /* extract data */ + svcno = 0; + while (svcno < MAXMAPSTACK) + { + maptype[svcno] = st->s_service[svcno]; + if (maptype[svcno++] == NULL) + break; + } + return --svcno; } #endif @@ -1019,9 +1074,14 @@ setsignal(sig, handler) struct sigaction n, o; bzero(&n, sizeof n); +# if USE_SA_SIGACTION + n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler; + n.sa_flags = SA_RESTART|SA_SIGINFO; +# else n.sa_handler = handler; -# ifdef SA_RESTART +# ifdef SA_RESTART n.sa_flags = SA_RESTART; +# endif # endif if (sigaction(sig, &n, &o) < 0) return SIG_ERR; @@ -1029,13 +1089,56 @@ setsignal(sig, handler) #endif } /* +** BLOCKSIGNAL -- hold a signal to prevent delivery +** +** Parameters: +** sig -- the signal to block. +** +** Returns: +** 1 signal was previously blocked +** 0 signal was not previously blocked +** -1 on failure. +*/ + +int +blocksignal(sig) + int sig; +{ +#ifdef BSD4_3 +# ifndef sigmask +# define sigmask(s) (1 << ((s) - 1)) +# endif + return (sigblock(sigmask(sig)) & sigmask(sig)) != 0; +#else +# ifdef ALTOS_SYSTEM_V + sigfunc_t handler; + + handler = sigset(sig, SIG_HOLD); + if (handler == SIG_ERR) + return -1; + else + return handler == SIG_HOLD; +# else + sigset_t sset, oset; + + sigemptyset(&sset); + sigaddset(&sset, sig); + if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0) + return -1; + else + return sigismember(&oset, sig); +# endif +#endif +} +/* ** RELEASESIGNAL -- release a held signal ** ** Parameters: ** sig -- the signal to release. ** ** Returns: -** 0 on success. +** 1 signal was previously blocked +** 0 signal was not previously blocked ** -1 on failure. */ @@ -1044,13 +1147,26 @@ releasesignal(sig) int sig; { #ifdef BSD4_3 - return sigsetmask(sigblock(0) & ~(1 << sig)); + return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0; #else - sigset_t sset; +# ifdef ALTOS_SYSTEM_V + sigfunc_t handler; + + handler = sigset(sig, SIG_HOLD); + if (sigrelse(sig) < 0) + return -1; + else + return handler == SIG_HOLD; +# else + sigset_t sset, oset; sigemptyset(&sset); sigaddset(&sset, sig); - return sigprocmask(SIG_UNBLOCK, &sset, NULL); + if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0) + return -1; + else + return sigismember(&oset, sig); +# endif #endif } /* @@ -1097,7 +1213,11 @@ rlsesigs() */ #ifdef _AUX_SOURCE -# include <compat.h> +# include <compat.h> +#endif + +#if SHARE_V1 +# include <shares.h> #endif void @@ -1109,6 +1229,29 @@ init_md(argc, argv) setcompat(getcompat() | COMPAT_BSDPROT); #endif +#ifdef SUN_EXTENSIONS + init_md_sun(); +#endif + +#if _CONVEX_SOURCE + /* keep gethostby*() from stripping the local domain name */ + set_domain_trim_off(); +#endif +#if SECUREWARE || defined(_SCO_unix_) + set_auth_parameters(argc, argv); + +# ifdef _SCO_unix_ + /* + ** This is required for highest security levels (the kernel + ** won't let it call set*uid() or run setuid binaries without + ** it). It may be necessary on other SECUREWARE systems. + */ + + if (getluid() == -1) + setluid(0); +# endif +#endif + #ifdef VENDOR_DEFAULT VendorCode = VENDOR_DEFAULT; #else @@ -1161,6 +1304,10 @@ init_vendor_macros(e) #define LA_READKSYM 8 /* SVR4: use MIOC_READKSYM ioctl call */ #define LA_DGUX 9 /* special DGUX implementation */ #define LA_HPUX 10 /* special HPUX implementation */ +#define LA_IRIX6 11 /* special IRIX 6.2 implementation */ +#define LA_KSTAT 12 /* special Solaris kstat(3k) implementation */ +#define LA_DEVSHORT 13 /* read short from a device */ +#define LA_ALPHAOSF 14 /* Digital UNIX (OSF/1 on Alpha) table() call */ /* do guesses based on general OS type */ #ifndef LA_TYPE @@ -1176,9 +1323,6 @@ init_vendor_macros(e) # define FSHIFT 10 # endif -# if defined(_AIX3) -# define FSHIFT 16 -# endif #endif #ifndef FSHIFT @@ -1230,6 +1374,7 @@ struct nlist Nl[] = #endif #define X_AVENRUN 0 +int getla() { static int kmem = -1; @@ -1247,22 +1392,12 @@ getla() if (kmem < 0) { - kmem = open(_PATH_KMEM, 0, 0); - if (kmem < 0) - { - if (tTd(3, 1)) - printf("getla: open(/dev/kmem): %s\n", - errstring(errno)); - return (-1); - } - (void) fcntl(kmem, F_SETFD, 1); - #ifdef _AUX_SOURCE strcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN); Nl[1].n_name[0] = '\0'; #endif -#ifdef _AIX3 +#if defined(_AIX3) || defined(_AIX4) if (knlist(Nl, 1, sizeof Nl[0]) < 0) #else if (nlist(_PATH_UNIX, Nl) < 0) @@ -1283,9 +1418,20 @@ getla() #ifdef NAMELISTMASK Nl[X_AVENRUN].n_value &= NAMELISTMASK; #endif + + kmem = open(_PATH_KMEM, 0, 0); + if (kmem < 0) + { + if (tTd(3, 1)) + printf("getla: open(/dev/kmem): %s\n", + errstring(errno)); + return (-1); + } + (void) fcntl(kmem, F_SETFD, 1); } if (tTd(3, 20)) - printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); + printf("getla: symbol address = %#lx\n", + (u_long) Nl[X_AVENRUN].n_value); if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 || read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) { @@ -1297,9 +1443,15 @@ getla() # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) if (tTd(3, 5)) { +# if LA_TYPE == LA_SHORT printf("getla: avenrun = %d", avenrun[0]); if (tTd(3, 15)) printf(", %d, %d", avenrun[1], avenrun[2]); +# else + printf("getla: avenrun = %ld", avenrun[0]); + if (tTd(3, 15)) + printf(", %ld, %ld", avenrun[1], avenrun[2]); +# endif printf("\n"); } if (tTd(3, 1)) @@ -1452,6 +1604,7 @@ getla() # include <mach.h> #endif +int getla() { processor_set_t default_set; @@ -1462,14 +1615,22 @@ getla() error = processor_set_default(host_self(), &default_set); if (error != KERN_SUCCESS) + { + if (tTd(3, 1)) + perror("getla: processor_set_default failed:"); return -1; + } info_count = PROCESSOR_SET_BASIC_INFO_COUNT; if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host, (processor_set_info_t)&info, &info_count) != KERN_SUCCESS) { + if (tTd(3, 1)) + perror("getla: processor_set_info failed:"); return -1; } + if (tTd(3, 1)) + printf("getla: %d\n", (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE); return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; } @@ -1522,8 +1683,292 @@ getla() #endif /* LA_TYPE == LA_PROCSTR */ +#if LA_TYPE == LA_IRIX6 + +#include <nlist.h> +#include <sys/types.h> +#include <unistd.h> + +#define X_AVENRUN 0 +struct nlist Nl32[] = +{ + { LA_AVENRUN }, + { 0 }, +}; +struct nlist64 Nl64[] = +{ + { LA_AVENRUN }, + { 0 }, +}; + +int getla(void) +{ + static int kmem = -1; + static enum { getla_none, getla_32, getla_64 } kernel_type = + getla_none; + uint32_t avenrun32[3]; + uint64_t avenrun64[3]; + + if (kernel_type == getla_none) + { + /* Try 32 bit kernel ... */ + errno = 0; + if (nlist(_PATH_UNIX, Nl32) == 0) + { + if (tTd(3, 20)) + printf("getla: Kernel is 32bit\n"); + + if (Nl32[X_AVENRUN].n_value == 0) + { + if (tTd(3, 1)) + printf("getla: nlist(%s, %s) ==> 0\n", + _PATH_UNIX, LA_AVENRUN); + } + else + kernel_type = getla_32; + } + else if (errno != 0) + { + if (tTd(3, 1)) + printf("getla: nlist(%s): %s\n", + _PATH_UNIX, errstring(errno)); + } + else + { + if (tTd(3, 20)) + printf("getla: Kernel is not 32bit\n"); + } + + /* Try 64 bit kernel ... */ + errno = 0; + if (nlist64(_PATH_UNIX, Nl64) == 0) + { + if (tTd(3, 20)) + printf("getla: Kernel is 64bit\n"); + + if (Nl64[X_AVENRUN].n_value == 0) + { + if (tTd(3, 1)) + printf("getla: nlist(%s, %s) ==> 0\n", + _PATH_UNIX, LA_AVENRUN); + } + else + kernel_type = getla_64; + } + else if (errno != 0) + { + if (tTd(3, 1)) + printf("getla: nlist64(%s): %s\n", + _PATH_UNIX, errstring(errno)); + } + else + { + if (tTd(3, 20)) + printf("getla: Kernel is not 64bit\n"); + } + } + + if (kernel_type == getla_none) + { + if (tTd(3, 1)) + printf("getla: Failed to determine kernel type\n"); + return -1; + } + + if (kmem < 0) + { + kmem = open(_PATH_KMEM, 0, 0); + if (kmem < 0) + { + if (tTd(3, 1)) + printf("getla: open(/dev/kmem): %s\n", + errstring(errno)); + return -1; + } + (void) fcntl(kmem, F_SETFD, 1); + } + + switch (kernel_type) + { + case getla_32: + if (lseek(kmem, (off_t) Nl32[X_AVENRUN].n_value, SEEK_SET) == -1 || + read(kmem, (char *) avenrun32, sizeof(avenrun32)) < sizeof(avenrun32)) + { + if (tTd(3, 1)) + printf("getla: lseek or read: %s\n", + errstring(errno)); + return -1; + } + if (tTd(3, 5)) + { + printf("getla: avenrun{32} = %ld", + (long int) avenrun32[0]); + if (tTd(3, 15)) + printf(", %ld, %ld", + (long int)avenrun32[1], + (long int)avenrun32[2]); + printf("\n"); + } + if (tTd(3, 1)) + printf("getla: %d\n", + (int) (avenrun32[0] + FSCALE/2) >> FSHIFT); + return ((int) (avenrun32[0] + FSCALE/2) >> FSHIFT); + + case getla_64: + /* Using of lseek64 is perhaps overkill ... */ + if (lseek64(kmem, (off64_t) Nl64[X_AVENRUN].n_value, SEEK_SET) == -1 || + read(kmem, (char *) avenrun64, sizeof(avenrun64)) < + sizeof(avenrun64)) + { + if (tTd(3, 1)) + printf("getla: lseek64 or read: %s\n", + errstring(errno)); + return -1; + } + if (tTd(3, 5)) + { + printf("getla: avenrun{64} = %lld", + (long long int) avenrun64[0]); + if (tTd(3, 15)) + printf(", %lld, %lld", + (long long int) avenrun64[1], + (long long int) avenrun64[2]); + printf("\n"); + } + if (tTd(3, 1)) + printf("getla: %d\n", + (int) (avenrun64[0] + FSCALE/2) >> FSHIFT); + return ((int) (avenrun64[0] + FSCALE/2) >> FSHIFT); + } + return -1; +} +#endif + +#if LA_TYPE == LA_KSTAT + +#include <kstat.h> + +int +getla() +{ + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *ksn; + int la; + + kc = kstat_open(); + if (kc == NULL) + { + if (tTd(3, 1)) + printf("getla: kstat_open(): %s\n", + errstring(errno)); + return -1; + } + ksp = kstat_lookup(kc, "unix", 0, "system_misc"); /* NULL on error */ + if (ksp == NULL) + { + if (tTd(3, 1)) + printf("getla: kstat_lookup(): %s\n", + errstring(errno); + return -1; + } + if (kstat_read(kc, ksp, NULL) < 0) + { + if (tTd(3, 1)) + printf("getla: kstat_read(): %s\n", + errstring(errno); + return -1; + } + ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min"); + la = (ksn->value.ul + FSCALE/2) >> FSHIFT; + kstat_close(kc); + return la; +} + +#endif /* LA_TYPE == LA_KSTAT */ + +#if LA_TYPE == LA_DEVSHORT + +/* +** Read /dev/table/avenrun for the load average. This should contain +** three shorts for the 1, 5, and 15 minute loads. We only read the +** first, since that's all we care about. +** +** Intended for SCO OpenServer 5. +*/ + +# ifndef _PATH_AVENRUN +# define _PATH_AVENRUN "/dev/table/avenrun" +# endif + +int +getla() +{ + static int afd = -1; + short avenrun; + int loadav; + int r; + + errno = EBADF; + + if (afd == -1 || lseek(afd, 0L, SEEK_SET) == -1) + { + if (errno != EBADF) + return -1; + afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC); + if (afd < 0) + { + syslog(LOG_ERR, "can't open %s: %m", _PATH_AVENRUN); + return -1; + } + } + + r = read(afd, &avenrun, sizeof avenrun); + + if (tTd(3, 5)) + printf("getla: avenrun = %d\n", avenrun); + loadav = (int) (avenrun + FSCALE/2) >> FSHIFT; + if (tTd(3, 1)) + printf("getla: %d\n", loadav); + return loadav; +} + +#endif /* LA_TYPE == LA_DEVSHORT */ + +#if LA_TYPE == LA_ALPHAOSF +# include <sys/table.h> + +int getla() +{ + int ave = 0; + struct tbl_loadavg tab; + + if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1) + { + if (tTd(3, 1)) + printf("getla: table %s\n", errstring(errno)); + return (-1); + } + + if (tTd(3, 1)) + printf("getla: scale = %d\n", tab.tl_lscale); + + if (tab.tl_lscale) + ave = (tab.tl_avenrun.l[0] + (tab.tl_lscale/2)) / tab.tl_lscale; + else + ave = (int) (tab.tl_avenrun.d[0] + 0.5); + + if (tTd(3, 1)) + printf("getla: %d\n", ave); + + return ave; +} + +#endif + #if LA_TYPE == LA_ZERO +int getla() { if (tTd(3, 1)) @@ -1533,7 +1978,6 @@ getla() #endif /* LA_TYPE == LA_ZERO */ - /* * Copyright 1989 Massachusetts Institute of Technology * @@ -1559,7 +2003,7 @@ getla() /* Non Apollo stuff removed by Don Lewis 11/15/93 */ #ifndef lint -static char rcsid[] = "@(#)Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp "; +static char rcsid[] = "@(#)$Id: conf.c,v 1.5 1996/12/14 21:17:07 downsj Exp $"; #endif /* !lint */ #ifdef apollo @@ -1605,7 +2049,7 @@ shouldqueue(pri, ctime) bool rval; if (tTd(3, 30)) - printf("shouldqueue: CurrentLA=%d, pri=%d: ", CurrentLA, pri); + printf("shouldqueue: CurrentLA=%d, pri=%ld: ", CurrentLA, pri); if (CurrentLA < QueueLA) { if (tTd(3, 30)) @@ -1629,7 +2073,7 @@ shouldqueue(pri, ctime) ** REFUSECONNECTIONS -- decide if connections should be refused ** ** Parameters: -** none. +** port -- port number (for error messages only) ** ** Returns: ** TRUE if incoming SMTP connections should be refused @@ -1641,8 +2085,12 @@ shouldqueue(pri, ctime) */ bool -refuseconnections() +refuseconnections(port) + int port; { + time_t now; + static time_t lastconn = (time_t) 0; + static int conncnt = 0; extern bool enoughdiskspace(); extern void setproctitle __P((const char *, ...)); @@ -1651,24 +2099,69 @@ refuseconnections() return TRUE; #endif + now = curtime(); + if (now != lastconn) + { + lastconn = now; + conncnt = 0; + } + else if (conncnt++ > ConnRateThrottle && ConnRateThrottle > 0) + { + /* sleep to flatten out connection load */ + setproctitle("deferring connections on port %d: %d per second", + port, ConnRateThrottle); +#ifdef LOG + if (LogLevel >= 14) + syslog(LOG_INFO, "deferring connections on port %d: %d per second", + port, ConnRateThrottle); +#endif + sleep(1); + } + + CurrentLA = getla(); if (CurrentLA >= RefuseLA) { - setproctitle("rejecting connections: load average: %d", - CurrentLA); + setproctitle("rejecting connections on port %d: load average: %d", + port, CurrentLA); +#ifdef LOG + if (LogLevel >= 14) + syslog(LOG_INFO, "rejecting connections on port %d: load average: %d", + port, CurrentLA); +#endif + return TRUE; } - else if (!enoughdiskspace(MinBlocksFree + 1)) + + if (!enoughdiskspace(MinBlocksFree + 1)) { - setproctitle("rejecting connections: min free: %d", - MinBlocksFree); + setproctitle("rejecting connections on port %d: min free: %d", + port, MinBlocksFree); +#ifdef LOG + if (LogLevel >= 14) + syslog(LOG_INFO, "rejecting connections on port %d: min free: %d", + port, MinBlocksFree); +#endif + return TRUE; } - else if (MaxChildren > 0 && CurChildren >= MaxChildren) + + if (MaxChildren > 0 && CurChildren >= MaxChildren) { - setproctitle("rejecting connections: maximum children: %d", - CurChildren); + extern void proc_list_probe __P((void)); + + proc_list_probe(); + if (CurChildren >= MaxChildren) + { + setproctitle("rejecting connections on port %d: %d children, max %d", + port, CurChildren, MaxChildren); +#ifdef LOG + if (LogLevel >= 14) + syslog(LOG_INFO, "rejecting connections on port %d: %d children, max %d", + port, CurChildren, MaxChildren); +#endif + return TRUE; + } } - else - return FALSE; - return TRUE; + + return FALSE; } /* ** SETPROCTITLE -- set process title for ps @@ -1711,7 +2204,7 @@ refuseconnections() # else # ifndef NKPDE /* FreeBSD 2.0 */ # define NKPDE 63 -/*typedef unsigned int *pt_entry_t; */ +typedef unsigned int *pt_entry_t; # endif # endif # endif @@ -1823,7 +2316,7 @@ setproctitle(fmt, va_alist) /* print the argument string */ VA_START(fmt); - (void) vsnprintf(p, sizeof buf - (p - buf), fmt, ap); + (void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap); VA_END; i = strlen(buf); @@ -1852,7 +2345,7 @@ setproctitle(fmt, va_alist) } buf[PSARGSZ - 1] = '\0'; seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u; - if (lseek(kmem, (char *) seek_off, SEEK_SET) == seek_off) + if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off) (void) write(kmem, buf, PSARGSZ); # endif # if SPT_TYPE == SPT_REUSEARGV @@ -1889,10 +2382,10 @@ reapchild(sig) int sig; { int olderrno = errno; + pid_t pid; # ifdef HASWAITPID auto int status; int count; - int pid; count = 0; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) @@ -1900,24 +2393,26 @@ reapchild(sig) if (count++ > 1000) { #ifdef LOG - syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", - pid, status); + if (LogLevel > 0) + syslog(LOG_ALERT, + "reapchild: waitpid loop: pid=%d, status=%x", + pid, status); #endif break; } - CurChildren--; + proc_list_drop(pid); } # else # ifdef WNOHANG union wait status; - while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) - CurChildren--; + while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0) + proc_list_drop(pid); # else /* WNOHANG */ auto int status; - while (wait(&status) > 0) - CurChildren--; + while ((pid = wait(&status)) > 0) + proc_list_drop(pid); # endif /* WNOHANG */ # endif # ifdef SYS5SIGNALS @@ -1958,7 +2453,7 @@ putenv(str) * find out how much of str to match when searching * for a string to replace. */ - if ((tmp = index(str, '=')) == NULL || tmp == str) + if ((tmp = strchr(str, '=')) == NULL || tmp == str) matchlen = strlen(str); else matchlen = (int) (tmp - str); @@ -2322,7 +2817,7 @@ getopt(nargc,nargv,ostr) if (!*place) ++optind; tell(": illegal option -- "); } - if (*++oli != ':') { /* don't need argument */ + if (oli && *++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } @@ -2405,9 +2900,10 @@ vsprintf(s, fmt, ap) * causing nast effects. **************************************************************/ -/*static char _id[] = "$Id: conf.c,v 1.4 1996/10/01 23:07:18 michaels Exp $";*/ +/*static char _id[] = "$Id: conf.c,v 1.5 1996/12/14 21:17:07 downsj Exp $";*/ static void dopr(); static char *end; +static int SnprfOverflow; /* VARARGS3 */ int @@ -2421,30 +2917,34 @@ snprintf(str, count, fmt, va_alist) va_dcl #endif { - VA_LOCAL_DECL + int len; + VA_LOCAL_DECL - VA_START (fmt); - (void) vsnprintf ( str, count, fmt, ap); - VA_END; - return( strlen( str ) ); + VA_START(fmt); + len = vsnprintf(str, count, fmt, ap); + VA_END; + return len; } # ifndef luna2 int vsnprintf(str, count, fmt, args) - char *str; - size_t count; - const char *fmt; - va_list args; + char *str; + size_t count; + const char *fmt; + va_list args; { - str[0] = 0; - end = str+count-1; - dopr( str, fmt, args ); - if( count>0 ){ - end[0] = 0; - } - return(strlen(str)); + str[0] = 0; + end = str + count - 1; + SnprfOverflow = 0; + dopr( str, fmt, args ); + if (count > 0) + end[0] = 0; + if (SnprfOverflow && tTd(57, 2)) + printf("\nvsnprintf overflow, len = %d, str = %s", + count, shortenstring(str, 203)); + return strlen(str); } /* @@ -2460,7 +2960,7 @@ static void dopr_outch __P(( int c )); static void dopr( buffer, format, args ) char *buffer; - char *format; + const char *format; va_list args; { int ch; @@ -2543,8 +3043,11 @@ dopr( buffer, format, args ) fmtnum( value,-16,0, ljust, len, zpad ); break; case 's': strvalue = va_arg( args, char *); - if (maxwidth > 0 || !pointflag) + if (maxwidth > 0 || !pointflag) { + if (pointflag && len > maxwidth) + len = maxwidth; /* Adjust padding */ fmtstr( strvalue,ljust,len,zpad, maxwidth); + } break; case 'c': ch = va_arg( args, int ); @@ -2668,14 +3171,14 @@ dopr_outch( c ) #if 0 if( iscntrl(c) && c != '\n' && c != '\t' ){ c = '@' + (c & 0x1F); - if( end == 0 || output < end ){ + if( end == 0 || output < end ) *output++ = '^'; - } } #endif - if( end == 0 || output < end ){ + if( end == 0 || output < end ) *output++ = c; - } + else + SnprfOverflow++; } # endif /* !luna2 */ @@ -2699,7 +3202,7 @@ dopr_outch( c ) # define _PATH_SHELLS "/etc/shells" # endif -# ifdef _AIX3 +# if defined(_AIX3) || defined(_AIX4) # include <userconf.h> # include <usersec.h> # endif @@ -2727,7 +3230,7 @@ char *DefaultUserShells[] = "/bin/posix/sh", # endif #endif -#ifdef _AIX3 +#if defined(_AIX3) || defined(_AIX4) "/bin/ksh", /* Korn shell */ "/usr/bin/ksh", "/bin/tsh", /* trusted shell */ @@ -3259,9 +3762,9 @@ chownsafe(fd) tfd = open(s, O_RDONLY|O_CREAT, 0600); rval = fchown(tfd, DefUid, DefGid) != 0; close(tfd); - unlink(s); setresuid(o_uid, o_euid, -1); setresgid(o_gid, o_egid, -1); + unlink(s); return rval; #else # ifdef _POSIX_CHOWN_RESTRICTED @@ -3306,7 +3809,7 @@ chownsafe(fd) */ #if HASSETRLIMIT -# ifdef apollo +# ifdef RLIMIT_NEEDS_SYS_TIME_H # include <sys/time.h> # endif # include <sys/resource.h> @@ -3414,10 +3917,26 @@ setvendor(vendor) ** none. */ +#if SHARE_V1 +int DefShareUid; /* default share uid to run as -- unused??? */ +#endif + void vendor_pre_defaults(e) ENVELOPE *e; { +#if SHARE_V1 + /* OTHERUID is defined in shares.h, do not be alarmed */ + DefShareUid = OTHERUID; +#endif +#ifdef SUN_EXTENSIONS + sun_pre_defaults(e); +#endif +#ifdef apollo + /* stupid domain/os can't even open /etc/sendmail.cf without this */ + setuserenv("ISP", NULL); + setuserenv("SYSTYPE", NULL); +#endif } @@ -3425,7 +3944,95 @@ void vendor_post_defaults(e) ENVELOPE *e; { +#ifdef SUN_EXTENSIONS + sun_post_defaults(e); +#endif +} +/* +** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode +*/ + +void +vendor_daemon_setup(e) + ENVELOPE *e; +{ +#if SECUREWARE + if (getluid() != -1) + { + usrerr("Daemon cannot have LUID"); + exit(EX_USAGE); + } +#endif /* SECUREWARE */ +} +/* +** VENDOR_SET_UID -- do setup for setting a user id +** +** This is called when we are still root. +** +** Parameters: +** uid -- the uid we are about to become. +** +** Returns: +** none. +*/ + +void +vendor_set_uid(uid) + UID_T uid; +{ + /* + ** We need to setup the share groups (lnodes) + ** and and auditing inforation (luid's) + ** before we loose our ``root''ness. + */ +#if SHARE_V1 + if (setupshares(uid, syserr) != 0) + syserr("Unable to set up shares"); +#endif +#if SECUREWARE + (void) setup_secure(uid); +#endif +} +/* +** VALIDATE_CONNECTION -- check connection for rationality +** +** If the connection is rejected, this routine should log an +** appropriate message -- but should never issue any SMTP protocol. +** +** Parameters: +** sap -- a pointer to a SOCKADDR naming the peer. +** hostname -- the name corresponding to sap. +** e -- the current envelope. +** +** Returns: +** TRUE -- if the connection should be accepted. +** FALSE -- if it should be rejected. +*/ + +#if TCPWRAPPERS +# include <tcpd.h> +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif + +#if DAEMON +bool +validate_connection(sap, hostname, e) + SOCKADDR *sap; + char *hostname; + ENVELOPE *e; +{ + if (rscheck("check_relay", hostname, anynet_ntoa(sap), e) != EX_OK) + return FALSE; + +#if TCPWRAPPERS + if (!hosts_ctl("sendmail", hostname, anynet_ntoa(sap), STRING_UNKNOWN)) + return FALSE; +#endif + return TRUE; } + +#endif /* ** STRTOL -- convert string to long integer ** @@ -3582,8 +4189,8 @@ sm_gethostbyname(name) char *name; { struct hostent *h; -#if defined(SOLARIS) && SOLARIS < 204 || defined(sony_news) && defined(__svr4) -# if SOLARIS == 203 +#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) +# if SOLARIS == 20300 || SOLARIS == 203 static struct hostent hp; static char buf[1000]; extern struct hostent *_switch_gethostbyname_r(); @@ -3620,7 +4227,7 @@ sm_gethostbyname(name) if (nmaps >= 0) { /* try short name */ - if (strlen(name) > sizeof hbuf - 1) + if (strlen(name) > (SIZE_T) sizeof hbuf - 1) return NULL; strcpy(hbuf, name); shorten_hostname(hbuf); @@ -3651,8 +4258,8 @@ sm_gethostbyaddr(addr, len, type) int len; int type; { -#if defined(SOLARIS) && SOLARIS < 204 -# if SOLARIS == 203 +#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) +# if SOLARIS == 20300 || SOLARIS == 203 static struct hostent hp; static char buf[1000]; extern struct hostent *_switch_gethostbyaddr_r(); @@ -3675,15 +4282,89 @@ struct passwd * sm_getpwnam(user) char *user; { +#ifdef _AIX4 + extern struct passwd *_getpwnam_shadow(const char *, const int); + + return _getpwnam_shadow(user, 0); +#else return getpwnam(user); +#endif } struct passwd * sm_getpwuid(uid) UID_T uid; { +#if defined(_AIX4) && 0 + extern struct passwd *_getpwuid_shadow(const int, const int); + + return _getpwuid_shadow(uid,0); +#else return getpwuid(uid); +#endif +} +/* +** SECUREWARE_SETUP_SECURE -- Convex SecureWare setup +** +** Set up the trusted computing environment for C2 level security +** under SecureWare. +** +** Parameters: +** uid -- uid of the user to initialize in the TCB +** +** Returns: +** none +** +** Side Effects: +** Initialized the user in the trusted computing base +*/ + +#if SECUREWARE + +# include <sys/security.h> +# include <prot.h> + +void +secureware_setup_secure(uid) + UID_T uid; +{ + int rc; + + if (getluid() != -1) + return; + + if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN) + { + switch (rc) + { + case SSI_NO_PRPW_ENTRY: + syserr("No protected passwd entry, uid = %d", uid); + break; + + case SSI_LOCKED: + syserr("Account has been disabled, uid = %d", uid); + break; + + case SSI_RETIRED: + syserr("Account has been retired, uid = %d", uid); + break; + + case SSI_BAD_SET_LUID: + syserr("Could not set LUID, uid = %d", uid); + break; + + case SSI_BAD_SET_PRIVS: + syserr("Could not set kernel privs, uid = %d", uid); + + default: + syserr("Unknown return code (%d) from set_secure_info(%d)", + rc, uid); + break; + } + exit(EX_NOPERM); + } } +#endif /* SECUREWARE */ /* ** LOAD_IF_NAMES -- load interface-specific names into $=w ** @@ -3730,7 +4411,6 @@ load_if_names() close(s); return; } - close(s); /* scan the list of IP address */ if (tTd(0, 40)) @@ -3743,6 +4423,9 @@ load_if_names() struct sockaddr *sa = &ifr->ifr_addr; struct in_addr ia; struct hostent *hp; +#ifdef SIOCGIFFLAGS + struct ifreq ifrf; +#endif char ip_addr[256]; extern char *inet_ntoa(); extern struct hostent *gethostbyaddr(); @@ -3757,19 +4440,35 @@ load_if_names() if (tTd(0, 20)) printf("%s\n", anynet_ntoa((SOCKADDR *) sa)); - /* for some reason gcc 2.3 pukes on || here */ - if (!bitset(IFF_UP, ifr->ifr_flags)) - continue; if (ifr->ifr_addr.sa_family != AF_INET) continue; +#ifdef SIOCGIFFLAGS + bzero(&ifrf, sizeof(struct ifreq)); + strncpy(ifrf.ifr_name, ifr->ifr_name, sizeof(ifrf.ifr_name)); + ioctl(s, SIOCGIFFLAGS, (char *) &ifrf); + if (tTd(0, 41)) + printf("\tflags: %x\n", ifrf.ifr_flags); + if (!bitset(IFF_UP, ifrf.ifr_flags)) + continue; +#else + if (!bitset(IFF_UP, ifr->ifr_flags)) + continue; +#endif + /* extract IP address from the list*/ ia = (((struct sockaddr_in *) sa)->sin_addr); + if (ia.s_addr == INADDR_ANY || ia.s_addr == INADDR_NONE) + { + message("WARNING: interface %s is UP with %s address", + ifr->ifr_name, inet_ntoa(ia)); + continue; + } /* save IP address in text from */ (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]", sizeof ip_addr - 3, - inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); + inet_ntoa(ia)); if (!wordinclass(ip_addr, 'w')) { setclass('w', ip_addr); @@ -3785,8 +4484,12 @@ load_if_names() hp = sm_gethostbyaddr((char *) &ia, sizeof(ia), AF_INET); if (hp == NULL) { - syslog(LOG_CRIT, "gethostbyaddr() failed for %.100s\n", - inet_ntoa(ia)); +#ifdef LOG + if (LogLevel > 3) + syslog(LOG_WARNING, + "gethostbyaddr() failed for %.100s\n", + inet_ntoa(ia)); +#endif continue; } @@ -3810,6 +4513,7 @@ load_if_names() hp->h_aliases++; } } + close(s); #endif } /* @@ -3823,14 +4527,21 @@ load_if_names() # define MAXSYSLOGTRIES 100 # undef syslog +# ifdef V4FS +# define XCNST const +# define CAST (const char *) +# else +# define XCNST +# define CAST +# endif -# ifdef __STDC__ void -hard_syslog(int pri, char *msg, ...) +# ifdef __STDC__ +hard_syslog(int pri, XCNST char *msg, ...) # else hard_syslog(pri, msg, va_alist) int pri; - char *msg; + XCNST char *msg; va_dcl # endif { @@ -3842,10 +4553,11 @@ hard_syslog(pri, msg, va_alist) vsnprintf(buf, sizeof buf, msg, ap); VA_END; - for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; ) + for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; ) continue; } +# undef CAST #endif /* ** LOCAL_HOSTNAME_LENGTH @@ -3891,12 +4603,18 @@ char *CompileOptions[] = #if HES_GETMAILHOST "HES_GETMAILHOST", #endif +#if LDAPMAP + "LDAPMAP", +#endif #ifdef LOG "LOG", #endif #if MATCHGECOS "MATCHGECOS", #endif +#if MIME7TO8 + "MIME7TO8", +#endif #if MIME8TO7 "MIME8TO7", #endif @@ -3933,12 +4651,24 @@ char *CompileOptions[] = #if NISPLUS "NISPLUS", #endif +#if QUEUE + "QUEUE", +#endif #if SCANF "SCANF", #endif +#if SMTP + "SMTP", +#endif +#if SMTPDEBUG + "SMTPDEBUG", +#endif #if SUID_ROOT_FILES_OK "SUID_ROOT_FILES_OK", #endif +#if TCPWRAPPERS + "TCPWRAPPERS", +#endif #if USERDB "USERDB", #endif @@ -3964,6 +4694,9 @@ char *OsCompileOptions[] = #if HASFLOCK "HASFLOCK", #endif +#if HASGETDTABLESIZE + "HASGETDTABLESIZE", +#endif #if HASGETUSERSHELL "HASGETUSERSHELL", #endif @@ -3976,18 +4709,33 @@ char *OsCompileOptions[] = #if HASSETREUID "HASSETREUID", #endif +#if HASSETRLIMIT + "HASSETRLIMIT", +#endif #if HASSETSID "HASSETSID", #endif +#if HASSETUSERCONTEXT + "HASSETUSERCONTEXT", +#endif #if HASSETVBUF "HASSETVBUF", #endif #if HASSNPRINTF "HASSNPRINTF", #endif +#if HASULIMIT + "HASULIMIT", +#endif #if HASUNAME "HASUNAME", #endif +#if HASUNSETENV + "HASUNSETENV", +#endif +#if HASWAITPID + "HASWAITPID", +#endif #if IDENTPROTO "IDENTPROTO", #endif @@ -4000,12 +4748,24 @@ char *OsCompileOptions[] = #if NOFTRUNCATE "NOFTRUNCATE", #endif +#if RLIMIT_NEEDS_SYS_TIME_H + "RLIMIT_NEEDS_SYS_TIME_H", +#endif +#if SECUREWARE + "SECUREWARE", +#endif +#if SHARE_V1 + "SHARE_V1", +#endif #if SYS5SETPGRP "SYS5SETPGRP", #endif #if SYSTEM5 "SYSTEM5", #endif +#if USE_SA_SIGACTION + "USE_SA_SIGACTION", +#endif #if USESETEUID "USESETEUID", #endif diff --git a/usr.sbin/sendmail/src/conf.h b/usr.sbin/sendmail/src/conf.h index 8f8756f534b..ed84c66fa2a 100644 --- a/usr.sbin/sendmail/src/conf.h +++ b/usr.sbin/sendmail/src/conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)conf.h 8.220 (Berkeley) 11/29/95 + * @(#)conf.h 8.279 (Berkeley) 12/1/96 */ /* @@ -41,7 +41,9 @@ ** included in the next release. */ +#ifdef __GNUC__ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ +#endif # include <sys/param.h> # include <sys/types.h> @@ -66,7 +68,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define MAXMAILERS 25 /* maximum mailers known to system */ # define MAXRWSETS 200 /* max # of sets of rewriting rules */ # define MAXPRIORITIES 25 /* max values for Precedence: field */ -# define MAXMXHOSTS 20 /* max # of MX records */ +# define MAXMXHOSTS 100 /* max # of MX records for one host */ # define SMTPLINELIM 990 /* maximum SMTP line length */ # define MAXKEY 128 /* maximum size of a database key */ # define MEMCHUNKSIZE 1024 /* chunk size for memory allocation */ @@ -183,9 +185,6 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */ # endif # define syslog hard_syslog -# ifdef __STDC__ -extern void hard_syslog(int, char *, ...); -# endif # ifdef V4FS /* HP-UX 10.x */ @@ -205,12 +204,29 @@ extern void hard_syslog(int, char *, ...); # ifndef IDENTPROTO # define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif +# ifdef __STDC__ +extern void hard_syslog(int, char *, ...); +# endif # endif #endif /* +** IBM AIX 4.x +*/ + +#ifdef _AIX4 +# define _AIX3 1 /* pull in AIX3 stuff */ +# define USESETEUID 1 /* seteuid(2) works */ +# define TZ_TYPE TZ_NAME /* use tzname[] vector */ +# if _AIX4 >= 40200 +# define HASSETREUID 1 /* setreuid(2) works as of AIX 4.2 */ +# endif +#endif + + +/* ** IBM AIX 3.x -- actually tested for 3.2.3 */ @@ -222,29 +238,89 @@ extern void hard_syslog(int, char *, ...); # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define IP_SRCROUTE 0 /* Something is broken with getsockopt() */ -# define FORK fork /* no vfork primitive available */ # define GIDSET_T gid_t # define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */ # define SPT_PADCHAR '\0' /* pad process title with nulls */ # define LA_TYPE LA_INT +# define FSHIFT 16 # define LA_AVENRUN "avenrun" #endif /* +** IBM AIX 2.2.1 -- actually tested for osupdate level 2706+1773 +** +** From Mark Whetzel <markw@wg.waii.com>. +*/ + +#ifdef AIX /* AIX/RT compiler pre-defines this */ +# include <paths.h> +# include <sys/time.h> /* AIX/RT resource.h does NOT include this */ +# define HASINITGROUPS 1 /* has initgroups(3) call */ +# define HASUNAME 1 /* use System V uname(2) system call */ +# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ +# define HASFCHMOD 0 /* does not have fchmod(2) syscall */ +# define HASSETREUID 1 /* use setreuid(2) -lbsd system call */ +# define HASSETVBUF 1 /* use setvbuf(2) system call */ +# define HASSETRLIMIT 0 /* does not have setrlimit call */ +# define HASFLOCK 0 /* does not have flock call - use fcntl */ +# define HASULIMIT 1 /* use ulimit instead of setrlimit call */ +# define NEEDGETOPT 1 /* Do we need theirs or ours */ +# define SYS5SETPGRP 1 /* don't have setpgid on AIX/RT */ +# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */ +# define BSD4_3 1 /* NOT bsd 4.4 or posix signals */ +# define GIDSET_T int +# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */ +# define SPT_PADCHAR '\0' /* pad process title with nulls */ +# define LA_TYPE LA_SUBR /* use our ported loadavgd daemon */ +# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ +# define ARBPTR_T int * +# define void int +typedef int pid_t; +/* RTisms for BSD compatibility, specified in the Makefile + define BSD 1 + define BSD_INCLUDES 1 + define BSD_REMAP_SIGNAL_TO_SIGVEC + RTisms needed above */ +/* make this sendmail in a completely different place */ +# define _PATH_VENDORCF "/usr/local/newmail/sendmail.cf" +# ifndef _PATH_SENDMAILPID +# define _PATH_SENDMAILPID "/usr/local/newmail/sendmail.pid" +# endif +#endif + + +/* ** Silicon Graphics IRIX ** ** Compiles on 4.0.1. ** ** Use IRIX64 instead of IRIX for 64-bit IRIX (6.0). ** Use IRIX5 instead of IRIX for IRIX 5.x. +** +** This version tries to be adaptive using _MIPS_SIM: +** _MIPS_SIM == _ABIO32 (= 1) Abi: -32 on IRIX 6.2 +** _MIPS_SIM == _ABIN32 (= 2) Abi: -n32 on IRIX 6.2 +** _MIPS_SIM == _ABI64 (= 3) Abi: -64 on IRIX 6.2 +** +** _MIPS_SIM is 1 also on IRIX 5.3 ** ** IRIX64 changes from Mark R. Levinson <ml@cvdev.rochester.edu>. ** IRIX5 changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>. +** Adaptive changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>. */ -#if defined(IRIX64) || defined(IRIX5) -# define IRIX +#if defined(__sgi) +# ifndef IRIX +# define IRIX +# endif +# if _MIPS_SIM > 0 && !defined(IRIX5) +# define IRIX5 /* IRIX5 or IRIX6 */ +# endif +# if _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64) +# define IRIX6 /* IRIX6 */ +# endif + #endif #ifdef IRIX @@ -254,18 +330,24 @@ extern void hard_syslog(int, char *, ...); # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # define IP_SRCROUTE 1 /* can check IP source routing */ -# define FORK fork /* no vfork primitive available */ # define setpgid BSDsetpgrp # define GIDSET_T gid_t # define SFS_TYPE SFS_4ARGS /* four argument statfs() call */ # define SFS_BAVAIL f_bfree /* alternate field name */ -# define LA_TYPE LA_INT -# ifdef IRIX64 -# define NAMELISTMASK 0x7fffffffffffffff /* mask for nlist() values */ +# ifdef IRIX6 +# define LA_TYPE LA_IRIX6 /* figure out at run time */ # else -# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */ +# define LA_TYPE LA_INT + +# ifdef IRIX64 +# define NAMELISTMASK 0x7fffffffffffffff /* mask for nlist() values */ +# else +# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */ +# endif # endif -# if defined(IRIX64) || defined(IRIX5) +# if defined(IRIX64) || defined(IRIX5) +# include <sys/cdefs.h> +# include <paths.h> # define ARGV_T char *const * # define HASSETRLIMIT 1 /* has setrlimit(2) syscall */ # define HASGETDTABLESIZE 1 /* has getdtablesize(2) syscall */ @@ -290,10 +372,16 @@ extern void hard_syslog(int, char *, ...); # define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define IP_SRCROUTE 1 /* can check IP source routing */ -# define LA_TYPE LA_INT +# ifndef LA_TYPE +# define LA_TYPE LA_INT +# endif # ifdef SOLARIS_2_3 -# define SOLARIS 203 /* for back compat only -- use -DSOLARIS=203 */ +# define SOLARIS 20300 /* for back compat only -- use -DSOLARIS=20300 */ +# endif + +# if defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# define SOLARIS 1 /* unknown Solaris version */ # endif # ifdef SOLARIS @@ -303,6 +391,7 @@ extern void hard_syslog(int, char *, ...); # endif # include <sys/time.h> # define GIDSET_T gid_t +# define USE_SA_SIGACTION 1 /* use sa_sigaction field */ # ifndef _PATH_UNIX # define _PATH_UNIX "/dev/ksyms" # endif @@ -316,6 +405,23 @@ extern void hard_syslog(int, char *, ...); # ifndef SYSLOG_BUFSIZE # define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */ # endif +# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) +# define USESETEUID 1 /* seteuid works as of 2.3 */ +# endif +# if SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) +# define HASSNPRINTF 1 /* has snprintf starting in 2.5 */ +# define HASSETREUID 1 /* setreuid works as of 2.5 */ +# if SOLARIS == 20500 || SOLARIS == 205 +# define snprintf __snprintf /* but names it oddly in 2.5 */ +# define vsnprintf __vsnprintf +# endif +# ifndef LA_TYPE +# define LA_TYPE LA_KSTAT /* use kstat(3k) -- may work in < 2.5 */ +# endif +# endif +# ifndef HASGETUSERSHELL +# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */ +# endif # else /* SunOS 4.0.3 or 4.1.x */ @@ -337,6 +443,7 @@ extern void hard_syslog(int, char *, ...); # undef WEXITSTATUS # undef HASUNAME # define setpgid setpgrp +# define MODE_T int typedef int pid_t; extern char *getenv(); @@ -370,6 +477,7 @@ extern char *getenv(); # define HASINITGROUPS 1 /* has initgroups(3) call */ # define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */ # define HASGETUSERSHELL 0 /* does not have getusershell(3) */ +# define HASSNPRINTF 1 /* has snprintf(3) */ # ifndef IDENTPROTO # define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif @@ -432,8 +540,6 @@ extern long dgux_inet_addr(); #ifdef __ksr__ # define __osf__ 1 /* get OSF/1 defines below */ -# define FORK fork /* no vfork primitive available */ -# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf" # ifndef TZ_TYPE # define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ # endif @@ -449,12 +555,16 @@ extern long dgux_inet_addr(); #ifdef __PARAGON__ # define __osf__ 1 /* get OSF/1 defines below */ -# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf" +# ifndef TZ_TYPE +# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ +# endif #endif /* -** OSF/1 (tested on Alpha) +** OSF/1 (tested on Alpha) -- now known as Digital UNIX. +** +** Tested for 3.2 and 4.0. */ #ifdef __osf__ @@ -466,8 +576,9 @@ extern long dgux_inet_addr(); # ifndef HASFLOCK # define HASFLOCK 1 /* has flock(2) call */ # endif -# define LA_TYPE LA_INT +# define LA_TYPE LA_ALPHAOSF # define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */ +# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf" # ifndef _PATH_SENDMAILPID # define _PATH_SENDMAILPID "/var/run/sendmail.pid" # endif @@ -487,6 +598,8 @@ extern long dgux_inet_addr(); # define NEEDGETOPT 1 /* need a replacement for getopt(3) */ # define WAITUNION 1 /* use "union wait" as wait argument type */ # define UID_T int /* compiler gripes on uid_t */ +# define GID_T int /* ditto for gid_t */ +# define MODE_T int /* and mode_t */ # define sleep sleepX # define setpgid setpgrp # ifndef LA_TYPE @@ -518,7 +631,6 @@ typedef int pid_t; # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */ # include <sys/cdefs.h> -# include <paths.h> /* for _PATH_VARTMP */ # define ERRLIST_PREDEFINED /* don't declare sys_errlist */ # define BSD4_4_SOCKADDR /* has sa_len */ # define NETLINK 1 /* supports AF_LINK */ @@ -531,11 +643,12 @@ typedef int pid_t; /* -** BSD/386 (all versions) +** BSD/OS (was BSD/386) (all versions) ** From Tony Sanders, BSDI */ #ifdef __bsdi__ +# include <paths.h> # define HASUNSETENV 1 /* has the unsetenv(3) call */ # define HASSETSID 1 /* has the setsid(2) POSIX syscall */ # define USESETEUID 1 /* has useable seteuid(2) call */ @@ -567,7 +680,7 @@ typedef int pid_t; /* -** FreeBSD / NetBSD (all architectures, all versions) +** FreeBSD / NetBSD / OpenBSD (all architectures, all versions) ** ** 4.3BSD clone, closer to 4.4BSD for FreeBSD 1.x and NetBSD 0.9x ** 4.4BSD-Lite based for FreeBSD 2.x and NetBSD 1.x @@ -575,7 +688,8 @@ typedef int pid_t; ** See also BSD defines. */ -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +# include <paths.h> # define HASUNSETENV 1 /* has unsetenv(3) call */ # define HASSETSID 1 /* has the setsid(2) POSIX syscall */ # define USESETEUID 1 /* has useable seteuid(2) call */ @@ -594,11 +708,29 @@ typedef int pid_t; # if defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1) # undef SPT_TYPE # define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */ -# define setreuid __setreuid +# endif +# if defined(__OpenBSD__) +# undef SPT_TYPE +# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */ +# endif +# if defined(__FreeBSD__) +# undef SPT_TYPE +# if __FreeBSD__ == 2 +# include <osreldate.h> /* and this works */ +# if __FreeBSD_version >= 199512 /* 2.2-current right now */ +# include <libutil.h> +# define SPT_TYPE SPT_BUILTIN +# endif +# endif +# ifndef SPT_TYPE +# define SPT_TYPE SPT_REUSEARGV +# define SPT_PADCHAR '\0' /* pad process title with nulls */ +# endif # endif #endif + /* ** Mach386 ** @@ -660,36 +792,76 @@ extern int errno; /* ** SCO Unix ** -** This includes two parts -- the first is for SCO Open Server 3.2v4 -** (contributed by Philippe Brand <phb@colombo.telesys-innov.fr>). -** The second is, I believe, for an older version. +** This includes three parts: +** +** The first is for SCO OpenServer 5. +** (Contributed by Keith Reynolds <keithr@sco.COM>). +** +** SCO OpenServer 5 has a compiler version number macro, +** which we can use to figure out what version we're on. +** This may have to change in future releases. +** +** The second is for SCO UNIX 3.2v4.2/Open Desktop 3.0. +** (Contributed by Philippe Brand <phb@colombo.telesys-innov.fr>). +** +** The third is for SCO UNIX 3.2v4.0/Open Desktop 2.0 and earlier. */ +/* SCO OpenServer 5 */ +#if _SCO_DS >= 1 +# include <paths.h> +# define _SCO_unix_4_2 +# define HASSNPRINTF 1 /* has snprintf(3) call */ +# define HASFCHMOD 1 /* has fchmod(2) call */ +# define HASSETRLIMIT 1 /* has setrlimit(2) call */ +# define USESETEUID 1 /* has seteuid(2) call */ +# define HASINITGROUPS 1 /* has initgroups(3) call */ +# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */ +# define RLIMIT_NEEDS_SYS_TIME_H 1 +# ifndef LA_TYPE +# define LA_TYPE LA_DEVSHORT +# endif +# define _PATH_AVENRUN "/dev/table/avenrun" +#endif + +/* SCO UNIX 3.2v4.2/Open Desktop 3.0 */ #ifdef _SCO_unix_4_2 # define _SCO_unix_ # define HASSETREUID 1 /* has setreuid(2) call */ -# define _PATH_UNIX "/unix" -# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf" -# ifndef _PATH_SENDMAILPID -# define _PATH_SENDMAILPID "/etc/sendmail.pid" -# endif #endif +/* SCO UNIX 3.2v4.0 Open Desktop 2.0 and earlier */ #ifdef _SCO_unix_ # include <sys/stream.h> /* needed for IP_SRCROUTE */ # define SYSTEM5 1 /* include all the System V defines */ -# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */ # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ -# define NOFTRUNCATE 0 /* does not have ftruncate(3) call */ -# define NEEDFSYNC 1 /* needs the fsync(2) call stub */ -# define FORK fork +# define NOFTRUNCATE 0 /* has (simulated) ftruncate call */ # define MAXPATHLEN PATHSIZE -# define LA_TYPE LA_SHORT # define SFS_TYPE SFS_4ARGS /* use <sys/statfs.h> 4-arg impl */ # define SFS_BAVAIL f_bfree /* alternate field name */ # define SPT_TYPE SPT_SCO /* write kernel u. area */ # define TZ_TYPE TZ_TM_NAME /* use tm->tm_name */ -# define NETUNIX 0 /* no unix domain socket support */ +# define UID_T uid_t +# define GID_T gid_t +# define GIDSET_T gid_t +# define _PATH_UNIX "/unix" +# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf" +# ifndef _PATH_SENDMAILPID +# define _PATH_SENDMAILPID "/etc/sendmail.pid" +# endif + +/* stuff fixed in later releases */ +# ifndef _SCO_unix_4_2 +# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */ +# endif + +# ifndef _SCO_DS +# define ftruncate chsize /* use chsize(2) to emulate ftruncate */ +# define NEEDFSYNC 1 /* needs the fsync(2) call stub */ +# define NETUNIX 0 /* no unix domain socket support */ +# define LA_TYPE LA_SHORT +# endif + #endif @@ -709,7 +881,6 @@ extern int errno; # define HASSETREUID 1 /* has setreuid(2) call */ # define NEEDFSYNC 1 /* needs the fsync(2) call stub */ # define NETUNIX 0 /* no unix domain socket support */ -# define FORK fork # define MAXPATHLEN 1024 # define LA_TYPE LA_SHORT # define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */ @@ -724,22 +895,24 @@ extern int errno; /* -** Altos System V. -** Contributed by Tim Rice <timr@crl.com>. +** Altos System V (5.3.1) +** Contributed by Tim Rice <tim@trr.metro.net>. */ -#ifdef ALTOS_SYS_V +#ifdef ALTOS_SYSTEM_V +# include <sys/stream.h> +# include <limits.h> # define SYSTEM5 1 /* include all the System V defines */ # define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */ # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # define WAITUNION 1 /* use "union wait" as wait argument type */ # define NEEDFSYNC 1 /* no fsync(2) in system library */ -# define FORK fork -# define MAXPATHLEN PATHSIZE +# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */ +# define MAXPATHLEN PATH_MAX # define LA_TYPE LA_SHORT # define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */ # define SFS_BAVAIL f_bfree /* alternate field name */ -# define TZ_TYPE TZ_TM_NAME /* use tm->tm_name */ +# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ # define NETUNIX 0 /* no unix domain socket support */ # undef WIFEXITED # undef WEXITSTATUS @@ -748,6 +921,17 @@ extern int errno; typedef unsigned short uid_t; typedef unsigned short gid_t; typedef short pid_t; + +/* some stuff that should have been in the include files */ +# include <grp.h> +extern char *malloc(); +extern struct passwd *getpwent(); +extern struct passwd *getpwnam(); +extern struct passwd *getpwuid(); +extern char *getenv(); +extern struct group *getgrgid(); +extern struct group *getgrnam(); + #endif @@ -756,13 +940,26 @@ typedef short pid_t; ** ** "Todd C. Miller" <millert@mroe.cs.colorado.edu> claims this ** works on 9.1 as well. +** +** ConvexOS 11.5 and later, should work on 11.0 as defined. +** For pre-ConvexOOS 11.0, define NEEDGETOPT, undef IDENTPROTO +** +** Eric Schnoebelen (eric@cirr.com) For CONVEX Computer Corp. +** (now the CONVEX Technologies Center of Hewlett Packard) */ #ifdef _CONVEX_SOURCE -# define BSD 1 /* include all the BSD defines */ +# define HASGETDTABLESIZE 1 /* has getdtablesize(2) */ +# define HASINITGROUPS 1 /* has initgroups(3) */ # define HASUNAME 1 /* use System V uname(2) system call */ # define HASSETSID 1 /* has POSIX setsid(2) call */ -# define NEEDGETOPT 1 /* need replacement for getopt(3) */ +# define HASUNSETENV 1 /* has unsetenv(3) */ +# define HASFLOCK 1 /* has flock(2) */ +# define HASSETRLIMIT 1 /* has setrlimit(2) */ +# define HASSETREUID 1 /* has setreuid(2) */ +# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_error=0 */ +# define NEEDPUTENV 1 /* needs putenv (written in terms of setenv) */ +# define NEEDGETOPT 0 /* need replacement for getopt(3) */ # define IP_SRCROUTE 0 /* Something is broken with getsockopt() */ # define LA_TYPE LA_FLOAT # define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */ @@ -775,8 +972,23 @@ typedef short pid_t; # define S_IFCHR _S_IFCHR # define S_IFBLK _S_IFBLK # endif +# ifndef TZ_TYPE +# define TZ_TYPE TZ_TIMEZONE +# endif # ifndef IDENTPROTO -# define IDENTPROTO 0 /* TCP/IP implementation is broken */ +# define IDENTPROTO 1 +# endif +# ifndef SHARE_V1 +# define SHARE_V1 1 /* version 1 of the fair share scheduler */ +# endif +# if !defined(__GNUC__ ) +# define UID_T int /* GNUC gets it right, ConvexC botches */ +# define GID_T int /* GNUC gets it right, ConvexC botches */ +# endif +# if SECUREWARE +# define FORK fork /* SecureWare wants the real fork! */ +# else +# define FORK vfork /* the rest of the OS versions don't care */ # endif #endif @@ -827,9 +1039,14 @@ extern void *malloc(); ** Florian La Roche <rzsfl@rz.uni-sb.de> ** Karl London <karl@borg.demon.co.uk> ** -** Last compiled against: [09/06/95 @ 10:20:58 AM (Wednesday)] -** sendmail 8.7-b14 named 4.9.3-beta17 db-1.85 -** gcc 2.7.0 libc-5.2.7 linux 1.2.13 +** Last compiled against: [06/10/96 @ 09:21:40 PM (Monday)] +** sendmail 8.8-a4 named bind-4.9.4-T4B db-1.85 +** gcc 2.7.2 libc-5.3.12 linux 2.0.0 +** +** NOTE: Override HASFLOCK as you will but, as of 1.99.6, mixed-style +** file locking is no longer allowed. In particular, make sure +** your DBM library and sendmail are both using either flock(2) +** *or* fcntl(2) file locking, but not both. */ #ifdef __linux__ @@ -845,7 +1062,12 @@ extern void *malloc(); # define HASGETUSERSHELL 0 /* getusershell(3) broken in Slackware 2.0 */ # define IP_SRCROUTE 0 /* linux <= 1.2.8 doesn't support IP_OPTIONS */ # ifndef HASFLOCK -# define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */ +# include <linux/version.h> +# if LINUX_VERSION_CODE < 66399 +# define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */ +# else +# define HASFLOCK 1 /* flock(2) fixed after 1.3.95 */ +# endif # endif # ifndef LA_TYPE # define LA_TYPE LA_PROCSTR @@ -895,7 +1117,6 @@ extern void *malloc(); # ifndef IDENTPROTO # define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif -# define FORK fork # ifndef LA_TYPE # define LA_TYPE LA_INT # define FSHIFT 16 @@ -925,7 +1146,6 @@ extern void *malloc(); # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */ # define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */ -# define FORK fork /* no vfork(2) primitive available */ # define SFS_TYPE SFS_4ARGS /* four argument statfs() call */ # define MAXPATHLEN PATH_MAX extern struct passwd *getpwent(), *getpwnam(), *getpwuid(); @@ -998,9 +1218,12 @@ typedef int pid_t; ** For DYNIX/ptx v1.x, undefine HASSETREUID. ** ** From Tim Wright <timw@sequent.com>. +** Update from Jack Woolley <jwoolley@sctcorp.com>, 26 Dec 1995, +** for DYNIX/ptx 4.0.2. */ #ifdef _SEQUENT_ +# include <sys/stream.h> # define SYSTEM5 1 /* include all the System V defines */ # define HASSETSID 1 /* has POSIX setsid(2) call */ # define HASINITGROUPS 1 /* has initgroups(3) call */ @@ -1064,6 +1287,7 @@ typedef int pid_t; # ifndef IDENTPROTO # define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif +# define RLIMIT_NEEDS_SYS_TIME_H 1 #endif @@ -1126,18 +1350,30 @@ typedef int pid_t; /* -** NCR 3000 Series (SysVr4) +** NCR MP-RAS 2.x (SysVr4) with Wollongong TCP/IP ** ** From Kevin Darcy <kevin@tech.mis.cfc.com>. */ -#ifdef NCR3000 +#ifdef NCR_MP_RAS2 # include <sys/sockio.h> # define __svr4__ # define IP_SRCROUTE 0 /* Something is broken with getsockopt() */ -# undef BSD -# define LA_AVENRUN "avenrun" # define SYSLOG_BUFSIZE 1024 +# define SPT_TYPE SPT_NONE +#endif + + +/* +** NCR MP-RAS 3.x (SysVr4) with STREAMware TCP/IP +** +** From Tom Moore <Tom.Moore@DaytonOH.NCR.COM> +*/ + +#ifdef NCR_MP_RAS3 +# define __svr4__ +# define SYSLOG_BUFSIZE 1024 +# define SPT_TYPE SPT_NONE #endif @@ -1205,7 +1441,6 @@ extern int syslog(int, char *, ...); # define HASUNAME 1 /* use System V uname(2) system call */ # define HASINITGROUPS 1 /* has initgroups(3) function */ # define HASSETVBUF 1 /* has setvbuf(3) function */ -# define HASSIGSETMASK 0 /* does not have sigsetmask(2) function */ # ifndef HASGETUSERSHELL # define HASGETUSERSHELL 0 /* does not have getusershell(3) function */ # endif @@ -1259,6 +1494,7 @@ extern struct group *getgrent(), *getgrnam(), *getgrgid(); # define setpgid setpgrp # undef WIFEXITED # undef WEXITSTATUS +# define MODE_T int /* system include files have no mode_t */ typedef int pid_t; typedef int (*sigfunc_t)(); # define SIGFUNC_DEFINED @@ -1360,20 +1596,75 @@ extern int errno; ** Fujitsu/ICL UXP/DS (For the DS/90 Series) ** ** From Diego R. Lopez <drlopez@cica.es>. +** Additional changes from Fumio Moriya and Toshiaki Nomura of the +** Fujitsu Fresoftware gruop <dsfrsoft@oai6.yk.fujitsu.co.jp>. */ -#ifdef UXPDS +#ifdef __uxp__ +# include <arpa/nameser.h> +# include <sys/sysmacros.h> +# include <sys/mkdev.h> # define __svr4__ -# define HASGETUSERSHELL 1 +# define HASGETUSERSHELL 0 # define HASFLOCK 0 +# if UXPDS == 10 +# define HASSNPRINTF 0 /* no snprintf(3) or vsnprintf(3) */ +# else +# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */ +# endif # define _PATH_UNIX "/stand/unix" -# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf" +# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf" # ifndef _PATH_SENDMAILPID -# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid" +# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid" # endif #endif +/* +** Pyramid DC/OSx +** +** From Earle Ake <akee@wpdis01.wpafb.af.mil>. +*/ + +#ifdef DCOSx +# define GIDSET_T gid_t +# ifndef IDENTPROTO +# define IDENTPROTO 0 /* TCP/IP implementation is broken */ +# endif +#endif +/* +** Concurrent Computer Corporation Maxion +** +** From Donald R. Laster Jr. <laster@access.digex.net>. +*/ + +#ifdef __MAXION__ + +# include <sys/stream.h> +# define __svr4__ 1 /* SVR4.2MP */ +# define HASSETREUID 1 /* have setreuid(2) */ +# define HASLSTAT 1 /* have lstat(2) */ +# define HASSETRLIMIT 1 /* have setrlimit(2) */ +# define HASGETDTABLESIZE 1 /* have getdtablesize(2) */ +# define HASSNPRINTF 1 /* have snprintf(3) */ +# define HASGETUSERSHELL 1 /* have getusershell(3) */ +# define NOFTRUNCATE 1 /* do not have ftruncate(2) */ +# define SLEEP_T unsigned +# define SFS_TYPE SFS_STATVFS +# define SFS_BAVAIL f_bavail +# ifndef SYSLOG_BUFSIZE +# define SYSLOG_BUFSIZE 256 /* Use 256 bytes */ +# endif + +# undef WUNTRACED +# undef WIFEXITED +# undef WIFSIGNALED +# undef WIFSTOPPED +# undef WEXITSTATUS +# undef WTERMSIG +# undef WSTOPSIG + +#endif /********************************************************************** ** End of Per-Operating System defines @@ -1406,13 +1697,16 @@ extern int errno; # define SYSTEM5 1 # define USESETEUID 1 /* has useable seteuid(2) call */ # define HASINITGROUPS 1 /* has initgroups(3) call */ -# define BSD_COMP 1 /* get BSD ioctl calls */ +# define BSD_COMP 1 /* get BSD ioctl calls */ # ifndef HASSETRLIMIT # define HASSETRLIMIT 1 /* has setrlimit(2) call */ # endif # ifndef HASGETUSERSHELL # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # endif +# ifndef HASFCHMOD +# define HASFCHMOD 1 /* most (all?) SVr4s seem to have fchmod(2) */ +# endif # ifndef _PATH_UNIX # define _PATH_UNIX "/unix" @@ -1430,6 +1724,7 @@ extern int errno; # define SFS_TYPE SFS_STATVFS # endif +/* SVr4 uses different routines for setjmp/longjmp with signal support */ # define jmp_buf sigjmp_buf # define setjmp(env) sigsetjmp(env, 1) # define longjmp(env, val) siglongjmp(env, val) @@ -1487,7 +1782,7 @@ extern int errno; # undef bcopy /* despite SystemV claim, uses BSD bcopy */ #endif -#ifdef ALTOS_SYS_V +#ifdef ALTOS_SYSTEM_V # undef bcopy /* despite SystemV claim, uses BSD bcopy */ # undef bzero /* despite SystemV claim, uses BSD bzero */ # undef bcmp /* despite SystemV claim, uses BSD bcmp */ @@ -1549,13 +1844,8 @@ extern int errno; # define OLD_NEWDB 0 /* assume newer version of newdb */ #endif -/* heuristic setting of HASSETSIGMASK; can override above */ -#ifndef HASSIGSETMASK -# ifdef SIGVTALRM -# define HASSETSIGMASK 1 -# else -# define HASSETSIGMASK 0 -# endif +#ifndef SECUREWARE +# define SECUREWARE 0 /* assume no SecureWare C2 auditing hooks */ #endif /* @@ -1572,10 +1862,18 @@ extern int errno; # define UID_T uid_t #endif +#ifndef GID_T +# define GID_T gid_t +#endif + #ifndef SIZE_T # define SIZE_T size_t #endif +#ifndef MODE_T +# define MODE_T mode_t +#endif + #ifndef ARGV_T # define ARGV_T char ** #endif @@ -1589,6 +1887,9 @@ extern int errno; #ifndef S_ISREG # define S_ISREG(foo) ((foo & S_IFMT) == S_IFREG) #endif +#ifndef S_ISDIR +# define S_ISDIR(foo) ((foo & S_IFMT) == S_IFDIR) +#endif #if !defined(S_ISLNK) && defined(S_IFLNK) # define S_ISLNK(foo) ((foo & S_IFMT) == S_IFLNK) #endif @@ -1614,6 +1915,9 @@ extern int errno; /* pseudo-code used in server SMTP */ # define EX_QUIT 22 /* drop out of server immediately */ +/* pseudo-code used for mci_setstat */ +# define EX_NOTSTICKY -5 /* don't save persistent status */ + /* ** These are used in a few cases where we need some special @@ -1676,9 +1980,15 @@ extern int h_errno; */ #if NETINET || NETISO -# define SMTP 1 /* enable user and server SMTP */ -# define QUEUE 1 /* enable queueing */ -# define DAEMON 1 /* include the daemon (requires IPC & SMTP) */ +# ifndef SMTP +# define SMTP 1 /* enable user and server SMTP */ +# endif +# ifndef QUEUE +# define QUEUE 1 /* enable queueing */ +# endif +# ifndef DAEMON +# define DAEMON 1 /* include the daemon (requires IPC & SMTP) */ +# endif #endif @@ -1717,7 +2027,7 @@ struct utsname }; #endif /* HASUNAME */ -#if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYS_V) +#if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V) # define MAXHOSTNAMELEN 256 #endif @@ -1797,9 +2107,10 @@ typedef void (*sigfunc_t) __P((int)); */ # define PSBUFSIZE (MAXNAME + MAXATOM) /* size of prescan buffer */ + /* fork routine -- set above using #ifdef _osname_ or in Makefile */ # ifndef FORK -# define FORK vfork /* function to call to fork mailer */ +# define FORK fork /* function to call to fork mailer */ # endif /* diff --git a/usr.sbin/sendmail/src/convtime.c b/usr.sbin/sendmail/src/convtime.c index adc38f73ed5..65994f88758 100644 --- a/usr.sbin/sendmail/src/convtime.c +++ b/usr.sbin/sendmail/src/convtime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)convtime.c 8.4.1.1 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)convtime.c 8.8 (Berkeley) 11/24/96"; #endif /* not lint */ # include "sendmail.h" @@ -149,7 +149,10 @@ pintvl(intvl, brief) hr = intvl % 24; intvl /= 24; if (brief) + { dy = intvl; + wk = 0; + } else { dy = intvl % 7; diff --git a/usr.sbin/sendmail/src/daemon.c b/usr.sbin/sendmail/src/daemon.c index 48aafb70e01..c8516fc48a4 100644 --- a/usr.sbin/sendmail/src/daemon.c +++ b/usr.sbin/sendmail/src/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -37,28 +37,29 @@ #ifndef lint #ifdef DAEMON -static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (with daemon mode)"; +static char sccsid[] = "@(#)daemon.c 8.156 (Berkeley) 12/1/96 (with daemon mode)"; #else -static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (without daemon mode)"; +static char sccsid[] = "@(#)daemon.c 8.156 (Berkeley) 12/1/96 (without daemon mode)"; #endif #endif /* not lint */ -#ifdef DAEMON - +#if DAEMON || defined(SOCK_STREAM) # include <arpa/inet.h> - -#if NAMED_BIND -# include <resolv.h> -# ifndef NO_DATA -# define NO_DATA NO_ADDRESS +# if NAMED_BIND +# include <resolv.h> +# ifndef NO_DATA +# define NO_DATA NO_ADDRESS +# endif # endif #endif -#if IP_SRCROUTE -# include <netinet/in_systm.h> -# include <netinet/ip.h> -# include <netinet/ip_var.h> -#endif +#if DAEMON + +# if IP_SRCROUTE +# include <netinet/in_systm.h> +# include <netinet/ip.h> +# include <netinet/ip_var.h> +# endif /* ** DAEMON.C -- routines to use when running as a daemon. @@ -70,7 +71,7 @@ static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (without daemo ** thing yourself, I recommend chucking the entire file ** and starting from scratch. Basic semantics are: ** -** getrequests() +** getrequests(e) ** Opens a port and initiates a connection. ** Returns in a child. Must set InChannel and ** OutChannel appropriately. @@ -80,7 +81,7 @@ static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (without daemo ** etc., to avoid having extra file descriptors during ** the queue run and to avoid confusing the network ** code (if it cares). -** makeconnection(host, port, outfile, infile, usesecureport) +** makeconnection(host, port, outfile, infile, e) ** Make a connection to the named host on the given ** port. Set *outfile and *infile to the files ** appropriate for communication. Returns zero on @@ -93,10 +94,12 @@ static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (without daemo ** GETREQUESTS -- open mail IPC port and get requests. ** ** Parameters: -** none. +** e -- the current envelope. ** ** Returns: -** none. +** TRUE -- if a "null server" should be used -- that is, one +** that rejects all commands. +** FALSE -- to use a normal server. ** ** Side Effects: ** Waits until some interesting activity occurs. When @@ -113,8 +116,9 @@ int ListenQueueSize = 10; /* size of listen queue */ int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ int TcpSndBufferSize = 0; /* size of TCP send buffer */ -void -getrequests() +bool +getrequests(e) + ENVELOPE *e; { int t; bool refusingconnections = TRUE; @@ -124,6 +128,7 @@ getrequests() bool j_has_dot; #endif extern void reapchild(); + extern int opendaemonsocket __P((bool)); /* ** Set up the address for the mailer. @@ -166,7 +171,7 @@ getrequests() extern char *CommandLineArgs; /* write the process id on line 1 */ - fprintf(pidf, "%d\n", getpid()); + fprintf(pidf, "%ld\n", (long) getpid()); /* line 2 contains all command line flags */ fprintf(pidf, "%s\n", CommandLineArgs); @@ -179,7 +184,7 @@ getrequests() { char jbuf[MAXHOSTNAMELEN]; - expand("\201j", jbuf, sizeof jbuf, CurEnv); + expand("\201j", jbuf, sizeof jbuf, e); j_has_dot = strchr(jbuf, '.') != NULL; } #endif @@ -189,14 +194,16 @@ getrequests() for (;;) { - register int pid; + register pid_t pid; auto int lotherend; + int savederrno; + int pipefd[2]; extern bool refuseconnections(); extern int getla(); /* see if we are rejecting connections */ - CurrentLA = getla(); - if (refuseconnections()) + (void) blocksignal(SIGALRM); + if (refuseconnections(ntohs(DaemonAddr.sin.sin_port))) { if (DaemonSocket >= 0) { @@ -220,8 +227,9 @@ getrequests() /* check for disaster */ { char jbuf[MAXHOSTNAMELEN]; + extern void dumpstate __P((char *)); - expand("\201j", jbuf, sizeof jbuf, CurEnv); + expand("\201j", jbuf, sizeof jbuf, e); if (!wordinclass(jbuf, 'w')) { dumpstate("daemon lost $j"); @@ -238,7 +246,19 @@ getrequests() #endif /* wait for a connection */ - setproctitle("accepting connections"); + setproctitle("accepting connections on port %d", + ntohs(DaemonAddr.sin.sin_port)); +#if 0 + /* + ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will + ** fix the SVr4 problem. But it seems to have gone away, + ** so is it worth doing this? + */ + + if (SetNonBlocking(DaemonSocket, FALSE) < 0) + log an error here; +#endif + (void) releasesignal(SIGALRM); do { errno = 0; @@ -246,8 +266,11 @@ getrequests() t = accept(DaemonSocket, (struct sockaddr *)&RealHostAddr, &lotherend); } while (t < 0 && errno == EINTR); + savederrno = errno; + (void) blocksignal(SIGALRM); if (t < 0) { + errno = savederrno; syserr("getrequests: accept"); /* arrange to re-open the socket next time around */ @@ -265,10 +288,26 @@ getrequests() if (tTd(15, 2)) printf("getrequests: forking (fd = %d)\n", t); + /* + ** Create a pipe to keep the child from writing to the + ** socket until after the parent has closed it. Otherwise + ** the parent may hang if the child has closed it first. + */ + + if (pipe(pipefd) < 0) + pipefd[0] = pipefd[1] = -1; + + blocksignal(SIGCHLD); pid = fork(); if (pid < 0) { syserr("daemon: cannot fork"); + if (pipefd[0] != -1) + { + (void) close(pipefd[0]); + (void) close(pipefd[1]); + } + (void) releasesignal(SIGCHLD); sleep(10); (void) close(t); continue; @@ -277,9 +316,9 @@ getrequests() if (pid == 0) { char *p; - extern char *hostnamebyanyaddr(); extern void intsig(); FILE *inchannel, *outchannel; + bool nullconn; /* ** CHILD -- return to caller. @@ -287,16 +326,44 @@ getrequests() ** Verify calling user id if possible here. */ + (void) releasesignal(SIGALRM); + (void) releasesignal(SIGCHLD); (void) setsignal(SIGCHLD, SIG_DFL); (void) setsignal(SIGHUP, intsig); (void) close(DaemonSocket); + proc_list_clear(); + + /* don't schedule queue runs if we are told to ETRN */ + QueueIntvl = 0; setproctitle("startup with %s", anynet_ntoa(&RealHostAddr)); + if (pipefd[0] != -1) + { + auto char c; + + /* + ** Wait for the parent to close the write end + ** of the pipe, which we will see as an EOF. + ** This guarantees that we won't write to the + ** socket until after the parent has closed + ** the pipe. + */ + + /* close the write end of the pipe */ + (void) close(pipefd[1]); + + /* we shouldn't be interrupted, but ... */ + while (read(pipefd[0], &c, 1) < 0 && + errno == EINTR) + continue; + (void) close(pipefd[0]); + } + /* determine host name */ p = hostnamebyanyaddr(&RealHostAddr); - if (strlen(p) > MAXNAME) + if (strlen(p) > (SIZE_T) MAXNAME) p[MAXNAME] = '\0'; RealHostName = newstr(p); setproctitle("startup with %s", p); @@ -313,7 +380,13 @@ getrequests() OutChannel = outchannel; DisConnected = FALSE; - /* should we check for illegal connection here? XXX */ + /* validate the connection */ + HoldErrs = TRUE; + nullconn = !validate_connection(&RealHostAddr, RealHostName, e); + HoldErrs = FALSE; + if (nullconn) + break; + #ifdef XLA if (!xla_host_ok(RealHostName)) { @@ -323,16 +396,28 @@ getrequests() #endif if (tTd(15, 2)) - printf("getreq: returning\n"); - return; + printf("getreq: returning (normal server)\n"); + return FALSE; } - CurChildren++; + /* parent -- keep track of children */ + proc_list_add(pid); + (void) releasesignal(SIGCHLD); + + /* close the read end of the synchronization pipe */ + if (pipefd[0] != -1) + (void) close(pipefd[0]); /* close the port so that others will hang (for a while) */ (void) close(t); + + /* release the child by closing the read end of the sync pipe */ + if (pipefd[1] != -1) + (void) close(pipefd[1]); } - /*NOTREACHED*/ + if (tTd(15, 2)) + printf("getreq: returning (null server)\n"); + return TRUE; } /* ** OPENDAEMONSOCKET -- open the SMTP socket @@ -446,6 +531,7 @@ opendaemonsocket(firsttime) } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); finis(); + return -1; /* avoid compiler warning on IRIX */ } /* ** CLRDAEMON -- reset the daemon connection @@ -536,16 +622,16 @@ setdaemonoptions(p) #if NETINET case AF_INET: if (isascii(*v) && isdigit(*v)) - DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v)); + DaemonAddr.sin.sin_addr.s_addr = inet_addr(v); else { - register struct netent *np; + register struct hostent *hp; - np = getnetbyname(v); - if (np == NULL) - syserr("554 network \"%s\" unknown", v); + hp = sm_gethostbyname(v); + if (hp == NULL) + syserr("554 host \"%s\" unknown", v); else - DaemonAddr.sin.sin_addr.s_addr = np->n_net; + bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ); } break; #endif @@ -560,7 +646,9 @@ setdaemonoptions(p) case 'P': /* port */ switch (DaemonAddr.sa.sa_family) { +#if NETISO short port; +#endif #if NETINET case AF_INET: @@ -630,8 +718,7 @@ setdaemonoptions(p) ** port -- the port number to connect to. ** mci -- a pointer to the mail connection information ** structure to be filled in. -** usesecureport -- if set, use a low numbered (reserved) -** port to provide some rudimentary authentication. +** e -- the current envelope. ** ** Returns: ** An exit code telling whether the connection could be @@ -653,20 +740,20 @@ connecttimeout() SOCKADDR CurHostAddr; /* address of current host */ int -makeconnection(host, port, mci, usesecureport) +makeconnection(host, port, mci, e) char *host; u_short port; register MCI *mci; - bool usesecureport; + ENVELOPE *e; { - register int i = 0; - register int s; - register struct hostent *hp = (struct hostent *)NULL; + register volatile int i = 0; + register volatile int s; + register struct hostent *volatile hp = (struct hostent *)NULL; SOCKADDR addr; int sav_errno; - int addrlen; - bool firstconnect; - EVENT *ev; + volatile int addrlen; + volatile bool firstconnect; + EVENT *volatile ev = NULL; /* ** Set up the address for the mailer. @@ -683,13 +770,15 @@ makeconnection(host, port, mci, usesecureport) if (host[0] == '[') { + long hid; register char *p = strchr(host, ']'); if (p != NULL) { *p = '\0'; #if NETINET - if (inet_aton(&host[1], &addr.sin.sin_addr) == 0) + hid = inet_addr(&host[1]); + if (hid == INADDR_NONE) #endif { /* try it as a host name (avoid MX lookup) */ @@ -715,32 +804,38 @@ makeconnection(host, port, mci, usesecureport) } if (p == NULL) { + extern char MsgBuf[]; + usrerr("553 Invalid numeric domain spec \"%s\"", host); - mci->mci_status = "5.1.2"; - return (EX_NOHOST); + mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); + return EX_NOHOST; } #if NETINET addr.sin.sin_family = AF_INET; /*XXX*/ + addr.sin.sin_addr.s_addr = hid; #endif } else { - register char *p = &host[strlen(host) - 1]; - - hp = sm_gethostbyname(host); - if (hp == NULL && *p == '.') + /* contortion to get around SGI cc complaints */ { + register char *p = &host[strlen(host) - 1]; + + hp = sm_gethostbyname(host); + if (hp == NULL && *p == '.') + { #if NAMED_BIND - int oldopts = _res.options; + int oldopts = _res.options; - _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); + _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); #endif - *p = '\0'; - hp = sm_gethostbyname(host); - *p = '.'; + *p = '\0'; + hp = sm_gethostbyname(host); + *p = '.'; #if NAMED_BIND - _res.options = oldopts; + _res.options = oldopts; #endif + } } gothostent: if (hp == NULL) @@ -750,10 +845,11 @@ gothostent: if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || (errno == ECONNREFUSED && UseNameServer)) { - mci->mci_status = "4.4.3"; - return (EX_TEMPFAIL); + mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL); + return EX_TEMPFAIL; } #endif + mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); return (EX_NOHOST); } addr.sa.sa_family = hp->h_addrtype; @@ -815,6 +911,7 @@ gothostent: default: syserr("Can't connect to address family %d", addr.sa.sa_family); + mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); return (EX_NOHOST); } @@ -838,7 +935,7 @@ gothostent: /* save for logging */ CurHostAddr = addr; - if (usesecureport) + if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) { int rport = IPPORT_RESERVED - 1; @@ -852,7 +949,11 @@ gothostent: { sav_errno = errno; syserr("makeconnection: cannot create socket"); - goto failure; +#ifdef XLA + xla_host_end(host); +#endif + mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); + return EX_TEMPFAIL; } #ifdef SO_SNDBUF @@ -875,8 +976,8 @@ gothostent: (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); } - if (CurEnv->e_xfp != NULL) - (void) fflush(CurEnv->e_xfp); /* for debugging */ + if (e->e_xfp != NULL) + (void) fflush(e->e_xfp); /* for debugging */ errno = 0; /* for debugging */ /* @@ -886,10 +987,12 @@ gothostent: if (setjmp(CtxConnectTimeout) == 0) { - if (TimeOuts.to_connect == 0) - ev = NULL; - else + if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) + ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0); + else if (TimeOuts.to_connect != 0) ev = setevent(TimeOuts.to_connect, connecttimeout, 0); + else + ev = NULL; if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) { if (ev != NULL) @@ -938,18 +1041,12 @@ gothostent: continue; } - /* failure, decide if temporary or not */ - failure: + /* couldn't open connection */ #ifdef XLA xla_host_end(host); #endif - if (transienterror(sav_errno)) - return EX_TEMPFAIL; - else - { - message("%s", errstring(sav_errno)); - return (EX_UNAVAILABLE); - } + mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); + return EX_TEMPFAIL; } /* connection ok, put it into canonical form */ @@ -958,9 +1055,11 @@ gothostent: (mci->mci_in = fdopen(s, "r")) == NULL) { syserr("cannot open SMTP client channel, fd=%d", s); + mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); return EX_TEMPFAIL; } + mci_setstat(mci, EX_OK, NULL, NULL); return (EX_OK); } /* @@ -983,7 +1082,6 @@ myhostname(hostbuf, size) int size; { register struct hostent *hp; - extern bool getcanonname(); if (gethostname(hostbuf, size) < 0) { @@ -1074,7 +1172,7 @@ getauthinfo(fd) int fd; { int falen; - register char *p; + register char *volatile p = NULL; SOCKADDR la; int lalen; register struct servent *sp; @@ -1084,7 +1182,6 @@ getauthinfo(fd) int nleft; char ibuf[MAXNAME + 1]; static char hbuf[MAXNAME * 2 + 2]; - extern char *hostnamebyanyaddr(); falen = sizeof RealHostAddr; if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || @@ -1101,6 +1198,8 @@ getauthinfo(fd) { /* translate that to a host name */ RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); + if (strlen(RealHostName) > MAXNAME) + RealHostName[MAXNAME - 1] = '\0'; } if (TimeOuts.to_ident == 0) @@ -1167,6 +1266,9 @@ getauthinfo(fd) { p += i; nleft -= i; + *p = '\0'; + if (strchr(ibuf, '\n') != NULL) + break; } (void) close(s); clrevent(ev); @@ -1204,14 +1306,6 @@ getauthinfo(fd) } /* p now points to the OSTYPE field */ - while (isascii(*p) && isspace(*p)) - p++; - if (strncasecmp(p, "other", 5) == 0 && - (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0')) - { - /* not useful information */ - goto noident; - } p = strchr(p, ':'); if (p == NULL) { @@ -1429,25 +1523,28 @@ host_map_lookup(map, name, av, statp) if (*name != '[') { - extern bool getcanonname(); - if (tTd(9, 1)) printf("host_map_lookup(%s) => ", name); s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ - if (strlen(name) < sizeof hbuf) snprintf(hbuf, sizeof hbuf, "%s", name); if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX)) { if (tTd(9, 1)) printf("%s\n", hbuf); - cp = map_rewrite(map, hbuf, strlen(hbuf), av); - s->s_namecanon.nc_cname = newstr(cp); + if (bitset(MF_MATCHONLY, map->map_mflags)) + { + cp = map_rewrite(map, name, strlen(name), av); + s->s_namecanon.nc_cname = newstr(hbuf); + } + else + { + cp = map_rewrite(map, hbuf, strlen(hbuf), av); + s->s_namecanon.nc_cname = newstr(cp); + } return cp; } else { - register struct hostent *hp; - s->s_namecanon.nc_errno = errno; #if NAMED_BIND s->s_namecanon.nc_herrno = h_errno; @@ -1490,10 +1587,10 @@ host_map_lookup(map, name, av, statp) if ((cp = strchr(name, ']')) == NULL) return (NULL); *cp = '\0'; - (void) inet_aton(&name[1], &in_addr); - - /* nope -- ask the name server */ - hp = gethostbyaddr((char *)&in_addr, sizeof(in_addr), AF_INET); + in_addr.s_addr = inet_addr(&name[1]); + + /* nope -- ask the name server */ + hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); s->s_namecanon.nc_errno = errno; #if NAMED_BIND s->s_namecanon.nc_herrno = h_errno; @@ -1511,6 +1608,94 @@ host_map_lookup(map, name, av, statp) s->s_namecanon.nc_cname = newstr(cp); return cp; } + +# else /* DAEMON */ +/* code for systems without sophisticated networking */ + +/* +** MYHOSTNAME -- stub version for case of no daemon code. +** +** Can't convert to upper case here because might be a UUCP name. +** +** Mark, you can change this to be anything you want...... +*/ + +char ** +myhostname(hostbuf, size) + char hostbuf[]; + int size; +{ + register FILE *f; + + hostbuf[0] = '\0'; + f = fopen("/usr/include/whoami", "r"); + if (f != NULL) + { + (void) fgets(hostbuf, size, f); + fixcrlf(hostbuf, TRUE); + (void) fclose(f); + } + return (NULL); +} +/* +** GETAUTHINFO -- get the real host name asociated with a file descriptor +** +** Parameters: +** fd -- the descriptor +** +** Returns: +** The host name associated with this descriptor, if it can +** be determined. +** NULL otherwise. +** +** Side Effects: +** none +*/ + +char * +getauthinfo(fd) + int fd; +{ + return NULL; +} +/* +** MAPHOSTNAME -- turn a hostname into canonical form +** +** Parameters: +** map -- a pointer to the database map. +** name -- a buffer containing a hostname. +** avp -- a pointer to a (cf file defined) argument vector. +** statp -- an exit status (out parameter). +** +** Returns: +** mapped host name +** FALSE otherwise. +** +** Side Effects: +** Looks up the host specified in name. If it is not +** the canonical name for that host, replace it with +** the canonical name. If the name is unknown, or it +** is already the canonical name, leave it unchanged. +*/ + +/*ARGSUSED*/ +char * +host_map_lookup(map, name, avp, statp) + MAP *map; + char *name; + char **avp; + char *statp; +{ + register struct hostent *hp; + + hp = sm_gethostbyname(name); + if (hp != NULL) + return hp->h_name; + *statp = EX_NOHOST; + return NULL; +} + +#endif /* DAEMON */ /* ** ANYNET_NTOA -- convert a network address to printable form. ** @@ -1521,6 +1706,8 @@ host_map_lookup(map, name, av, statp) ** A printable version of that sockaddr. */ +#ifdef SOCK_STREAM + #if NETLINK # include <net/if_dl.h> #endif @@ -1625,9 +1812,11 @@ hostnamebyanyaddr(sap) break; #endif +#if NETUNIX case AF_UNIX: hp = NULL; break; +#endif default: hp = sm_gethostbyaddr(sap->sa.sa_data, @@ -1652,90 +1841,4 @@ hostnamebyanyaddr(sap) } } -# else /* DAEMON */ -/* code for systems without sophisticated networking */ - -/* -** MYHOSTNAME -- stub version for case of no daemon code. -** -** Can't convert to upper case here because might be a UUCP name. -** -** Mark, you can change this to be anything you want...... -*/ - -char ** -myhostname(hostbuf, size) - char hostbuf[]; - int size; -{ - register FILE *f; - - hostbuf[0] = '\0'; - f = fopen("/usr/include/whoami", "r"); - if (f != NULL) - { - (void) fgets(hostbuf, size, f); - fixcrlf(hostbuf, TRUE); - (void) fclose(f); - } - return (NULL); -} -/* -** GETAUTHINFO -- get the real host name asociated with a file descriptor -** -** Parameters: -** fd -- the descriptor -** -** Returns: -** The host name associated with this descriptor, if it can -** be determined. -** NULL otherwise. -** -** Side Effects: -** none -*/ - -char * -getauthinfo(fd) - int fd; -{ - return NULL; -} -/* -** MAPHOSTNAME -- turn a hostname into canonical form -** -** Parameters: -** map -- a pointer to the database map. -** name -- a buffer containing a hostname. -** avp -- a pointer to a (cf file defined) argument vector. -** statp -- an exit status (out parameter). -** -** Returns: -** mapped host name -** FALSE otherwise. -** -** Side Effects: -** Looks up the host specified in name. If it is not -** the canonical name for that host, replace it with -** the canonical name. If the name is unknown, or it -** is already the canonical name, leave it unchanged. -*/ - -/*ARGSUSED*/ -char * -host_map_lookup(map, name, avp, statp) - MAP *map; - char *name; - char **avp; - char *statp; -{ - register struct hostent *hp; - - hp = sm_gethostbyname(name); - if (hp != NULL) - return hp->h_name; - *statp = EX_NOHOST; - return NULL; -} - -#endif /* DAEMON */ +#endif /* SOCK_STREAM */ diff --git a/usr.sbin/sendmail/src/deliver.c b/usr.sbin/sendmail/src/deliver.c index cfa2e965d13..576c166785d 100644 --- a/usr.sbin/sendmail/src/deliver.c +++ b/usr.sbin/sendmail/src/deliver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)deliver.c 8.185.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)deliver.c 8.260 (Berkeley) 12/1/96"; #endif /* not lint */ #include "sendmail.h" @@ -44,7 +44,7 @@ static char sccsid[] = "@(#)deliver.c 8.185.1.2 (Berkeley) 9/16/96"; extern int h_errno; #endif -#ifdef SMTP +#if SMTP extern char SmtpError[]; #endif @@ -69,7 +69,7 @@ extern char SmtpError[]; void sendall(e, mode) ENVELOPE *e; - char mode; + int mode; { register ADDRESS *q; char *owner; @@ -78,7 +78,7 @@ sendall(e, mode) ENVELOPE *splitenv = NULL; bool oldverbose = Verbose; bool somedeliveries = FALSE; - int pid; + pid_t pid; extern void sendenvelope(); /* @@ -125,11 +125,13 @@ sendall(e, mode) */ CurEnv = e; + if (tTd(62, 1)) + checkfds(NULL); if (e->e_hopcount > MaxHopCount) { errno = 0; -#ifdef QUEUE +#if QUEUE queueup(e, mode == SM_QUEUE || mode == SM_DEFER); #endif e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; @@ -177,19 +179,28 @@ sendall(e, mode) continue; if (a != NULL) q->q_owner = a->q_owner; - + if (q->q_owner != NULL && !bitset(QDONTSEND, q->q_flags) && strcmp(q->q_owner, e->e_from.q_paddr) == 0) q->q_owner = NULL; } - + + if (tTd(13, 25)) + { + printf("\nAfter first owner pass, sendq =\n"); + printaddr(e->e_sendqueue, TRUE); + } + owner = ""; otherowners = 1; while (owner != NULL && otherowners > 0) { + if (tTd(13, 28)) + printf("owner = \"%s\", otherowners = %d\n", + owner, otherowners); owner = NULL; - otherowners = 0; + otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0; for (q = e->e_sendqueue; q != NULL; q = q->q_next) { @@ -204,27 +215,49 @@ sendall(e, mode) printf(" ... QDONTSEND\n"); continue; } + if (tTd(13, 29) && !tTd(13, 30)) + { + printf("Checking "); + printaddr(q, FALSE); + } if (q->q_owner != NULL) { if (owner == NULL) + { + if (tTd(13, 40)) + printf(" ... First owner = \"%s\"\n", + q->q_owner); owner = q->q_owner; + } else if (owner != q->q_owner) { if (strcmp(owner, q->q_owner) == 0) { + if (tTd(13, 40)) + printf(" ... Same owner = \"%s\"\n", + owner); + /* make future comparisons cheap */ q->q_owner = owner; } else { + if (tTd(13, 40)) + printf(" ... Another owner \"%s\"\n", + q->q_owner); otherowners++; } owner = q->q_owner; } + else if (tTd(13, 40)) + printf(" ... Same owner = \"%s\"\n", + owner); } else { + if (tTd(13, 40)) + printf(" ... Null owner\n"); otherowners++; } @@ -273,8 +306,8 @@ sendall(e, mode) (void) queuename(ee, '\0'); if (tTd(13, 1)) - printf("sendall: split %s into %s\n", - e->e_id, ee->e_id); + printf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", + e->e_id, ee->e_id, owner, otherowners); ee->e_header = copyheader(e->e_header); ee->e_sendqueue = copyqueue(e->e_sendqueue); @@ -293,13 +326,16 @@ sendall(e, mode) ee->e_errormode = EM_MAIL; ee->e_sibling = splitenv; splitenv = ee; - + for (q = e->e_sendqueue; q != NULL; q = q->q_next) { if (q->q_owner == owner) { q->q_flags |= QDONTSEND; - q->q_flags &= ~QQUEUEUP; + q->q_flags &= ~(QQUEUEUP|QBADADDR); + if (tTd(13, 6)) + printf("\t... stripping %s from original envelope\n", + q->q_paddr); } } for (q = ee->e_sendqueue; q != NULL; q = q->q_next) @@ -307,13 +343,19 @@ sendall(e, mode) if (q->q_owner != owner) { q->q_flags |= QDONTSEND; - q->q_flags &= ~QQUEUEUP; + q->q_flags &= ~(QQUEUEUP|QBADADDR); + if (tTd(13, 6)) + printf("\t... dropping %s from cloned envelope\n", + q->q_paddr); } else { /* clear DSN parameters */ - q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS); - q->q_flags |= QPINGONFAILURE|QPINGONDELAY; + q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); + q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; + if (tTd(13, 6)) + printf("\t... moving %s to cloned envelope\n", + q->q_paddr); } } @@ -368,6 +410,7 @@ sendall(e, mode) e->e_from.q_flags |= QDONTSEND; e->e_errormode = EM_MAIL; e->e_flags |= EF_NORECEIPT; + e->e_flags &= ~EF_FATALERRS; } /* if nothing to be delivered, just queue up everything */ @@ -379,10 +422,10 @@ sendall(e, mode) mode = SM_QUEUE; } -# ifdef QUEUE +# if QUEUE if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK || (mode != SM_VERIFY && SuperSafe)) && - !bitset(EF_INQUEUE, e->e_flags)) + (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) { /* be sure everything is instantiated in the queue */ queueup(e, mode == SM_QUEUE || mode == SM_DEFER); @@ -391,12 +434,31 @@ sendall(e, mode) } #endif /* QUEUE */ + if (tTd(62, 10)) + checkfds("after envelope splitting"); + /* ** If we belong in background, fork now. */ if (tTd(13, 20)) + { printf("sendall: final mode = %c\n", mode); + if (tTd(13, 21)) + { + printf("\n================ Final Send Queue(s) =====================\n"); + printf("\n *** Envelope %s, e_from=%s ***\n", + e->e_id, e->e_from.q_paddr); + printaddr(e->e_sendqueue, TRUE); + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + printf("\n *** Envelope %s, e_from=%s ***\n", + ee->e_id, ee->e_from.q_paddr); + printaddr(ee->e_sendqueue, TRUE); + } + printf("==========================================================\n\n"); + } + } switch (mode) { case SM_VERIFY: @@ -428,15 +490,26 @@ sendall(e, mode) /* now drop the envelope in the parent */ e->e_flags |= EF_INQUEUE; - dropenvelope(e); + dropenvelope(e, FALSE); - /* and reacquire in the child */ - (void) dowork(qid, TRUE, FALSE, e); + /* arrange to reacquire lock after fork */ + e->e_id = qid; } - return; + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + /* save id for future use */ + char *qid = ee->e_id; + + /* drop envelope in parent */ + ee->e_flags |= EF_INQUEUE; + dropenvelope(ee, FALSE); -# else /* HASFLOCK */ + /* and save qid for reacquisition */ + ee->e_id = qid; + } + +# endif /* !HASFLOCK */ pid = fork(); if (pid < 0) @@ -445,6 +518,7 @@ sendall(e, mode) } else if (pid > 0) { +# if HASFLOCK /* be sure we leave the temp files to our child */ /* can't call unlockqueue to avoid unlink of xfp */ if (e->e_lockfp != NULL) @@ -456,8 +530,11 @@ sendall(e, mode) if (e->e_dfp != NULL) (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id); e->e_dfp = NULL; - e->e_id = NULL; e->e_flags &= ~EF_HAS_DF; +# endif + + /* make sure the parent doesn't own the envelope */ + e->e_id = NULL; /* catch intermediate zombie */ (void) waitfor(pid); @@ -491,31 +568,33 @@ sendall(e, mode) mci_flush(FALSE, NULL); -# endif /* HASFLOCK */ - +# if HASFLOCK break; - } - - if (splitenv != NULL) - { - if (tTd(13, 2)) - { - printf("\nsendall: Split queue; remaining queue:\n"); - printaddr(e->e_sendqueue, TRUE); - } +# else - for (ee = splitenv; ee != NULL; ee = ee->e_sibling) - { - CurEnv = ee; - if (mode != SM_VERIFY) - openxscript(ee); - sendenvelope(ee, mode); - dropenvelope(ee); - } + /* + ** Now reacquire and run the various queue files. + */ - CurEnv = e; + for (ee = splitenv; ee != NULL; ee = e->e_sibling) + (void) dowork(ee->e_id, FALSE, FALSE, ee); + (void) dowork(e->e_id, FALSE, FALSE, e); + finis(); +# endif /* !HASFLOCK */ } + sendenvelope(e, mode); + dropenvelope(e, TRUE); + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + CurEnv = ee; + if (mode != SM_VERIFY) + openxscript(ee); + sendenvelope(ee, mode); + dropenvelope(ee, TRUE); + } + CurEnv = e; + Verbose = oldverbose; if (mode == SM_FORK) finis(); @@ -530,7 +609,7 @@ sendenvelope(e, mode) bool didany; if (tTd(13, 10)) - printf("sendenvelope(%s) e_flags=0x%x\n", + printf("sendenvelope(%s) e_flags=0x%lx\n", e->e_id == NULL ? "[NOQUEUE]" : e->e_id, e->e_flags); #ifdef LOG @@ -563,6 +642,8 @@ sendenvelope(e, mode) e->e_nsent = 0; e->e_flags |= EF_GLOBALERRS; + define(macid("{envid}", NULL), e->e_envid, e); + define(macid("{bodytype}", NULL), e->e_bodytype, e); didany = FALSE; /* now run through the queue */ @@ -593,7 +674,9 @@ sendenvelope(e, mode) } else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) { -# ifdef QUEUE + extern int deliver __P((ENVELOPE *, ADDRESS *)); + +# if QUEUE /* ** Checkpoint the send list every few addresses */ @@ -677,7 +760,7 @@ sendenvelope(e, mode) int dofork() { - register int pid = -1; + register pid_t pid = -1; DOFORK(fork); return (pid); @@ -704,6 +787,13 @@ dofork() ** The standard input is passed off to someone. */ +#ifndef NO_UID +# define NO_UID ((uid_t) -1) +#endif +#ifndef NO_GID +# define NO_GID ((gid_t) -1) +#endif + int deliver(e, firstto) register ENVELOPE *e; @@ -716,15 +806,19 @@ deliver(e, firstto) register char *p; register MAILER *m; /* mailer for this recipient */ ADDRESS *volatile ctladdr; + ADDRESS *volatile contextaddr = NULL; register MCI *volatile mci; register ADDRESS *to = firstto; volatile bool clever = FALSE; /* running user smtp to this mailer */ ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */ int rcode; /* response code */ char *firstsig; /* signature of firstto */ - int pid = -1; + pid_t pid = -1; char *volatile curhost; + register volatile u_short port = 0; time_t xstart; + bool suidwarn; + bool anyok; /* at least one address was OK */ int mpvect[2]; int rpvect[2]; char *pv[MAXPV+1]; @@ -738,6 +832,8 @@ deliver(e, firstto) if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) return (0); + suidwarn = geteuid() == 0; + #if NAMED_BIND /* unless interactive, try twice, over a minute */ if (OpMode == MD_DAEMON || OpMode == MD_SMTP) @@ -745,13 +841,13 @@ deliver(e, firstto) _res.retrans = 30; _res.retry = 2; } -#endif +#endif m = to->q_mailer; host = to->q_host; CurEnv = e; /* just in case */ e->e_statmsg = NULL; -#ifdef SMTP +#if SMTP SmtpError[0] = '\0'; #endif xstart = curtime(); @@ -843,7 +939,7 @@ deliver(e, firstto) if (*mvp == NULL) { /* running SMTP */ -# ifdef SMTP +# if SMTP clever = TRUE; *pvp = NULL; # else /* SMTP */ @@ -888,7 +984,7 @@ deliver(e, firstto) /* compute effective uid/gid when sending */ if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) - ctladdr = getctladdr(to); + contextaddr = ctladdr = getctladdr(to); if (tTd(10, 2)) { @@ -921,7 +1017,15 @@ deliver(e, firstto) #if NAMED_BIND h_errno = 0; #endif - rcode = checkcompat(to, e); + + /* do config file checking of compatibility */ + rcode = rscheck("check_compat", + e->e_from.q_paddr, to->q_paddr, e); + if (rcode == EX_OK) + { + /* do in-code checking */ + rcode = checkcompat(to, e); + } if (rcode != EX_OK) { markfailure(e, to, NULL, rcode); @@ -956,9 +1060,6 @@ deliver(e, firstto) if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) continue; - /* save statistics.... */ - markstats(e, to); - /* ** See if this user name is "special". ** If the user name has a slash in it, assume that this @@ -975,9 +1076,9 @@ deliver(e, firstto) if (rcode == EX_OK) { to->q_flags |= QSENT; + markstats(e, to); if (bitnset(M_LOCALMAILER, m->m_flags) && - (e->e_receiptto != NULL || - bitset(QPINGONSUCCESS, to->q_flags))) + bitset(QPINGONSUCCESS, to->q_flags)) { to->q_flags |= QDELIVERED; to->q_status = "2.1.5"; @@ -1114,6 +1215,9 @@ deliver(e, firstto) goto give_up; } + if (tTd(62, 8)) + checkfds("before delivery"); + /* check for Local Person Communication -- not for mortals!!! */ if (strcmp(m->m_mailer, "[LPC]") == 0) { @@ -1127,9 +1231,8 @@ deliver(e, firstto) else if (strcmp(m->m_mailer, "[IPC]") == 0 || strcmp(m->m_mailer, "[TCP]") == 0) { -#ifdef DAEMON +#if DAEMON register int i; - register volatile u_short port = 0; if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') { @@ -1172,11 +1275,12 @@ tryhost: { register char *p; static char hostbuf[MAXNAME + 1]; + extern int makeconnection __P((char *, u_short, MCI *, ENVELOPE *)); /* pull the next host from the signature */ p = strchr(curhost, ':'); if (p == NULL) - p = &curhost[strlen(curhost)]; + p = (char *) &curhost[strlen(curhost)]; if (p == curhost) { syserr("deliver: null host name in signature"); @@ -1209,12 +1313,21 @@ tryhost: if (mci->mci_exitstat != EX_OK) continue; + if (mci_lock_host(mci) != EX_OK) + { + mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); + continue; + } + /* try the connection */ setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); - message("Connecting to %s via %s...", - hostbuf, m->m_name); - i = makeconnection(hostbuf, port, mci, - bitnset(M_SECURE_PORT, m->m_flags)); + if (port == 0) + message("Connecting to %s via %s...", + hostbuf, m->m_name); + else + message("Connecting to %s port %d via %s...", + hostbuf, port, m->m_name); + i = makeconnection(hostbuf, port, mci, e); mci->mci_lastuse = curtime(); mci->mci_exitstat = i; mci->mci_errno = errno; @@ -1226,13 +1339,17 @@ tryhost: mci->mci_state = MCIS_OPENING; mci_cache(mci); if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d == CONNECT %s\n", - getpid(), hostbuf); + fprintf(TrafficLogFile, "%05d === CONNECT %s\n", + (int) getpid(), hostbuf); break; } - else if (tTd(11, 1)) - printf("openmailer: makeconnection => stat=%d, errno=%d\n", - i, errno); + else + { + if (tTd(11, 1)) + printf("openmailer: makeconnection => stat=%d, errno=%d\n", + i, errno); + mci_unlock_host(mci); + } /* enter status of this host */ setstat(i); @@ -1242,7 +1359,7 @@ tryhost: if (mci == NULL) { syserr("deliver: no host name"); - rcode = EX_OSERR; + rcode = EX_SOFTWARE; goto give_up; } mci->mci_pid = 0; @@ -1268,12 +1385,16 @@ tryhost: { char **av; - fprintf(TrafficLogFile, "%05d === EXEC", getpid()); + fprintf(TrafficLogFile, "%05d === EXEC", (int) getpid()); for (av = pv; *av != NULL; av++) fprintf(TrafficLogFile, " %s", *av); fprintf(TrafficLogFile, "\n"); } +#if XDEBUG + checkfd012("before creating mail pipe"); +#endif + /* create a pipe to shove the mail through */ if (pipe(mpvect) < 0) { @@ -1285,19 +1406,59 @@ tryhost: goto give_up; } - /* if this mailer speaks smtp, create a return pipe */ -#ifdef SMTP - if (clever && pipe(rpvect) < 0) +#if XDEBUG + /* make sure we didn't get one of the standard I/O files */ + if (mpvect[0] < 3 || mpvect[1] < 3) { - syserr("%s... openmailer(%s): pipe (from mailer)", - shortenstring(e->e_to, 203), m->m_name); - (void) close(mpvect[0]); - (void) close(mpvect[1]); + syserr("%s... openmailer(%s): bogus mpvect %d %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1]); + printopenfds(TRUE); if (tTd(11, 1)) printf("openmailer: NULL\n"); rcode = EX_OSERR; goto give_up; } + + /* make sure system call isn't dead meat */ + checkfdopen(mpvect[0], "mpvect[0]"); + checkfdopen(mpvect[1], "mpvect[1]"); + if (mpvect[0] == mpvect[1] || + (e->e_lockfp != NULL && + (mpvect[0] == fileno(e->e_lockfp) || + mpvect[1] == fileno(e->e_lockfp)))) + { + if (e->e_lockfp == NULL) + syserr("%s... openmailer(%s): overlapping mpvect %d %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1]); + else + syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1], fileno(e->e_lockfp)); + } +#endif + + /* if this mailer speaks smtp, create a return pipe */ +#if SMTP + if (clever) + { + if (pipe(rpvect) < 0) + { + syserr("%s... openmailer(%s): pipe (from mailer)", + shortenstring(e->e_to, 203), m->m_name); + (void) close(mpvect[0]); + (void) close(mpvect[1]); + if (tTd(11, 1)) + printf("openmailer: NULL\n"); + rcode = EX_OSERR; + goto give_up; + } +# if XDEBUG + checkfdopen(rpvect[0], "rpvect[0]"); + checkfdopen(rpvect[1], "rpvect[1]"); +# endif + } #endif /* @@ -1323,7 +1484,7 @@ tryhost: shortenstring(e->e_to, 203), m->m_name); (void) close(mpvect[0]); (void) close(mpvect[1]); -#ifdef SMTP +#if SMTP if (clever) { (void) close(rpvect[0]); @@ -1339,6 +1500,9 @@ tryhost: { int i; int saveerrno; + uid_t new_euid = NO_UID; + uid_t new_ruid = NO_UID; + gid_t new_gid = NO_GID; struct stat stb; extern int DtableSize; @@ -1353,63 +1517,98 @@ tryhost: if (m != FileMailer || stat(tochain->q_user, &stb) < 0) stb.st_mode = 0; +#if HASSETUSERCONTEXT + /* + ** Set user resources. + */ + + if (contextaddr != NULL) + { + struct passwd *pwd; + + if (contextaddr->q_ruser != NULL) + pwd = sm_getpwnam(contextaddr->q_ruser); + else + pwd = sm_getpwnam(contextaddr->q_user); + if (pwd != NULL) + (void) setusercontext(NULL, + pwd, pwd->m_uid, + LOGIN_SETRESOURCES|LOGIN_SETPRIORITY); + } +#endif + /* tweak niceness */ if (m->m_nice != 0) nice(m->m_nice); /* reset group id */ if (bitnset(M_SPECIFIC_UID, m->m_flags)) - (void) setgid(m->m_gid); + new_gid = m->m_gid; else if (bitset(S_ISGID, stb.st_mode)) - (void) setgid(stb.st_gid); + new_gid = stb.st_gid; else if (ctladdr != NULL && ctladdr->q_gid != 0) { if (!DontInitGroups) (void) initgroups(ctladdr->q_ruser != NULL ? ctladdr->q_ruser : ctladdr->q_user, ctladdr->q_gid); - (void) setgid(ctladdr->q_gid); + new_gid = ctladdr->q_gid; } else { if (!DontInitGroups) (void) initgroups(DefUser, DefGid); if (m->m_gid == 0) - (void) setgid(DefGid); + new_gid = DefGid; else - (void) setgid(m->m_gid); + new_gid = m->m_gid; } + if (new_gid != NO_GID && setgid(new_gid) < 0 && suidwarn) + syserr("openmailer: setgid(%ld) failed", + (long) new_gid); /* reset user id */ endpwent(); if (bitnset(M_SPECIFIC_UID, m->m_flags)) + new_euid = m->m_uid; + if (bitset(S_ISUID, stb.st_mode)) + new_ruid = stb.st_uid; + else if (ctladdr != NULL && ctladdr->q_uid != 0) + new_ruid = ctladdr->q_uid; + else if (m->m_uid != 0) + new_ruid = m->m_uid; + else if (!bitnset(M_SPECIFIC_UID, m->m_flags)) + new_ruid = DefUid; + if (new_euid != NO_UID) { + vendor_set_uid(new_euid); #if USESETEUID - (void) seteuid(m->m_uid); + if (seteuid(new_euid) < 0 && suidwarn) + syserr("openmailer: seteuid(%ld) failed", + (long) new_euid); #else # if HASSETREUID - (void) setreuid(-1, m->m_uid); + if (setreuid(new_ruid, new_euid) < 0 && suidwarn) + syserr("openmailer: setreuid(%ld, %ld) failed", + (long) new_ruid, (long) new_euid); # else - if (m->m_uid != geteuid()) - (void) setuid(m->m_uid); + if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) + syserr("openmailer: setuid(%ld) failed", + (long) new_euid); # endif #endif } - else if (bitset(S_ISUID, stb.st_mode)) - (void) setuid(stb.st_uid); - else if (ctladdr != NULL && ctladdr->q_uid != 0) - (void) setuid(ctladdr->q_uid); - else + else if (new_ruid != NO_UID) { - if (m->m_uid == 0) - (void) setuid(DefUid); - else - (void) setuid(m->m_uid); + vendor_set_uid(new_ruid); + if (setuid(new_ruid) < 0 && suidwarn) + syserr("openmailer: setuid(%ld) failed", + (long) new_ruid); } if (tTd(11, 2)) printf("openmailer: running as r/euid=%d/%d\n", - getuid(), geteuid()); + (int) getuid(), (int) geteuid()); /* move into some "safe" directory */ if (m->m_execdir != NULL) @@ -1434,7 +1633,7 @@ tryhost: } /* arrange to filter std & diag output of command */ -#ifdef SMTP +#if SMTP if (clever) { (void) close(rpvect[0]); @@ -1516,7 +1715,7 @@ tryhost: syserr("deliver: cannot create mailer output channel, fd=%d", mpvect[1]); (void) close(mpvect[1]); -#ifdef SMTP +#if SMTP if (clever) { (void) close(rpvect[0]); @@ -1526,7 +1725,7 @@ tryhost: rcode = EX_OSERR; goto give_up; } -#ifdef SMTP +#if SMTP if (clever) { (void) close(rpvect[1]); @@ -1555,11 +1754,15 @@ tryhost: */ if (bitnset(M_7BITS, m->m_flags) && - (!clever || mci->mci_state == MCIS_CLOSED)) + (!clever || mci->mci_state == MCIS_OPENING)) mci->mci_flags |= MCIF_7BIT; -#ifdef SMTP +#if SMTP if (clever && mci->mci_state != MCIS_CLOSED) + { + extern void smtpinit __P((MAILER *, MCI *, ENVELOPE *)); + smtpinit(m, mci, e); + } #endif if (bitset(EF_HAS8BIT, e->e_flags) && @@ -1569,6 +1772,22 @@ tryhost: else mci->mci_flags &= ~MCIF_CVT8TO7; +#if MIME7TO8 + if (bitnset(M_MAKE8BIT, m->m_flags) && + !bitset(MCIF_7BIT, mci->mci_flags) && + (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && + (strcasecmp(p, "quoted-printable") == 0 || + strcasecmp(p, "base64") == 0) && + (p = hvalue("Content-Type", e->e_header)) != NULL) + { + /* may want to convert 7 -> 8 */ + /* XXX should really parse it here -- and use a class XXX */ + if (strncasecmp(p, "text/plain", 10) == 0 && + (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) + mci->mci_flags |= MCIF_CVT7TO8; + } +#endif + if (tTd(11, 1)) { printf("openmailer: "); @@ -1586,11 +1805,13 @@ tryhost: if (rcode == EX_OK) { /* shouldn't happen */ - syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", - rcode, mci->mci_state, firstsig); + syserr("554 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", + (long) mci, rcode, errno, mci->mci_state, + firstsig); + mci_dump_all(TRUE); rcode = EX_SOFTWARE; } -#ifdef DAEMON +#if DAEMON else if (curhost != NULL && *curhost != '\0') { /* try next MX site */ @@ -1612,8 +1833,13 @@ tryhost: rcode = endmailer(mci, e, pv); } else -#ifdef SMTP +#if SMTP { + extern int smtpmailfrom __P((MAILER *, MCI *, ENVELOPE *)); + extern int smtprcpt __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *)); + extern int smtpdata __P((MAILER *, MCI *, ENVELOPE *)); + extern int smtpgetstat __P((MAILER *, MCI *, ENVELOPE *)); + /* ** Send the MAIL FROM: protocol */ @@ -1656,16 +1882,14 @@ tryhost: e->e_to = tobuf + 1; rcode = smtpdata(m, mci, e); } - - /* now close the connection */ - if (!bitset(MCIF_CACHED, mci->mci_flags)) - smtpquit(m, mci, e); } - if (rcode != EX_OK && curhost != NULL && *curhost != '\0') +# if DAEMON + if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0') { /* try next MX site */ goto tryhost; } +# endif } #else /* not SMTP */ { @@ -1679,13 +1903,8 @@ tryhost: _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ #endif - /* arrange a return receipt if requested */ - if (rcode == EX_OK && e->e_receiptto != NULL && - bitnset(M_LOCALMAILER, m->m_flags)) - { - e->e_flags |= EF_SENDRECEIPT; - /* do we want to send back more info? */ - } + if (tTd(62, 1)) + checkfds("after delivery"); /* ** Do final status disposal. @@ -1695,19 +1914,55 @@ tryhost: */ give_up: - if (tobuf[0] != '\0') - giveresponse(rcode, m, mci, ctladdr, xstart, e); +#if SMTP +# if _FFR_LMTP + if (bitnset(M_LMTP, m->m_flags)) + { + tobuf[0] = '\0'; + anyok = FALSE; + } + else +# endif +#endif + anyok = rcode == EX_OK; + for (to = tochain; to != NULL; to = to->q_tchain) { /* see if address already marked */ if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) continue; - /* mark bad addresses */ - if (rcode != EX_OK) +#if SMTP +# if _FFR_LMTP + /* if running LMTP, get the status for each address */ + if (bitnset(M_LMTP, m->m_flags)) { - markfailure(e, to, mci, rcode); - continue; + rcode = smtpgetstat(m, mci, e); + if (rcode == EX_OK) + { + strcat(tobuf, ","); + strcat(tobuf, to->q_paddr); + anyok = TRUE; + } + else + { + e->e_to = to->q_paddr; + markfailure(e, to, mci, rcode); + giveresponse(rcode, m, mci, ctladdr, xstart, e); + e->e_to = tobuf + 1; + continue; + } + } + else +# endif +#endif + { + /* mark bad addresses */ + if (rcode != EX_OK) + { + markfailure(e, to, mci, rcode); + continue; + } } /* successful delivery */ @@ -1715,8 +1970,7 @@ tryhost: to->q_statdate = curtime(); e->e_nsent++; if (bitnset(M_LOCALMAILER, m->m_flags) && - (e->e_receiptto != NULL || - bitset(QPINGONSUCCESS, to->q_flags))) + bitset(QPINGONSUCCESS, to->q_flags)) { to->q_flags |= QDELIVERED; to->q_status = "2.1.5"; @@ -1733,6 +1987,38 @@ tryhost: } } +#if SMTP +# if _FFR_LMTP + if (bitnset(M_LMTP, m->m_flags)) + { + /* + ** Global information applies to the last recipient only; + ** clear it out to avoid bogus errors. + */ + + rcode = EX_OK; + e->e_statmsg = NULL; + + /* reset the mci state for the next transaction */ + if (mci->mci_state == MCIS_ACTIVE) + mci->mci_state = MCIS_OPEN; + } +# endif +#endif + + if (tobuf[0] != '\0') + giveresponse(rcode, m, mci, ctladdr, xstart, e); + if (anyok) + markstats(e, tochain); + mci_store_persistent(mci); + +#if SMTP + /* now close the connection */ + if (clever && mci->mci_state != MCIS_CLOSED && + !bitset(MCIF_CACHED, mci->mci_flags)) + smtpquit(m, mci, e); +#endif + /* ** Restore state and return. */ @@ -1798,11 +2084,17 @@ markfailure(e, q, mci, rcode) } /* find most specific error code possible */ - if (q->q_status == NULL && mci != NULL) + if (mci != NULL && mci->mci_status != NULL) + { q->q_status = mci->mci_status; - if (q->q_status == NULL) + q->q_rstatus = mci->mci_rstatus; + } + else if (e->e_status != NULL) + { q->q_status = e->e_status; - if (q->q_status == NULL) + q->q_rstatus = NULL; + } + else { switch (rcode) { @@ -1903,11 +2195,15 @@ endmailer(mci, e, pv) if (mci->mci_pid == 0) return (EX_OK); +#ifdef _FFR_TIMEOUT_WAIT + put a timeout around the wait +#endif + /* wait for the mailer process to die and collect status */ st = waitfor(mci->mci_pid); if (st == -1) { - syserr("endmailer %s: wait", pv[0]); + syserr("endmailer %s: wait", mci->mci_mailer->m_name); return (EX_SOFTWARE); } @@ -2012,7 +2308,7 @@ giveresponse(stat, m, mci, ctladdr, xstart, e) statmsg = errstring(errno); else { -#ifdef SMTP +#if SMTP statmsg = SmtpError; #else /* SMTP */ statmsg = NULL; @@ -2168,7 +2464,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) /* relay: max 66 bytes for IPv4 addresses */ if (mci != NULL && mci->mci_host != NULL) { -# ifdef DAEMON +# if DAEMON extern SOCKADDR CurHostAddr; # endif @@ -2176,7 +2472,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) shortenstring(mci->mci_host, 40)); bp += strlen(bp); -# ifdef DAEMON +# if DAEMON if (CurHostAddr.sa.sa_family != 0) { snprintf(bp, SPACELEFT(buf, bp), " [%s]", @@ -2219,7 +2515,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) bp += strlen(bp); (void) strcpy(bp, shortenstring(stat, (STATLEN))); - + /* id, to: max 13 + TOBUFSIZE bytes */ l = SYSLOG_BUFSIZE - 100 - strlen(buf); p = e->e_to; @@ -2239,7 +2535,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) l = SYSLOG_BUFSIZE - 85; p = e->e_to; - while (strlen(p) >= l) + while (strlen(p) >= (SIZE_T) l) { register char *q = strchr(p + l, ','); @@ -2287,14 +2583,14 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) bp = buf; if (mci != NULL && mci->mci_host != NULL) { -# ifdef DAEMON +# if DAEMON extern SOCKADDR CurHostAddr; # endif snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", mci->mci_host); bp += strlen(bp); -# ifdef DAEMON +# if DAEMON if (CurHostAddr.sa.sa_family != 0) snprintf(bp, SPACELEFT(buf, bp), " [%.100s]", anynet_ntoa(&CurHostAddr)); @@ -2342,6 +2638,7 @@ putfromline(mci, e) { char *template = UnixFromLine; char buf[MAXLINE]; + char xbuf[MAXLINE]; if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) return; @@ -2349,14 +2646,29 @@ putfromline(mci, e) if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) { char *bang; - char xbuf[MAXLINE]; expand("\201g", buf, sizeof buf, e); bang = strchr(buf, '!'); if (bang == NULL) { - errno = 0; - syserr("554 No ! in UUCP From address! (%s given)", buf); + char *at; + char hname[MAXNAME]; + + /* + ** If we can construct a UUCP path, do so + */ + + at = strrchr(buf, '@'); + if (at == NULL) + { + expand( "\201k", hname, sizeof hname, e); + at = hname; + } + else + *at++ = '\0'; + (void) snprintf(xbuf, sizeof xbuf, + "From %.800s \201d remote from %.100s\n", + buf, at); } else { @@ -2461,6 +2773,12 @@ putbody(mci, e, separator) boundaries[0] = NULL; mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); } +# if MIME7TO8 + else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) + { + mime7to8(mci, e->e_header, e); + } +# endif else #endif { @@ -2468,6 +2786,7 @@ putbody(mci, e, separator) register char *bp; register char *pbp; register int c; + register char *xp; int padc; char *buflim; int pos = 0; @@ -2492,8 +2811,6 @@ putbody(mci, e, separator) pbp = peekbuf; while (!ferror(mci->mci_out)) { - register char *xp; - if (pbp > peekbuf) c = *--pbp; else if ((c = getc(e->e_dfp)) == EOF) @@ -2503,6 +2820,11 @@ putbody(mci, e, separator) switch (ostate) { case OS_HEAD: +#ifdef _FFR_NONULLS + if (c == '\0' && + bitnset(M_NONULLS, mci->mci_mailer->m_flags)) + break; +#endif if (c != '\r' && c != '\n' && bp < buflim) { *bp++ = c; @@ -2537,7 +2859,8 @@ putbody(mci, e, separator) /* now copy out saved line */ if (TrafficLogFile != NULL) { - fprintf(TrafficLogFile, "%05d >>> ", getpid()); + fprintf(TrafficLogFile, "%05d >>> ", + (int) getpid()); if (padc != EOF) putc(padc, TrafficLogFile); for (xp = buf; xp < bp; xp++) @@ -2593,6 +2916,7 @@ putbody(mci, e, separator) /* had a naked carriage return */ *pbp++ = c; c = '\r'; + ostate = OS_INLINE; goto putch; case OS_INLINE: @@ -2601,6 +2925,11 @@ putbody(mci, e, separator) ostate = OS_CR; continue; } +#ifdef _FFR_NONULLS + if (c == '\0' && + bitnset(M_NONULLS, mci->mci_mailer->m_flags)) + break; +#endif putch: if (mci->mci_mailer->m_linelimit > 0 && pos > mci->mci_mailer->m_linelimit && @@ -2617,11 +2946,23 @@ putch: *pbp++ = c; continue; } - if (TrafficLogFile != NULL) - putc(c, TrafficLogFile); - putc(c, mci->mci_out); - pos++; - ostate = c == '\n' ? OS_HEAD : OS_INLINE; + if (c == '\n') + { + if (TrafficLogFile != NULL) + fputs(mci->mci_mailer->m_eol, + TrafficLogFile); + fputs(mci->mci_mailer->m_eol, mci->mci_out); + pos = 0; + ostate = OS_HEAD; + } + else + { + if (TrafficLogFile != NULL) + putc(c, TrafficLogFile); + putc(c, mci->mci_out); + pos++; + ostate = OS_INLINE; + } break; } } @@ -2629,8 +2970,19 @@ putch: /* make sure we are at the beginning of a line */ if (bp > buf) { - *bp = '\0'; - fputs(buf, mci->mci_out); + if (TrafficLogFile != NULL) + { + for (xp = buf; xp < bp; xp++) + putc(*xp, TrafficLogFile); + } + for (xp = buf; xp < bp; xp++) + putc(*xp, mci->mci_out); + pos += bp - buf; + } + if (pos > 0) + { + if (TrafficLogFile != NULL) + fputs(mci->mci_mailer->m_eol, TrafficLogFile); fputs(mci->mci_mailer->m_eol, mci->mci_out); } } @@ -2691,8 +3043,9 @@ mailfile(filename, ctladdr, sfflags, e) register ENVELOPE *e; { register FILE *f; - register int pid = -1; + register pid_t pid = -1; int mode; + bool suidwarn = geteuid() == 0; if (tTd(11, 1)) { @@ -2704,6 +3057,14 @@ mailfile(filename, ctladdr, sfflags, e) fflush(e->e_xfp); /* + ** Special case /dev/null. This allows us to restrict file + ** delivery to regular files only. + */ + + if (strcmp(filename, "/dev/null") == 0) + return EX_OK; + + /* ** Fork so we can change permissions here. ** Note that we MUST use fork, not vfork, because of ** the complications of calling subroutines, etc. @@ -2717,7 +3078,6 @@ mailfile(filename, ctladdr, sfflags, e) { /* child -- actually write to file */ struct stat stb; - struct stat fsb; MCI mcibuf; int oflags = O_WRONLY|O_APPEND; @@ -2816,12 +3176,9 @@ mailfile(filename, ctladdr, sfflags, e) RealGid = DefGid; } - /* now set the group and user ids */ - endpwent(); + /* set group id list (needs /etc/group access) */ if (RealUserName != NULL && !DontInitGroups) (void) initgroups(RealUserName, RealGid); - (void) setgid(RealGid); - (void) setuid(RealUid); /* if you have a safe environment, go into it */ if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') @@ -2841,6 +3198,14 @@ mailfile(filename, ctladdr, sfflags, e) if (chdir("/") < 0) syserr("mailfile: cannot chdir(/)"); + /* now reset the group and user ids */ + endpwent(); + if (setgid(RealGid) < 0 && suidwarn) + syserr("mailfile: setgid(%ld) failed", (long) RealGid); + vendor_set_uid(RealUid); + if (setuid(RealUid) < 0 && suidwarn) + syserr("mailfile: setuid(%ld) failed", (long) RealUid); + sfflags |= SFF_NOPATHCHECK; sfflags &= ~SFF_OPENASROOT; f = safefopen(filename, oflags, FileMode, sfflags); @@ -2873,9 +3238,9 @@ mailfile(filename, ctladdr, sfflags, e) /* reset ISUID & ISGID bits for paranoid systems */ #if HASFCHMOD - (void) fchmod(fileno(f), (int) stb.st_mode); + (void) fchmod(fileno(f), (MODE_T) stb.st_mode); #else - (void) chmod(filename, (int) stb.st_mode); + (void) chmod(filename, (MODE_T) stb.st_mode); #endif (void) xfclose(f, "mailfile", filename); (void) fflush(stdout); @@ -2897,6 +3262,7 @@ mailfile(filename, ctladdr, sfflags, e) } /*NOTREACHED*/ } + return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ } /* ** HOSTSIGNATURE -- return the "signature" for a host. @@ -2929,7 +3295,6 @@ hostsignature(m, host, e) int len; #if NAMED_BIND int nmx; - auto int rcode; char *hp; char *endp; int oldoptions = _res.options; @@ -2969,23 +3334,33 @@ hostsignature(m, host, e) if (endp != NULL) *endp = '\0'; - nmx = getmxrr(hp, mxhosts, TRUE, &rcode); - - if (nmx <= 0) + if (bitnset(M_NOMX, m->m_flags)) { - register MCI *mci; - - /* update the connection info for this host */ - mci = mci_get(hp, m); - mci->mci_lastuse = curtime(); - mci->mci_exitstat = rcode; - mci->mci_errno = errno; - mci->mci_herrno = h_errno; - - /* and return the original host name as the signature */ + /* skip MX lookups */ nmx = 1; mxhosts[0] = hp; } + else + { + auto int rcode; + + nmx = getmxrr(hp, mxhosts, TRUE, &rcode); + if (nmx <= 0) + { + register MCI *mci; + + /* update the connection info for this host */ + mci = mci_get(hp, m); + mci->mci_errno = errno; + mci->mci_herrno = h_errno; + mci->mci_lastuse = curtime(); + mci_setstat(mci, rcode, NULL, NULL); + + /* use the original host name as signature */ + nmx = 1; + mxhosts[0] = hp; + } + } len = 0; for (i = 0; i < nmx; i++) diff --git a/usr.sbin/sendmail/src/domain.c b/usr.sbin/sendmail/src/domain.c index da43406689b..92036518b47 100644 --- a/usr.sbin/sendmail/src/domain.c +++ b/usr.sbin/sendmail/src/domain.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1986, 1995 Eric P. Allman + * Copyright (c) 1986, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #if NAMED_BIND -static char sccsid[] = "@(#)domain.c 8.54.1.2 (Berkeley) 9/16/96 (with name server)"; +static char sccsid[] = "@(#)domain.c 8.64 (Berkeley) 10/30/96 (with name server)"; #else -static char sccsid[] = "@(#)domain.c 8.54.1.2 (Berkeley) 9/16/96 (without name server)"; +static char sccsid[] = "@(#)domain.c 8.64 (Berkeley) 10/30/96 (without name server)"; #endif #endif /* not lint */ @@ -46,21 +46,39 @@ static char sccsid[] = "@(#)domain.c 8.54.1.2 (Berkeley) 9/16/96 (without name s #include <errno.h> #include <resolv.h> +#include <arpa/inet.h> + +/* +** The standard udp packet size PACKETSZ (512) is not sufficient for some +** nameserver answers containing very many resource records. The resolver +** may switch to tcp and retry if it detects udp packet overflow. +** Also note that the resolver routines res_query and res_search return +** the size of the *un*truncated answer in case the supplied answer buffer +** it not big enough to accommodate the entire answer. +*/ + +#ifndef MAXPACKET +# define MAXPACKET 8192 /* max packet size used internally by BIND */ +#endif typedef union { HEADER qb1; - u_char qb2[PACKETSZ]; + u_char qb2[MAXPACKET]; } querybuf; -static char MXHostBuf[MAXMXHOSTS*PACKETSZ]; +#ifndef MXHOSTBUFSIZE +# define MXHOSTBUFSIZE (128 * MAXMXHOSTS) +#endif + +static char MXHostBuf[MXHOSTBUFSIZE]; #ifndef MAXDNSRCH -#define MAXDNSRCH 6 /* number of possible domains to search */ +# define MAXDNSRCH 6 /* number of possible domains to search */ #endif #ifndef MAX -#define MAX(a, b) ((a) > (b) ? (a) : (b)) +# define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef NO_DATA @@ -114,32 +132,21 @@ getmxrr(host, mxhosts, droplocalhost, rcode) u_short pref, type; u_short localpref = 256; char *fallbackMX = FallBackMX; - static bool firsttime = TRUE; bool trycanon = FALSE; int (*resfunc)(); extern int res_query(), res_search(); u_short prefer[MAXMXHOSTS]; int weight[MAXMXHOSTS]; - extern bool getcanonname(); + extern int mxrand __P((char *)); if (tTd(8, 2)) printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost); - if (fallbackMX != NULL) + if (fallbackMX != NULL && droplocalhost && + wordinclass(fallbackMX, 'w')) { - if (firsttime && - res_query(FallBackMX, C_IN, T_A, - (u_char *) &answer, sizeof answer) < 0) - { - /* this entry is bogus */ - fallbackMX = FallBackMX = NULL; - } - else if (droplocalhost && wordinclass(fallbackMX, 'w')) - { - /* don't use fallback for this pass */ - fallbackMX = NULL; - } - firsttime = FALSE; + /* don't use fallback for this pass */ + fallbackMX = NULL; } *rcode = EX_OK; @@ -212,6 +219,10 @@ getmxrr(host, mxhosts, droplocalhost, rcode) return (-1); } + /* avoid problems after truncation in tcp packets */ + if (n > sizeof(answer)) + n = sizeof(answer); + /* find first satisfactory answer */ hp = (HEADER *)&answer; cp = (u_char *)&answer + HFIXEDSZ; @@ -350,15 +361,17 @@ punt: if (host[0] == '[') { register char *p; - struct in_addr junk; /* this may be an MX suppression-style address */ p = strchr(MXHostBuf, ']'); if (p != NULL) { *p = '\0'; - if (inet_aton(&MXHostBuf[1], &junk) != 0) + if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) + { + nmx++; *p = ']'; + } else { trycanon = TRUE; @@ -519,7 +532,7 @@ dns_getcanonname(host, hbsize, trymx, statp) int qtype; int loopcnt; char *xp; - char nbuf[MAX(PACKETSZ, MAXDNAME*2+2)]; + char nbuf[MAX(MAXPACKET, MAXDNAME*2+2)]; char *searchlist[MAXDNSRCH+2]; extern char *gethostalias(); @@ -652,6 +665,10 @@ cnameloop: else if (tTd(8, 7)) printf("\tYES\n"); + /* avoid problems after truncation in tcp packets */ + if (ret > sizeof(answer)) + ret = sizeof(answer); + /* ** Appear to have a match. Confirm it by searching for A or ** CNAME records. If we don't have a local domain diff --git a/usr.sbin/sendmail/src/envelope.c b/usr.sbin/sendmail/src/envelope.c index a22f73caa85..67815223cf0 100644 --- a/usr.sbin/sendmail/src/envelope.c +++ b/usr.sbin/sendmail/src/envelope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)envelope.c 8.76.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)envelope.c 8.99 (Berkeley) 12/1/96"; #endif /* not lint */ #include "sendmail.h" @@ -82,6 +82,7 @@ newenvelope(e, parent) ** ** Parameters: ** e -- the envelope to deallocate. +** fulldrop -- if set, do return receipts. ** ** Returns: ** none. @@ -92,11 +93,14 @@ newenvelope(e, parent) */ void -dropenvelope(e) +dropenvelope(e, fulldrop) register ENVELOPE *e; + bool fulldrop; { bool queueit = FALSE; + bool message_timeout = FALSE; bool failure_return = FALSE; + bool delay_return = FALSE; bool success_return = FALSE; register ADDRESS *q; char *id = e->e_id; @@ -106,7 +110,7 @@ dropenvelope(e) { extern void printenvflags(); - printf("dropenvelope %x: id=", e); + printf("dropenvelope %lx: id=", (u_long) e); xputs(e->e_id); printf(", flags="); printenvflags(e); @@ -143,16 +147,35 @@ dropenvelope(e) ** Extract state information from dregs of send list. */ + if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]) + message_timeout = TRUE; + e->e_flags &= ~EF_QUEUERUN; for (q = e->e_sendqueue; q != NULL; q = q->q_next) { - if (!bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags) || - bitset(QQUEUEUP, q->q_flags)) + if (bitset(QQUEUEUP, q->q_flags) && + bitset(QDONTSEND, q->q_flags)) + { + /* I'm not sure how this happens..... */ + if (tTd(50, 2)) + { + printf("Bogus flags: "); + printaddr(q, FALSE); + } + q->q_flags &= ~QDONTSEND; + } + if (!bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags)) queueit = TRUE; +#if XDEBUG + else if (bitset(QQUEUEUP, q->q_flags)) + syslog(LOG_DEBUG, "dropenvelope: %s: q_flags = %x, paddr = %s", + e->e_id, q->q_flags, q->q_paddr); +#endif /* see if a notification is needed */ - if (bitset(QBADADDR, q->q_flags) && - bitset(QPINGONFAILURE, q->q_flags)) + if (bitset(QPINGONFAILURE, q->q_flags) && + ((message_timeout && bitset(QQUEUEUP, q->q_flags)) || + bitset(QBADADDR, q->q_flags))) { failure_return = TRUE; if (q->q_owner == NULL && !emptyaddr(&e->e_from)) @@ -177,23 +200,25 @@ dropenvelope(e) if (!queueit) /* nothing to do */ ; - else if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]) + else if (message_timeout) { - (void) snprintf(buf, sizeof buf, "Cannot send message for %s", - pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); - if (e->e_message != NULL) - free(e->e_message); - e->e_message = newstr(buf); - message(buf); - e->e_flags |= EF_CLRQUEUE; - failure_return = TRUE; + if (failure_return) + { + (void) snprintf(buf, sizeof buf, + "Cannot send message within %s", + pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); + if (e->e_message != NULL) + free(e->e_message); + e->e_message = newstr(buf); + message(buf); + e->e_flags |= EF_CLRQUEUE; + } fprintf(e->e_xfp, "Message could not be delivered for %s\n", pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); fprintf(e->e_xfp, "Message will be deleted from queue\n"); for (q = e->e_sendqueue; q != NULL; q = q->q_next) { - if (bitset(QQUEUEUP, q->q_flags) || - !bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags)) + if (!bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags)) { q->q_flags |= QBADADDR; q->q_status = "4.4.7"; @@ -203,19 +228,7 @@ dropenvelope(e) else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 && curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass]) { - bool delay_return = FALSE; - - for (q = e->e_sendqueue; q != NULL; q = q->q_next) - { - if (bitset(QQUEUEUP, q->q_flags) && - bitset(QPINGONDELAY, q->q_flags)) - { - q->q_flags |= QDELAYED; - delay_return = TRUE; - } - } - if (delay_return && - !bitset(EF_WARNING|EF_RESPONSE, e->e_flags) && + if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) && e->e_class >= 0 && e->e_from.q_paddr != NULL && strcmp(e->e_from.q_paddr, "<>") != 0 && @@ -223,6 +236,18 @@ dropenvelope(e) (strlen(e->e_from.q_paddr) <= (SIZE_T) 8 || strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0)) { + for (q = e->e_sendqueue; q != NULL; q = q->q_next) + { + if (bitset(QQUEUEUP, q->q_flags) && + bitset(QPINGONDELAY, q->q_flags)) + { + q->q_flags |= QDELAYED; + delay_return = TRUE; + } + } + } + if (delay_return) + { (void) snprintf(buf, sizeof buf, "Warning: could not send message for past %s", pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE)); @@ -231,7 +256,6 @@ dropenvelope(e) e->e_message = newstr(buf); message(buf); e->e_flags |= EF_WARNING; - failure_return = TRUE; } fprintf(e->e_xfp, "Warning: message still undelivered after %s\n", @@ -241,8 +265,8 @@ dropenvelope(e) } if (tTd(50, 2)) - printf("failure_return=%d success_return=%d queueit=%d\n", - failure_return, success_return, queueit); + printf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n", + failure_return, delay_return, success_return, queueit); /* ** If we had some fatal error, but no addresses are marked as @@ -263,21 +287,15 @@ dropenvelope(e) ** Send back return receipts as requested. */ -/* - if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags) - && !bitset(PRIV_NORECEIPTS, PrivacyFlags)) -*/ - if (e->e_receiptto == NULL) - e->e_receiptto = e->e_from.q_paddr; - if (success_return && !failure_return && + if (success_return && !failure_return && !delay_return && fulldrop && !bitset(PRIV_NORECEIPTS, PrivacyFlags) && - strcmp(e->e_receiptto, "<>") != 0) + strcmp(e->e_from.q_paddr, "<>") != 0) { auto ADDRESS *rlist = NULL; e->e_flags |= EF_SENDRECEIPT; - (void) sendtolist(e->e_receiptto, NULLADDR, &rlist, 0, e); - (void) returntosender("Return receipt", rlist, FALSE, e); + (void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e); + (void) returntosender("Return receipt", rlist, RTSF_NO_BODY, e); } e->e_flags &= ~EF_SENDRECEIPT; @@ -285,8 +303,12 @@ dropenvelope(e) ** Arrange to send error messages if there are fatal errors. */ - if (failure_return && e->e_errormode != EM_QUIET) + if ((failure_return || delay_return) && e->e_errormode != EM_QUIET) + { + extern void savemail __P((ENVELOPE *, bool)); + savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags)); + } /* ** Arrange to send warning messages to postmaster as requested. @@ -299,7 +321,7 @@ dropenvelope(e) auto ADDRESS *rlist = NULL; (void) sendtolist(PostMasterCopy, NULLADDR, &rlist, 0, e); - (void) returntosender(e->e_message, rlist, FALSE, e); + (void) returntosender(e->e_message, rlist, RTSF_PM_BOUNCE, e); } /* @@ -327,7 +349,7 @@ simpledrop: } else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) { -#ifdef QUEUE +#if QUEUE queueup(e, FALSE); #else /* QUEUE */ syserr("554 dropenvelope: queueup"); @@ -499,7 +521,6 @@ settime(e) char tbuf[20]; /* holds "current" time */ char dbuf[30]; /* holds ctime(tbuf) */ register struct tm *tm; - extern char *arpadate(); extern struct tm *gmtime(); now = curtime(); @@ -548,7 +569,7 @@ openxscript(e) if (e->e_xfp != NULL) return; p = queuename(e, 'x'); - fd = open(p, O_WRONLY|O_CREAT|O_APPEND, 0644); + fd = open(p, O_WRONLY|O_CREAT|O_APPEND, FileMode); if (fd < 0) { syserr("Can't create transcript file %s", p); @@ -754,7 +775,8 @@ setsender(from, e, delimptr, internal) FullName = NULL; } - if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL) + if (e->e_from.q_user[0] != '\0' && + (pw = sm_getpwnam(e->e_from.q_user)) != NULL) { /* ** Process passwd file entry. @@ -782,6 +804,10 @@ setsender(from, e, delimptr, internal) FullName = newstr(buf); } } + else + { + e->e_from.q_home = "/no/such/directory"; + } if (FullName != NULL && !internal) define('x', FullName, e); } @@ -874,31 +900,31 @@ struct eflags struct eflags EnvelopeFlags[] = { - "OLDSTYLE", EF_OLDSTYLE, - "INQUEUE", EF_INQUEUE, - "NO_BODY_RETN", EF_NO_BODY_RETN, - "CLRQUEUE", EF_CLRQUEUE, - "SENDRECEIPT", EF_SENDRECEIPT, - "FATALERRS", EF_FATALERRS, - "DELETE_BCC", EF_DELETE_BCC, - "RESPONSE", EF_RESPONSE, - "RESENT", EF_RESENT, - "VRFYONLY", EF_VRFYONLY, - "WARNING", EF_WARNING, - "QUEUERUN", EF_QUEUERUN, - "GLOBALERRS", EF_GLOBALERRS, - "PM_NOTIFY", EF_PM_NOTIFY, - "METOO", EF_METOO, - "LOGSENDER", EF_LOGSENDER, - "NORECEIPT", EF_NORECEIPT, - "HAS8BIT", EF_HAS8BIT, - "NL_NOT_EOL", EF_NL_NOT_EOL, - "CRLF_NOT_EOL", EF_CRLF_NOT_EOL, - "RET_PARAM", EF_RET_PARAM, - "HAS_DF", EF_HAS_DF, - "IS_MIME", EF_IS_MIME, - "DONT_MIME", EF_DONT_MIME, - NULL + { "OLDSTYLE", EF_OLDSTYLE }, + { "INQUEUE", EF_INQUEUE }, + { "NO_BODY_RETN", EF_NO_BODY_RETN }, + { "CLRQUEUE", EF_CLRQUEUE }, + { "SENDRECEIPT", EF_SENDRECEIPT }, + { "FATALERRS", EF_FATALERRS }, + { "DELETE_BCC", EF_DELETE_BCC }, + { "RESPONSE", EF_RESPONSE }, + { "RESENT", EF_RESENT }, + { "VRFYONLY", EF_VRFYONLY }, + { "WARNING", EF_WARNING }, + { "QUEUERUN", EF_QUEUERUN }, + { "GLOBALERRS", EF_GLOBALERRS }, + { "PM_NOTIFY", EF_PM_NOTIFY }, + { "METOO", EF_METOO }, + { "LOGSENDER", EF_LOGSENDER }, + { "NORECEIPT", EF_NORECEIPT }, + { "HAS8BIT", EF_HAS8BIT }, + { "NL_NOT_EOL", EF_NL_NOT_EOL }, + { "CRLF_NOT_EOL", EF_CRLF_NOT_EOL }, + { "RET_PARAM", EF_RET_PARAM }, + { "HAS_DF", EF_HAS_DF }, + { "IS_MIME", EF_IS_MIME }, + { "DONT_MIME", EF_DONT_MIME }, + { NULL } }; void diff --git a/usr.sbin/sendmail/src/err.c b/usr.sbin/sendmail/src/err.c index c231ef119d4..2e0f0b91004 100644 --- a/usr.sbin/sendmail/src/err.c +++ b/usr.sbin/sendmail/src/err.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)err.c 8.42.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)err.c 8.52 (Berkeley) 12/1/96"; #endif /* not lint */ # include "sendmail.h" @@ -145,10 +145,30 @@ syserr(fmt, va_alist) CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, uname, &MsgBuf[4]); # endif /* LOG */ - if (olderrno == EMFILE) + switch (olderrno) { + case EBADF: + case ENFILE: + case EMFILE: + case ENOTTY: +#ifdef EFBIG + case EFBIG: +#endif +#ifdef ESPIPE + case ESPIPE: +#endif +#ifdef EPIPE + case EPIPE: +#endif +#ifdef ENOBUFS + case ENOBUFS: +#endif +#ifdef ESTALE + case ESTALE: +#endif printopenfds(TRUE); mci_dump_all(TRUE); + break; } if (panic) { @@ -384,6 +404,11 @@ putoutmsg(msg, holdmsg, heldmsg) if (!heldmsg && CurEnv->e_xfp != NULL && strchr("45", msg[0]) != NULL) fprintf(CurEnv->e_xfp, "%s\n", msg); +#ifdef LOG + if (LogLevel >= 15 && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) + syslog(LOG_INFO, "--> %s%s", msg, holdmsg ? " (held)" : ""); +#endif + if (msgcode == '8') msg[0] = '0'; @@ -407,7 +432,7 @@ putoutmsg(msg, holdmsg, heldmsg) else fprintf(OutChannel, "%s\n", &msg[4]); if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), + fprintf(TrafficLogFile, "%05d >>> %s\n", (int) getpid(), (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : &msg[4]); if (msg[3] == ' ') (void) fflush(OutChannel); @@ -606,7 +631,7 @@ errstring(errnum) extern char *sys_errlist[]; extern int sys_nerr; # endif -# ifdef SMTP +# if SMTP extern char *SmtpPhase; # endif /* SMTP */ @@ -624,17 +649,29 @@ errstring(errnum) case ECONNRESET: bp = buf; snprintf(bp, SPACELEFT(buf, bp), "%s", sys_errlist[errnum]); - bp += strlen(buf); + bp += strlen(bp); + if (CurHostName != NULL) + { + if (errnum == ETIMEDOUT) + { + snprintf(bp, SPACELEFT(buf, bp), " with "); + bp += strlen(bp); + } + else + { + bp = buf; + snprintf(bp, SPACELEFT(buf, bp), + "Connection reset by "); + bp += strlen(bp); + } + snprintf(bp, SPACELEFT(buf, bp), "%s", + shortenstring(CurHostName, 203)); + bp += strlen(buf); + } if (SmtpPhase != NULL) { snprintf(bp, SPACELEFT(buf, bp), " during %s", SmtpPhase); - bp += strlen(bp); - } - if (CurHostName != NULL) - { - snprintf(bp, SPACELEFT(buf, bp), " with %s", - shortenstring(CurHostName, 203)); } return (buf); diff --git a/usr.sbin/sendmail/src/headers.c b/usr.sbin/sendmail/src/headers.c index 5a375b8eb0a..ba1845df168 100644 --- a/usr.sbin/sendmail/src/headers.c +++ b/usr.sbin/sendmail/src/headers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)headers.c 8.82.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)headers.c 8.101 (Berkeley) 11/23/96"; #endif /* not lint */ # include <errno.h> @@ -74,7 +74,6 @@ chompheader(line, def, hdrp, e) bool cond = FALSE; bool headeronly; BITMAP mopts; - char buf[MAXNAME + 1]; if (tTd(31, 6)) { @@ -158,7 +157,6 @@ chompheader(line, def, hdrp, e) if (bitset(H_EOH, hi->hi_flags)) return (hi->hi_flags); -#ifdef LOTUS_NOTES_HACK /* ** Horrible hack to work around problem with Lotus Notes SMTP ** mail gateway, which generates From: headers with newlines in @@ -172,7 +170,6 @@ chompheader(line, def, hdrp, e) while ((p = strchr(fvalue, '\n')) != NULL) *p = ' '; } -#endif /* ** Drop explicit From: if same as what we would generate. @@ -195,46 +192,6 @@ chompheader(line, def, hdrp, e) (strcmp(fvalue, e->e_from.q_paddr) == 0 || strcmp(fvalue, e->e_from.q_user) == 0)) return (hi->hi_flags); -#ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ -#if USERDB - else - { - auto ADDRESS a; - char *fancy; - bool oldSuprErrs = SuprErrs; - extern char *crackaddr(); - extern char *udbsender(); - - /* - ** Try doing USERDB rewriting even on fully commented - ** names; this saves the "comment" information (such - ** as full name) and rewrites the electronic part. - ** - ** XXX This code doesn't belong here -- parsing should - ** XXX not be done during collect() phase because - ** XXX error messages can confuse the SMTP phase. - ** XXX Setting SuprErrs is a crude hack around this - ** XXX problem. - */ - - if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP) - SuprErrs = TRUE; - fancy = crackaddr(fvalue); - if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && - bitnset(M_CHECKUDB, a.q_mailer->m_flags) && - (p = udbsender(a.q_user)) != NULL) - { - char *oldg = macvalue('g', e); - - define('g', p, e); - expand(fancy, buf, sizeof buf, e); - define('g', oldg, e); - fvalue = buf; - } - SuprErrs = oldSuprErrs; - } -#endif -#endif } /* delete default value for this header */ @@ -433,6 +390,7 @@ eatheader(e, full) int hopcnt = 0; char *msgid; char buf[MAXLINE]; + extern int priencode __P((char *)); /* ** Set up macros for possible expansion in headers. @@ -522,10 +480,6 @@ eatheader(e, full) while (isascii(*msgid) && isspace(*msgid)) msgid++; } - - /* see if this is a return-receipt header */ - if (bitset(H_RECEIPTTO, h->h_flags)) - e->e_receiptto = h->h_value; } if (tTd(32, 1)) printf("----------------------------\n"); @@ -558,11 +512,11 @@ eatheader(e, full) if (p != NULL) { /* (this should be in the configuration file) */ - if (strcasecmp(p, "urgent")) + if (strcasecmp(p, "urgent") == 0) e->e_timeoutclass = TOC_URGENT; - else if (strcasecmp(p, "normal")) + else if (strcasecmp(p, "normal") == 0) e->e_timeoutclass = TOC_NORMAL; - else if (strcasecmp(p, "non-urgent")) + else if (strcasecmp(p, "non-urgent") == 0) e->e_timeoutclass = TOC_NONURGENT; } @@ -807,6 +761,7 @@ crackaddr(addr) int realcmtlev; int anglelev, realanglelev; int copylev; + int bracklev; bool qmode; bool realqmode; bool skipping; @@ -833,9 +788,10 @@ crackaddr(addr) */ bp = bufhead = buf; - buflim = &buf[sizeof buf - 5]; + buflim = &buf[sizeof buf - 6]; p = addrhead = addr; copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; + bracklev = 0; qmode = realqmode = FALSE; while ((c = *p++) != '\0') @@ -892,7 +848,8 @@ crackaddr(addr) realcmtlev++; if (copylev++ <= 0) { - *bp++ = ' '; + if (bp != bufhead) + *bp++ = ' '; *bp++ = c; } } @@ -918,20 +875,33 @@ crackaddr(addr) bp--; } + /* count nesting on [ ... ] (for IPv6 domain literals) */ + if (c == '[') + bracklev++; + else if (c == ']') + bracklev--; + /* check for group: list; syntax */ - if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) + if (c == ':' && anglelev <= 0 && bracklev <= 0 && + !gotcolon && !ColonOkInAddr) { register char *q; - if (*p == ':') + /* + ** Check for DECnet phase IV ``::'' (host::user) + ** or ** DECnet phase V ``:.'' syntaxes. The latter + ** covers ``user@DEC:.tay.myhost'' and + ** ``DEC:.tay.myhost::user'' syntaxes (bletch). + */ + + if (*p == ':' || *p == '.') { - /* special case -- :: syntax */ if (cmtlev <= 0 && !qmode) quoteit = TRUE; if (copylev > 0 && !skipping) { *bp++ = c; - *bp++ = c; + *bp++ = *p; } p++; goto putg; @@ -1086,6 +1056,8 @@ crackaddr(addr) putg: if (copylev <= 0 && !putgmac) { + if (bp > bufhead && bp[-1] == ')') + *bp++ = ' '; *bp++ = MACROEXPAND; *bp++ = 'g'; putgmac = TRUE; @@ -1102,7 +1074,11 @@ crackaddr(addr) *bp++ = '\0'; if (tTd(33, 1)) - printf("crackaddr=>`%s'\n", buf); + { + printf("crackaddr=>`"); + xputs(buf); + printf("'\n"); + } return (buf); } @@ -1129,11 +1105,12 @@ crackaddr(addr) #endif void -putheader(mci, h, e) +putheader(mci, hdr, e) register MCI *mci; - register HDR *h; + HDR *hdr; register ENVELOPE *e; { + register HDR *h; char buf[MAX(MAXLINE,BUFSIZ)]; char obuf[MAXLINE]; @@ -1142,7 +1119,7 @@ putheader(mci, h, e) mci->mci_mailer->m_name); mci->mci_flags |= MCIF_INHEADER; - for (; h != NULL; h = h->h_link) + for (h = hdr; h != NULL; h = h->h_link) { register char *p = h->h_value; extern bool bitintersect(); @@ -1155,7 +1132,7 @@ putheader(mci, h, e) /* suppress Content-Transfer-Encoding: if we are MIMEing */ if (bitset(H_CTE, h->h_flags) && - bitset(MCIF_CVT8TO7|MCIF_INMIME, mci->mci_flags)) + bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags)) { if (tTd(34, 11)) printf(" (skipped (content-transfer-encoding))\n"); @@ -1166,7 +1143,8 @@ putheader(mci, h, e) { if (tTd(34, 11)) printf("\n"); - goto vanilla; + put_vanilla_header(h, p, mci); + continue; } if (bitset(H_CHECK|H_ACHECK, h->h_flags) && @@ -1239,31 +1217,7 @@ putheader(mci, h, e) } else { - /* vanilla header line */ - register char *nlp; - register char *obp; - -vanilla: - obp = obuf; - (void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", - h->h_field); - obp = obuf + strlen(obuf); - while ((nlp = strchr(p, '\n')) != NULL) - { - - *nlp = '\0'; - snprintf(obp, SPACELEFT(obuf, obp), "%.*s", - sizeof obuf - (obp - obuf) - 1, p); - *nlp = '\n'; - putline(obuf, mci); - p = ++nlp; - obp = obuf; - if (*p != ' ' && *p != '\t') - *obp++ = ' '; - } - snprintf(obp, SPACELEFT(obuf, obp), "%.*s", - sizeof obuf - (obp - obuf) - 1, p); - putline(obuf, mci); + put_vanilla_header(h, p, mci); } } @@ -1277,7 +1231,7 @@ vanilla: bitset(EF_HAS8BIT, e->e_flags) && !bitset(EF_DONT_MIME, e->e_flags) && !bitnset(M_8BITS, mci->mci_mailer->m_flags) && - !bitset(MCIF_CVT8TO7, mci->mci_flags)) + !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8, mci->mci_flags)) { if (hvalue("MIME-Version", e->e_header) == NULL) putline("MIME-Version: 1.0", mci); @@ -1294,6 +1248,55 @@ vanilla: #endif } /* +** PUT_VANILLA_HEADER -- output a fairly ordinary header +** +** Parameters: +** h -- the structure describing this header +** v -- the value of this header +** mci -- the connection info for output +** +** Returns: +** none. +*/ + +void +put_vanilla_header(h, v, mci) + HDR *h; + char *v; + MCI *mci; +{ + register char *nlp; + register char *obp; + int putflags; + char obuf[MAXLINE]; + + putflags = 0; +#ifdef _FFR_7BITHDRS + if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) + putflags |= PXLF_STRIP8BIT; +#endif + (void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field); + obp = obuf + strlen(obuf); + while ((nlp = strchr(v, '\n')) != NULL) + { + int l; + + l = nlp - v; + if (sizeof obuf - (obp - obuf) < l) + l = sizeof obuf - (obp - obuf); + + snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); + putxline(obuf, mci, putflags); + v += l + 1; + obp = obuf; + if (*v != ' ' && *v != '\t') + *obp++ = ' '; + } + snprintf(obp, SPACELEFT(obuf, obp), "%.*s", + sizeof obuf - (obp - obuf) - 1, v); + putxline(obuf, mci, putflags); +} +/* ** COMMAIZE -- output a header field, making a comma-translated list. ** ** Parameters: @@ -1322,6 +1325,7 @@ commaize(h, p, oldstyle, mci, e) int opos; int omax; bool firstone = TRUE; + int putflags = 0; char obuf[MAXLINE + 3]; /* @@ -1332,6 +1336,11 @@ commaize(h, p, oldstyle, mci, e) if (tTd(14, 2)) printf("commaize(%s: %s)\n", h->h_field, p); +#ifdef _FFR_7BITHDRS + if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) + putflags |= PXLF_STRIP8BIT; +#endif + obp = obuf; (void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field); opos = strlen(h->h_field) + 2; @@ -1428,7 +1437,7 @@ commaize(h, p, oldstyle, mci, e) if (opos > omax && !firstone) { snprintf(obp, SPACELEFT(obuf, obp), ",\n"); - putline(obuf, mci); + putxline(obuf, mci, putflags); obp = obuf; (void) strcpy(obp, " "); opos = strlen(obp); @@ -1447,7 +1456,7 @@ commaize(h, p, oldstyle, mci, e) *p = savechar; } *obp = '\0'; - putline(obuf, mci); + putxline(obuf, mci, putflags); } /* ** COPYHEADER -- copy header list diff --git a/usr.sbin/sendmail/src/macro.c b/usr.sbin/sendmail/src/macro.c index 94ef834bb08..e31d0deb21c 100644 --- a/usr.sbin/sendmail/src/macro.c +++ b/usr.sbin/sendmail/src/macro.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)macro.c 8.13 (Berkeley) 7/10/95"; +static char sccsid[] = "@(#)macro.c 8.17 (Berkeley) 5/13/96"; #endif /* not lint */ # include "sendmail.h" @@ -70,8 +70,10 @@ expand(s, buf, bufsize, e) bool skipping; /* set if conditionally skipping output */ bool recurse = FALSE; /* set if recursion required */ int i; + int skiplev; /* skipping nesting level */ int iflev; /* if nesting level */ char xbuf[BUFSIZ]; + static int explevel = 0; if (tTd(35, 24)) { @@ -81,6 +83,7 @@ expand(s, buf, bufsize, e) } skipping = FALSE; + skiplev = 0; iflev = 0; if (s == NULL) s = ""; @@ -98,23 +101,29 @@ expand(s, buf, bufsize, e) switch (c & 0377) { case CONDIF: /* see if var set */ + iflev++; c = *++s; if (skipping) - iflev++; + skiplev++; else skipping = macvalue(c, e) == NULL; continue; case CONDELSE: /* change state of skipping */ if (iflev == 0) + break; + if (skiplev == 0) skipping = !skipping; continue; case CONDFI: /* stop skipping */ if (iflev == 0) + break; + iflev--; + if (skiplev == 0) skipping = FALSE; if (skipping) - iflev--; + skiplev--; continue; case MACROEXPAND: /* macro interpolation */ @@ -135,7 +144,7 @@ expand(s, buf, bufsize, e) ** Interpolate q or output one character */ - if (skipping || xp >= &xbuf[sizeof xbuf]) + if (skipping || xp >= &xbuf[sizeof xbuf - 1]) continue; if (q == NULL) *xp++ = c; @@ -163,8 +172,15 @@ expand(s, buf, bufsize, e) /* recurse as appropriate */ if (recurse) { - expand(xbuf, buf, bufsize, e); - return; + if (explevel < MaxMacroRecursion) + { + explevel++; + expand(xbuf, buf, bufsize, e); + explevel--; + return; + } + syserr("expand: recursion too deep (%d max)", + MaxMacroRecursion); } /* copy results out */ diff --git a/usr.sbin/sendmail/src/main.c b/usr.sbin/sendmail/src/main.c index e3475eeed7e..a4805f91f8b 100644 --- a/usr.sbin/sendmail/src/main.c +++ b/usr.sbin/sendmail/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -39,12 +39,13 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.162.1.3 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)main.c 8.223 (Berkeley) 12/1/96"; #endif /* not lint */ #define _DEFINE #include "sendmail.h" +#include <arpa/inet.h> #if NAMED_BIND #include <resolv.h> #endif @@ -75,14 +76,16 @@ char edata, end; ** See the associated documentation for details. ** ** Author: -** Eric Allman, UCB/INGRES (until 10/81) +** Eric Allman, UCB/INGRES (until 10/81). ** Britton-Lee, Inc., purveyors of fine -** database computers (from 11/81) -** Now back at UCB at the Mammoth project. -** The support of the INGRES Project and Britton-Lee is -** gratefully acknowledged. Britton-Lee in -** particular had absolutely nothing to gain from -** my involvement in this project. +** database computers (11/81 - 10/88). +** International Computer Science Institute +** (11/88 - 9/89). +** UCB/Mammoth Project (10/89 - 7/95). +** InReference, Inc. (8/95 - present). +** The support of the my employers is gratefully acknowledged. +** Few of them (Britton-Lee in particular) have had +** anything to gain from my involvement in this project. */ @@ -97,14 +100,17 @@ bool Warn_Q_option = FALSE; /* warn about Q option use */ char **SaveArgv; /* argument vector for re-execing */ static void obsolete(); +extern void printmailer __P((MAILER *)); +extern void tTflag __P((char *)); -#ifdef DAEMON -#ifndef SMTP -ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR -#endif /* SMTP */ -#endif /* DAEMON */ +#if DAEMON && !SMTP +ERROR %%%% Cannot have DAEMON mode without SMTP %%%% ERROR +#endif /* DAEMON && !SMTP */ +#if SMTP && !QUEUE +ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR +#endif /* DAEMON && !SMTP */ -#define MAXCONFIGLEVEL 6 /* highest config version level known */ +#define MAXCONFIGLEVEL 7 /* highest config version level known */ int main(argc, argv, envp) @@ -124,27 +130,42 @@ main(argc, argv, envp) bool safecf = TRUE; bool warn_C_flag = FALSE; char warn_f_flag = '\0'; + bool run_in_foreground = FALSE; /* -bD mode */ static bool reenter = FALSE; struct passwd *pw; struct stat stb; struct hostent *hp; + bool nullserver = FALSE; char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ static char rnamebuf[MAXNAME]; /* holds RealUserName */ + char *emptyenviron[1]; extern int DtableSize; extern int optind; extern int opterr; + extern char *optarg; + extern char **environ; extern time_t convtime(); extern void intsig(); extern struct hostent *myhostname(); - extern char *arpadate(); extern char *getauthinfo(); extern char *getcfname(); - extern char *optarg; - extern char **environ; extern void sigusr1(); extern void sighup(); extern void initmacros __P((ENVELOPE *)); + extern void init_md __P((int, char **)); + extern int getdtsize __P((void)); + extern void tTsetup __P((u_char *, int, char *)); + extern void setdefaults __P((ENVELOPE *)); + extern void initsetproctitle __P((int, char **, char **)); + extern void init_vendor_macros __P((ENVELOPE *)); + extern void load_if_names __P((void)); + extern void vendor_pre_defaults __P((ENVELOPE *)); + extern void vendor_post_defaults __P((ENVELOPE *)); + extern void readcf __P((char *, bool, ENVELOPE *)); + extern void printqueue __P((void)); + extern void sendtoargv __P((char **, ENVELOPE *)); extern void resetlimits __P((void)); + extern void drop_privileges __P((void)); /* ** Check to see if we reentered. @@ -159,6 +180,9 @@ main(argc, argv, envp) } reenter = TRUE; + /* avoid null pointer dereferences */ + TermEscape.te_rv_on = TermEscape.te_rv_off = ""; + /* do machine-dependent initializations */ init_md(argc, argv); @@ -205,6 +229,45 @@ main(argc, argv, envp) tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); + /* drop group id privileges (RunAsUser not yet set) */ + drop_privileges(); + + /* Handle any non-getoptable constructions. */ + obsolete(argv); + + /* + ** Do a quick prescan of the argument list. + */ + +#if defined(__osf__) || defined(_AIX3) +# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:x" +#endif +#if defined(sony_news) +# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mN:nO:o:p:q:R:r:sTtUV:vX:" +#endif +#ifndef OPTIONS +# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:" +#endif + opterr = 0; + while ((j = getopt(argc, argv, OPTIONS)) != EOF) + { + switch (j) + { + case 'd': + /* hack attack -- see if should use ANSI mode */ + if (strcmp(optarg, "ANSI") == 0) + { + TermEscape.te_rv_on = "\033[7m"; + TermEscape.te_rv_off = "\033[0m"; + break; + } + tTflag(optarg); + setbuf(stdout, (char *) NULL); + break; + } + } + opterr = 1; + /* set up the blank envelope */ BlankEnvelope.e_puthdr = putheader; BlankEnvelope.e_putbody = putbody; @@ -247,35 +310,6 @@ main(argc, argv, envp) } SaveArgv[i] = NULL; - /* Handle any non-getoptable constructions. */ - obsolete(argv); - - /* - ** Do a quick prescan of the argument list. - */ - -#if defined(__osf__) || defined(_AIX3) -# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:x" -#endif -#if defined(sony_news) -# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mnO:o:p:q:r:sTtvX:" -#endif -#ifndef OPTIONS -# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:" -#endif - opterr = 0; - while ((j = getopt(argc, argv, OPTIONS)) != EOF) - { - switch (j) - { - case 'd': - tTflag(optarg); - setbuf(stdout, (char *) NULL); - break; - } - } - opterr = 1; - if (tTd(0, 1)) { int ll; @@ -308,7 +342,7 @@ main(argc, argv, envp) int ll; extern char *OsCompileOptions[]; - printf(" OS Defines:", Version); + printf(" OS Defines:"); av = OsCompileOptions; ll = 7; while (*av != NULL) @@ -332,7 +366,7 @@ main(argc, argv, envp) #ifdef _PATH_UNIX printf("Kernel symbols:\t%s\n", _PATH_UNIX); #endif - printf(" Config file:\t%s\n", getcfname()); + printf(" Def Conf file:\t%s\n", getcfname()); printf(" Pid file:\t%s\n", PidFile); } @@ -342,6 +376,11 @@ main(argc, argv, envp) /* initialize for setproctitle */ initsetproctitle(argc, argv, envp); + /* clear sendmail's environment */ + ExternalEnviron = environ; + emptyenviron[0] = NULL; + environ = emptyenviron; + /* prime the child environment */ setuserenv("AGENT", "sendmail"); @@ -351,14 +390,20 @@ main(argc, argv, envp) (void) setsignal(SIGPIPE, SIG_IGN); OldUmask = umask(022); OpMode = MD_DELIVER; - FullName = getenv("NAME"); + FullName = getextenv("NAME"); + + /* + ** Initialize name server if it is going to be used. + */ #if NAMED_BIND - if (tTd(8, 8)) - { + if (!bitset(RES_INIT, _res.options)) res_init(); + if (tTd(8, 8)) _res.options |= RES_DEBUG; - } +# ifdef RES_NOALIASES + _res.options |= RES_NOALIASES; +# endif #endif errno = 0; @@ -393,6 +438,8 @@ main(argc, argv, envp) while (p != NULL && strchr(&p[1], '.') != NULL) { *p = '\0'; + if (tTd(0, 4)) + printf("\ta.k.a.: %s\n", jbuf); setclass('w', jbuf); *p++ = '.'; p = strchr(p, '.'); @@ -449,13 +496,6 @@ main(argc, argv, envp) define('b', arpadate((char *) NULL), CurEnv); /* - ** Find our real host name for future logging. - */ - - p = getauthinfo(STDIN_FILENO); - define('_', p, CurEnv); - - /* ** Crack argv. */ @@ -469,6 +509,10 @@ main(argc, argv, envp) OpMode = MD_PRINT; else if (strcmp(p, "smtpd") == 0) OpMode = MD_DAEMON; + else if (strcmp(p, "hoststat") == 0) + OpMode = MD_HOSTSTAT; + else if (strcmp(p, "purgestat") == 0) + OpMode = MD_PURGESTAT; optind = 1; while ((j = getopt(argc, argv, OPTIONS)) != EOF) @@ -479,28 +523,26 @@ main(argc, argv, envp) switch (j = *optarg) { case MD_DAEMON: -# ifdef DAEMON - if (RealUid != 0) { - usrerr("Permission denied"); - exit (EX_USAGE); - } - (void) unsetenv("HOSTALIASES"); -# else + case MD_FGDAEMON: +# if !DAEMON usrerr("Daemon mode not implemented"); ExitStat = EX_USAGE; break; # endif /* DAEMON */ case MD_SMTP: -# ifndef SMTP +# if !SMTP usrerr("I don't speak SMTP"); ExitStat = EX_USAGE; break; # endif /* SMTP */ + + case MD_INITALIAS: case MD_DELIVER: case MD_VERIFY: case MD_TEST: - case MD_INITALIAS: case MD_PRINT: + case MD_HOSTSTAT: + case MD_PURGESTAT: case MD_ARPAFTP: OpMode = j; break; @@ -557,7 +599,6 @@ main(argc, argv, envp) { usrerr("Bad hop count (%s)", optarg); ExitStat = EX_USAGE; - break; } break; @@ -565,6 +606,29 @@ main(argc, argv, envp) NoAlias = TRUE; break; + case 'N': /* delivery status notifications */ + DefaultNotify |= QHASNOTIFY; + if (strcasecmp(optarg, "never") == 0) + break; + for (p = optarg; p != NULL; optarg = p) + { + p = strchr(p, ','); + if (p != NULL) + *p++ = '\0'; + if (strcasecmp(optarg, "success") == 0) + DefaultNotify |= QPINGONSUCCESS; + else if (strcasecmp(optarg, "failure") == 0) + DefaultNotify |= QPINGONFAILURE; + else if (strcasecmp(optarg, "delay") == 0) + DefaultNotify |= QPINGONDELAY; + else + { + usrerr("Invalid -N argument"); + ExitStat = EX_USAGE; + } + } + break; + case 'o': /* set option */ setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv); break; @@ -594,8 +658,7 @@ main(argc, argv, envp) break; case 'q': /* run queue files at intervals */ -# ifdef QUEUE - (void) unsetenv("HOSTALIASES"); +# if QUEUE FullName = NULL; queuemode = TRUE; switch (optarg[0]) @@ -622,10 +685,41 @@ main(argc, argv, envp) # endif /* QUEUE */ break; + case 'R': /* DSN RET: what to return */ + if (bitset(EF_RET_PARAM, CurEnv->e_flags)) + { + usrerr("Duplicate -R flag"); + ExitStat = EX_USAGE; + break; + } + CurEnv->e_flags |= EF_RET_PARAM; + if (strcasecmp(optarg, "hdrs") == 0) + CurEnv->e_flags |= EF_NO_BODY_RETN; + else if (strcasecmp(optarg, "full") != 0) + { + usrerr("Invalid -R value"); + ExitStat = EX_USAGE; + } + break; + case 't': /* read recipients from message */ GrabTo = TRUE; break; + case 'U': /* initial (user) submission */ + UserSubmission = TRUE; + break; + + case 'V': /* DSN ENVID: set "original" envelope id */ + if (!xtextok(optarg)) + { + usrerr("Invalid syntax in -V flag"); + ExitStat = EX_USAGE; + } + else + CurEnv->e_envid = newstr(optarg); + break; + case 'X': /* traffic log file */ endpwent(); setgid(RealGid); @@ -634,6 +728,7 @@ main(argc, argv, envp) if (TrafficLogFile == NULL) { syserr("cannot open %s", optarg); + ExitStat = EX_CANTCREAT; break; } #ifdef HASSETVBUF @@ -706,11 +801,25 @@ main(argc, argv, envp) #endif vendor_pre_defaults(CurEnv); readcf(getcfname(), safecf, CurEnv); + ConfigFileRead = TRUE; vendor_post_defaults(CurEnv); /* avoid denial-of-service attacks */ resetlimits(); + if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) + { + /* drop privileges -- daemon mode done after socket/bind */ + drop_privileges(); + } + + /* + ** Find our real host name for future logging. + */ + + p = getauthinfo(STDIN_FILENO); + define('_', p, CurEnv); + /* suppress error printing if errors mailed back or whatever */ if (CurEnv->e_errormode != EM_PRINT) HoldErrs = TRUE; @@ -734,18 +843,6 @@ main(argc, argv, envp) } /* - ** Initialize name server if it is going to be used. - */ - -#if NAMED_BIND - if (UseNameServer && !bitset(RES_INIT, _res.options)) - res_init(); -# ifdef RES_NOALIASES - _res.options |= RES_NOALIASES; -# endif -#endif - - /* ** Do more command line checking -- these are things that ** have to modify the results of reading the config file. */ @@ -770,6 +867,10 @@ main(argc, argv, envp) CurEnv->e_bodytype = NULL; } + /* tweak default DSN notifications */ + if (DefaultNotify == 0) + DefaultNotify = QPINGONFAILURE|QPINGONDELAY; + /* Enforce use of local time (null string overrides this) */ if (TimeZoneSpec == NULL) unsetenv("TZ"); @@ -782,8 +883,22 @@ main(argc, argv, envp) /* check for sane configuration level */ if (ConfigLevel > MAXCONFIGLEVEL) { - syserr("Warning: .cf version level (%d) exceeds program functionality (%d)", - ConfigLevel, MAXCONFIGLEVEL); + syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)", + ConfigLevel, Version, MAXCONFIGLEVEL); + } + + /* need MCI cache to have persistence */ + if (HostStatDir != NULL && MaxMciCache == 0) + { + HostStatDir = NULL; + printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); + } + + /* need HostStatusDir in order to have SingleThreadDelivery */ + if (SingleThreadDelivery && HostStatDir == NULL) + { + SingleThreadDelivery = FALSE; + printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n"); } if (MeToo) @@ -791,13 +906,43 @@ main(argc, argv, envp) switch (OpMode) { + case MD_TEST: + /* don't have persistent host status in test mode */ + HostStatDir = NULL; + break; + + case MD_FGDAEMON: + run_in_foreground = TRUE; + OpMode = MD_DAEMON; + /* fall through ... */ + case MD_DAEMON: + /* check for permissions */ + if (RealUid != 0) + { +#ifdef LOG + if (LogLevel > 1) + syslog(LOG_ALERT, "user %d attempted to run daemon", + RealUid); +#endif + usrerr("Permission denied"); + exit(EX_USAGE); + } + vendor_daemon_setup(CurEnv); + /* remove things that don't make sense in daemon mode */ FullName = NULL; GrabTo = FALSE; /* arrange to restart on hangup signal */ +#ifdef LOG + if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') + syslog(LOG_WARNING, "daemon invoked without full pathname; kill -1 won't work"); +#endif setsignal(SIGHUP, sighup); + + /* workaround: can't seem to release the signal in the parent */ + releasesignal(SIGHUP); break; case MD_INITALIAS: @@ -806,7 +951,8 @@ main(argc, argv, envp) default: /* arrange to exit cleanly on hangup signal */ - setsignal(SIGHUP, intsig); + if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) + setsignal(SIGHUP, intsig); break; } @@ -903,16 +1049,21 @@ main(argc, argv, envp) setbitn(M_RUNASRCPT, ProgMailer->m_flags); if (FileMailer != NULL) setbitn(M_RUNASRCPT, FileMailer->m_flags); - - /* propogate some envariables into children */ - setuserenv("ISP", NULL); - setuserenv("SYSTYPE", NULL); + } + if (ConfigLevel < 7) + { + if (LocalMailer != NULL) + setbitn(M_VRFY250, LocalMailer->m_flags); + if (ProgMailer != NULL) + setbitn(M_VRFY250, ProgMailer->m_flags); + if (FileMailer != NULL) + setbitn(M_VRFY250, FileMailer->m_flags); } /* MIME Content-Types that cannot be transfer encoded */ setclass('n', "multipart/signed"); - /* MIME message/* subtypes that can be treated as messages */ + /* MIME message/xxx subtypes that can be treated as messages */ setclass('s', "rfc822"); /* MIME Content-Transfer-Encodings that can be encoded */ @@ -920,14 +1071,39 @@ main(argc, argv, envp) setclass('e', "8bit"); setclass('e', "binary"); +#ifdef USE_B_CLASS + /* MIME Content-Types that should be treated as binary */ + setclass('b', "image"); + setclass('b', "audio"); + setclass('b', "video"); + setclass('b', "application/octet-stream"); +#endif + /* operate in queue directory */ - if (OpMode != MD_TEST && chdir(QueueDir) < 0) + if (OpMode == MD_TEST) + /* nothing -- just avoid further if clauses */ ; + else if (QueueDir == NULL) + { + syserr("QueueDirectory (Q) option must be set"); + ExitStat = EX_CONFIG; + } + else if (chdir(QueueDir) < 0) { syserr("cannot chdir(%s)", QueueDir); - ExitStat = EX_SOFTWARE; + ExitStat = EX_CONFIG; } -# ifdef QUEUE + /* check host status directory for validity */ + if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE)) + { + /* cannot use this value */ + if (tTd(0, 2)) + printf("Cannot use HostStatusDirectory = %s: %s\n", + HostStatDir, errstring(errno)); + HostStatDir = NULL; + } + +# if QUEUE if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) { struct stat stbuf; @@ -964,8 +1140,8 @@ main(argc, argv, envp) { case MD_PRINT: /* print the queue */ -#ifdef QUEUE - dropenvelope(CurEnv); +#if QUEUE + dropenvelope(CurEnv, TRUE); printqueue(); endpwent(); setuid(RealUid); @@ -975,15 +1151,33 @@ main(argc, argv, envp) finis(); #endif /* QUEUE */ + case MD_HOSTSTAT: + mci_traverse_persistent(mci_print_persistent, NULL); + exit(EX_OK); + break; + + case MD_PURGESTAT: + mci_traverse_persistent(mci_purge_persistent, NULL); + exit(EX_OK); + break; + case MD_INITALIAS: /* initialize alias database */ initmaps(TRUE, CurEnv); endpwent(); setuid(RealUid); - exit(EX_OK); + exit(ExitStat); - case MD_DAEMON: case MD_SMTP: + nullserver = FALSE; + /* fall through... */ + + case MD_DAEMON: + /* reset DSN parameters */ + DefaultNotify = QPINGONFAILURE|QPINGONDELAY; + CurEnv->e_envid = NULL; + CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); + /* don't open alias database -- done in srvrsmtp */ break; @@ -995,6 +1189,8 @@ main(argc, argv, envp) if (tTd(0, 15)) { + extern void printrules __P((void)); + /* print configuration table (or at least part of it) */ if (tTd(0, 90)) printrules(); @@ -1050,7 +1246,7 @@ main(argc, argv, envp) } } -# ifdef QUEUE +# if QUEUE /* ** If collecting stuff from the queue, go start doing that. */ @@ -1058,7 +1254,7 @@ main(argc, argv, envp) if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) { (void) unsetenv("HOSTALIASES"); - runqueue(FALSE); + (void) runqueue(FALSE, Verbose); finis(); } # endif /* QUEUE */ @@ -1075,8 +1271,9 @@ main(argc, argv, envp) if (OpMode == MD_DAEMON || QueueIntvl != 0) { char dtype[200]; + extern bool getrequests __P((ENVELOPE *)); - if (!tTd(99, 100)) + if (!run_in_foreground && !tTd(99, 100)) { /* put us in background */ i = fork(); @@ -1107,19 +1304,22 @@ main(argc, argv, envp) xla_create_file(); #endif -# ifdef QUEUE +# if QUEUE if (queuemode) { - runqueue(TRUE); + (void) runqueue(TRUE, FALSE); if (OpMode != MD_DAEMON) for (;;) pause(); } # endif /* QUEUE */ - dropenvelope(CurEnv); + dropenvelope(CurEnv, TRUE); -#ifdef DAEMON - getrequests(); +#if DAEMON + nullserver = getrequests(CurEnv); + + /* drop privileges */ + drop_privileges(); /* at this point we are in a child: reset state */ (void) newenvelope(CurEnv, CurEnv); @@ -1129,26 +1329,45 @@ main(argc, argv, envp) */ p = getauthinfo(fileno(InChannel)); - define('_', p, CurEnv); - + define('_', p, &BlankEnvelope); #endif /* DAEMON */ } - -# ifdef SMTP + +# if SMTP /* ** If running SMTP protocol, start collecting and executing ** commands. This will never return. */ if (OpMode == MD_SMTP || OpMode == MD_DAEMON) - smtp(CurEnv); + { + char pbuf[20]; + extern void smtp __P((bool, ENVELOPE *)); + + /* + ** Save some macros for check_* rulesets. + */ + + define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope); + define(macid("{client_addr}", NULL), + newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope); + if (RealHostAddr.sa.sa_family == AF_INET) + snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port); + else + snprintf(pbuf, sizeof pbuf, "0"); + define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope); + + smtp(nullserver, CurEnv); + } # endif /* SMTP */ + clearenvelope(CurEnv, FALSE); if (OpMode == MD_VERIFY) { CurEnv->e_sendmode = SM_VERIFY; - CurEnv->e_errormode = EM_QUIET; + CurEnv->e_errormode = EM_PRINT; PostMasterCopy = NULL; + HoldErrs = FALSE; } else { @@ -1224,6 +1443,8 @@ main(argc, argv, envp) */ finis(); + /*NOTREACHED*/ + return -1; } @@ -1264,7 +1485,8 @@ finis() /* clean up temp files */ CurEnv->e_to = NULL; - dropenvelope(CurEnv); + if (CurEnv->e_id != NULL) + dropenvelope(CurEnv, TRUE); /* flush any cached connections */ mci_flush(TRUE, NULL); @@ -1307,6 +1529,11 @@ finis() void intsig() { +#ifdef LOG + if (LogLevel > 79) + syslog(LOG_DEBUG, "%s: interrupt", + CurEnv->e_id == NULL ? "[NOQUEUE]" : CurEnv->e_id); +#endif FileName = NULL; unlockqueue(CurEnv); #ifdef XLA @@ -1338,24 +1565,24 @@ intsig() struct metamac MetaMacros[] = { /* LHS pattern matching characters */ - '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE, - '=', MATCHCLASS, '~', MATCHNCLASS, + { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE }, + { '=', MATCHCLASS }, { '~', MATCHNCLASS }, /* these are RHS metasymbols */ - '#', CANONNET, '@', CANONHOST, ':', CANONUSER, - '>', CALLSUBR, + { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER }, + { '>', CALLSUBR }, /* the conditional operations */ - '?', CONDIF, '|', CONDELSE, '.', CONDFI, + { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI }, /* the hostname lookup characters */ - '[', HOSTBEGIN, ']', HOSTEND, - '(', LOOKUPBEGIN, ')', LOOKUPEND, + { '[', HOSTBEGIN }, { ']', HOSTEND }, + { '(', LOOKUPBEGIN }, { ')', LOOKUPEND }, /* miscellaneous control characters */ - '&', MACRODEXPAND, + { '&', MACRODEXPAND }, - '\0' + { '\0' } }; #define MACBINDING(name, mid) \ @@ -1420,13 +1647,18 @@ disconnect(droplev, e) int fd; if (tTd(52, 1)) - printf("disconnect: In %d Out %d, e=%x\n", - fileno(InChannel), fileno(OutChannel), e); + printf("disconnect: In %d Out %d, e=%lx\n", + fileno(InChannel), fileno(OutChannel), (u_long) e); if (tTd(52, 100)) { printf("don't\n"); return; } +#ifdef LOG + if (LogLevel > 93) + syslog(LOG_DEBUG, "%s: disconnect level %d", + e->e_id == NULL ? "[NOQUEUE]" : e->e_id, droplev); +#endif /* be sure we don't get nasty signals */ (void) setsignal(SIGINT, SIG_IGN); @@ -1576,7 +1808,7 @@ auth_warning(e, msg, va_alist) (void) snprintf(buf, sizeof buf, "%s: ", hostbuf); p = &buf[strlen(buf)]; VA_START(msg); - vsnprintf(p, sizeof buf - (p - buf), msg, ap); + vsnprintf(p, SPACELEFT(buf, p), msg, ap); VA_END; addheader("X-Authentication-Warning", buf, &e->e_header); #ifdef LOG @@ -1587,6 +1819,31 @@ auth_warning(e, msg, va_alist) } } /* +** GETEXTENV -- get from external environment +** +** Parameters: +** envar -- the name of the variable to retrieve +** +** Returns: +** The value, if any. +*/ + +char * +getextenv(envar) + const char *envar; +{ + char **envp; + int l; + + l = strlen(envar); + for (envp = ExternalEnviron; *envp != NULL; envp++) + { + if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') + return &(*envp)[l + 1]; + } + return NULL; +} +/* ** SETUSERENV -- set an environment in the propogated environment ** ** Parameters: @@ -1611,7 +1868,7 @@ setuserenv(envar, value) if (value == NULL) { - value = getenv(envar); + value = getextenv(envar); if (value == NULL) return; } @@ -1650,6 +1907,7 @@ dumpstate(when) { #ifdef LOG register char *j = macvalue('j', CurEnv); + int rs; syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---", when, @@ -1664,16 +1922,18 @@ dumpstate(when) printopenfds(TRUE); syslog(LOG_DEBUG, "--- connection cache: ---"); mci_dump_all(TRUE); - if (RewriteRules[89] != NULL) + rs = strtorwset("debug_dumpstate", NULL, ST_FIND); + if (rs > 0) { int stat; register char **pvp; char *pv[MAXATOM + 1]; pv[0] = NULL; - stat = rewrite(pv, 89, 0, CurEnv); - syslog(LOG_DEBUG, "--- ruleset 89 returns stat %d, pv: ---", - stat); + stat = rewrite(pv, rs, 0, CurEnv); + syslog(LOG_DEBUG, + "--- ruleset debug_dumpstate returns stat %d, pv: ---", + stat); for (pvp = pv; *pvp != NULL; pvp++) syslog(LOG_DEBUG, "%s", *pvp); } @@ -1692,13 +1952,28 @@ sigusr1() void sighup() { + if (SaveArgv[0][0] != '/') + { +#ifdef LOG + if (LogLevel > 3) + syslog(LOG_INFO, "could not restart: need full path"); +#endif + exit(EX_OSFILE); + } #ifdef LOG if (LogLevel > 3) syslog(LOG_INFO, "restarting %s on signal", SaveArgv[0]); #endif releasesignal(SIGHUP); - (void) setgid(RealGid); - (void) setuid(RealUid); + if (setgid(RealGid) < 0 || setuid(RealUid) < 0) + { +#ifdef LOG + if (LogLevel > 0) + syslog(LOG_ALERT, "could not set[ug]id(%d, %d): %m", + RealUid, RealGid); +#endif + exit(EX_OSERR); + } execv(SaveArgv[0], (ARGV_T) SaveArgv); #ifdef LOG if (LogLevel > 0) @@ -1707,6 +1982,31 @@ sighup() exit(EX_OSFILE); } /* +** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option +** +** Parameters: +** none. +** +** Returns: +** none. +*/ + +void +drop_privileges() +{ +#ifdef NGROUPS_MAX + /* reset group permissions; these can be set later */ + GIDSET_T emptygidset[NGROUPS_MAX]; + + emptygidset[0] = RunAsGid == 0 ? geteuid() : RunAsGid; + (void) setgroups(1, emptygidset); +#endif + if (RunAsGid != 0) + (void) setgid(RunAsGid); + if (RunAsUid != 0) + (void) setuid(RunAsUid); +} +/* ** TESTMODELINE -- process a test mode input line ** ** Parameters: @@ -1741,6 +2041,7 @@ testmodeline(line, e) extern char *crackaddr __P((char *)); extern void dump_class __P((STAB *, int)); extern void translate_dollars __P((char *)); + extern void help __P((char *)); switch (line[0]) { @@ -1807,7 +2108,10 @@ testmodeline(line, e) case 'S': /* dump rule set */ rs = strtorwset(&line[2], NULL, ST_FIND); if (rs < 0) + { + printf("Undefined ruleset %s\n", &line[2]); return; + } rw = RewriteRules[rs]; if (rw == NULL) return; @@ -1829,7 +2133,7 @@ testmodeline(line, e) putchar(' '); } putchar('\n'); - } while (rw = rw->r_next); + } while ((rw = rw->r_next) != NULL); break; case 'M': @@ -1928,7 +2232,6 @@ testmodeline(line, e) } else if (strcasecmp(&line[1], "canon") == 0) { - auto int rcode = EX_OK; char host[MAXHOSTNAMELEN]; if (*p == '\0') @@ -1942,9 +2245,8 @@ testmodeline(line, e) return; } strcpy(host, p); - getcanonname(host, sizeof(host), HasWildcardMX, &rcode); - printf("getcanonname(%s) returns %s (%d)\n", - p, host, rcode); + (void) getcanonname(host, sizeof(host), HasWildcardMX); + printf("getcanonname(%s) returns %s\n", p, host); } else if (strcasecmp(&line[1], "map") == 0) { @@ -2008,6 +2310,7 @@ testmodeline(line, e) p = remotename(q, m, tryflags, &rcode, CurEnv); printf("Rcode = %d, addr = %s\n", rcode, p == NULL ? "<NULL>" : p); + e->e_to = NULL; } else if (strcasecmp(&line[1], "tryflags") == 0) { @@ -2063,6 +2366,7 @@ testmodeline(line, e) else printf("mailer %s, user %s\n", a.q_mailer->m_name, a.q_user); + e->e_to = NULL; } else { @@ -2100,7 +2404,10 @@ testmodeline(line, e) int rs = strtorwset(p, NULL, ST_FIND); if (rs < 0) + { + printf("Undefined ruleset %s\n", p); break; + } stat = rewrite(pvp, rs, 0, e); if (stat != EX_OK) printf("== Ruleset %s (%d) status %d\n", diff --git a/usr.sbin/sendmail/src/makesendmail b/usr.sbin/sendmail/src/makesendmail index df202e9163e..838d8919971 100644 --- a/usr.sbin/sendmail/src/makesendmail +++ b/usr.sbin/sendmail/src/makesendmail @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (c) 1993 Eric P. Allman +# Copyright (c) 1993, 1996 Eric P. Allman # Copyright (c) 1993 The Regents of the University of California. # All rights reserved. # @@ -32,7 +32,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)makesendmail 8.29 (Berkeley) 8/1/95 +# @(#)makesendmail 8.42 (Berkeley) 11/10/96 # # @@ -51,12 +51,12 @@ fi # # Do heuristic guesses !ONLY! for machines that do not have uname # -if [ -d /LocalApps -a ! -f /bin/uname -a ! -f /usr/bin/uname ] +if [ -d /NextApps -a ! -f /bin/uname -a ! -f /usr/bin/uname ] then # probably a NeXT box - arch=NeXT - os=Mach - rel=`strings /mach | grep 'Mach.*:' | sed -e 's/.* Mach //' -e 's/:.*//'` + arch=`hostinfo | sed -n 's/.*Processor type: \([^ ]*\).*/\1/p'` + os=NeXT + rel=`hostinfo | sed -n 's/.*NeXT Mach \([0-9\.]*\).*/\1/p'` elif [ -f /usr/sony/bin/machine -a -f /etc/osversion ] then # probably a Sony NEWS 4.x @@ -85,8 +85,8 @@ fi if [ ! "$arch" -a ! "$os" -a ! "$rel" ] then arch=`uname -m | sed -e 's/ //g'` - os=`uname -s | sed 's/\//-/g'` - rel=`uname -r` + os=`uname -s | sed -e 's/\//-/g' -e 's/ //g'` + rel=`uname -r | sed -e 's/(/-/g' -e 's/)//g'` fi # @@ -104,20 +104,44 @@ in sun4*) arch=sun4;; 9000/*) arch=`echo $arch | sed -e 's/9000.//' -e 's/..$/xx/'`;; + + DS/907000) arch=ds90;; esac # tweak operating system type and release +node=`uname -n | sed -e 's/\//-/g' -e 's/ //g'` +if [ "$os" = "$node" -a "$arch" = "i386" -a "$rel" = 3.2 -a "`uname -v`" = 2 ] +then + # old versions of SCO UNIX set uname -s the same as uname -n + os=SCO_SV +fi + case $os in DYNIX-ptx) os=PTX;; Paragon*) os=Paragon;; HP-UX) rel=`echo $rel | sed -e 's/^[^.]*\.0*//'`;; - AIX) rel=`uname -v`;; + AIX) rel=`uname -v` + if [ "$rel" = "2" ] + then + arch="" + fi;; BSD-386) os=BSD-OS;; + SCO_SV) os=SCO; rel=`uname -X | sed -n 's/Release = 3.2v//p'`;; + UNIX_System_V) if [ "$arch" = "ds90" ] + then + os="UXPDS" + rel=`uname -v | sed -e 's/\(V.*\)L.*/\1/'` + fi;; esac # get "base part" of operating system release +rroot=`echo $rel | sed -e 's/\.[^.]*$//'` rbase=`echo $rel | sed -e 's/\..*//'` +if [ "$rroot" = "$rbase" ] +then + rroot=$rel +fi # heuristic tweaks to clean up names -- PLEASE LIMIT THESE! if [ "$os" = "unix" ] @@ -164,11 +188,13 @@ else sfx=".${SENDMAIL_SUFFIX}" fi -echo "Configuration: os=$os, rel=$rel, rbase=$rbase, arch=$arch, sfx=$sfx" +echo "Configuration: os=$os, rel=$rel, rbase=$rbase, rroot=$rroot, arch=$arch, sfx=$sfx" # now try to find a reasonable object directory if [ -r obj.$os.$rel.$arch$sfx ]; then obj=obj.$os.$rel.$arch$sfx +elif [ -r obj.$os.$rroot.$arch$sfx ]; then + obj=obj.$os.$rroot.$arch$sfx elif [ -r obj.$os.$rbase.x.$arch$sfx ]; then obj=obj.$os.$rbase.x.$arch$sfx elif [ -r obj.$os.$rel$sfx ]; then @@ -196,6 +222,10 @@ else makefile=Makefile.$os.$rel.$arch$sfx elif [ -r Makefiles/Makefile.$os.$rel.$arch ]; then makefile=Makefile.$os.$rel.$arch + elif [ -r Makefiles/Makefile.$os.$rroot.$arch$sfx ]; then + makefile=Makefile.$os.$rroot.$arch$sfx + elif [ -r Makefiles/Makefile.$os.$rroot.$arch ]; then + makefile=Makefile.$os.$rroot.$arch elif [ -r Makefiles/Makefile.$os.$rbase.x.$arch$sfx ]; then makefile=Makefile.$os.$rbase.x.$arch$sfx elif [ -r Makefiles/Makefile.$os.$rbase.x.$arch ]; then @@ -204,6 +234,10 @@ else makefile=Makefile.$os.$rel$sfx elif [ -r Makefiles/Makefile.$os.$rel ]; then makefile=Makefile.$os.$rel + elif [ -r Makefiles/Makefile.$os.$rroot$sfx ]; then + makefile=Makefile.$os.$rroot$sfx + elif [ -r Makefiles/Makefile.$os.$rroot ]; then + makefile=Makefile.$os.$rroot elif [ -r Makefiles/Makefile.$os.$rbase.x$sfx ]; then makefile=Makefile.$os.$rbase.x$sfx elif [ -r Makefiles/Makefile.$os.$rbase.x ]; then @@ -216,6 +250,10 @@ else makefile=Makefile.$rel.$arch$sfx elif [ -r Makefiles/Makefile.$rel.$arch ]; then makefile=Makefile.$rel.$arch + elif [ -r Makefiles/Makefile.$rroot.$arch$sfx ]; then + makefile=Makefile.$rroot.$arch$sfx + elif [ -r Makefiles/Makefile.$rroot.$arch ]; then + makefile=Makefile.$rroot.$arch elif [ -r Makefiles/Makefile.$rbase.x.$arch$sfx ]; then makefile=Makefile.$rbase.x.$arch$sfx elif [ -r Makefiles/Makefile.$rbase.x.$arch ]; then diff --git a/usr.sbin/sendmail/src/map.c b/usr.sbin/sendmail/src/map.c index 13d38ce97be..1b0f08603dd 100644 --- a/usr.sbin/sendmail/src/map.c +++ b/usr.sbin/sendmail/src/map.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1992, 1995 Eric P. Allman. + * Copyright (c) 1992, 1995, 1996 Eric P. Allman. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,25 +33,29 @@ */ #ifndef lint -static char sccsid[] = "@(#)map.c 8.108.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)map.c 8.146 (Berkeley) 11/24/96"; #endif /* not lint */ #include "sendmail.h" #ifdef NDBM # include <ndbm.h> -#endif -#ifdef NEWDB # ifdef R_FIRST ERROR README: You are running the Berkeley DB version of ndbm.h. See ERROR README: the READ_ME file about tweaking Berkeley DB so it can - ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile. + ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile + ERROR README: and use -DNEWDB instead. # endif +#endif +#ifdef NEWDB # include <db.h> #endif #ifdef NIS struct dom_binding; /* forward reference needed on IRIX */ # include <rpcsvc/ypclnt.h> +# ifdef NDBM +# define NDBM_YP_COMPAT /* create YP-compatible NDBM files */ +# endif #endif /* @@ -96,12 +100,14 @@ static char sccsid[] = "@(#)map.c 8.108.1.2 (Berkeley) 9/16/96"; #define DBMMODE 0644 -#define EX_NOTFOUND EX_NOHOST +#ifndef EX_NOTFOUND +# define EX_NOTFOUND EX_NOHOST +#endif extern bool aliaswait __P((MAP *, char *, int)); extern bool extract_canonname __P((char *, char *, char[], int)); -#if defined(O_EXLOCK) && HASFLOCK +#if O_EXLOCK && HASFLOCK # define LOCK_ON_OPEN 1 /* we can open/create a locked file */ #else # define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */ @@ -204,6 +210,11 @@ map_parseargs(map, ap) } } break; + + case 't': + map->map_mflags |= MF_NODEFER; + break; + #ifdef RESERVED_FOR_SUN case 'd': map->map_mflags |= MF_DOMAIN_WIDE; @@ -632,10 +643,10 @@ getcanonname(host, hbsize, trymx) printf("getcanonname(%s), failed, stat=%d\n", host, stat); #if NAMED_BIND - if (stat == EX_NOHOST && !got_tempfail) - h_errno = HOST_NOT_FOUND; - else + if (got_tempfail) h_errno = TRY_AGAIN; + else + h_errno = HOST_NOT_FOUND; #endif return FALSE; @@ -679,6 +690,8 @@ extract_canonname(name, line, cbuf, cbuflen) p = get_column(line, i, '\0', nbuf, sizeof nbuf); if (p == NULL) break; + if (*p == '\0') + continue; if (cbuf[0] == '\0' || (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL)) { @@ -724,6 +737,7 @@ ndbm_map_open(map, mode) if (tTd(38, 2)) printf("ndbm_map_open(%s, %s, %d)\n", map->map_mname, map->map_file, mode); + map->map_lockfd = -1; #if LOCK_ON_OPEN if (mode == O_RDONLY) @@ -733,7 +747,7 @@ ndbm_map_open(map, mode) #else if (mode == O_RDWR) { -# ifdef NOFTRUNCATE +# if NOFTRUNCATE /* ** Warning: race condition. Try to lock the file as ** quickly as possible after opening it. @@ -768,15 +782,15 @@ ndbm_map_open(map, mode) if (!lockfile(dirfd, map->map_file, ".dir", LOCK_EX)) syserr("ndbm_map_open: cannot lock %s.dir", map->map_file); - if (ftruncate(dirfd, 0) < 0) + if (ftruncate(dirfd, (off_t) 0) < 0) syserr("ndbm_map_open: cannot truncate %s.dir", map->map_file); - if (ftruncate(pagfd, 0) < 0) + if (ftruncate(pagfd, (off_t) 0) < 0) syserr("ndbm_map_open: cannot truncate %s.pag", map->map_file); - /* we can safely unlock because others will wait for @:@ */ - close(dirfd); + /* have to save the lock for the duration (bletch) */ + map->map_lockfd = dirfd; close(pagfd); # endif } @@ -807,12 +821,7 @@ ndbm_map_open(map, mode) } else { - /* exclusive lock for duration of rebuild */ -#if !LOCK_ON_OPEN - if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) && - lockfile(fd, map->map_file, ".dir", LOCK_EX)) -#endif - map->map_mflags |= MF_LOCKED; + map->map_mflags |= MF_LOCKED; } if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0) map->map_mtime = st.st_mtime; @@ -845,7 +854,8 @@ ndbm_map_lookup(map, name, av, statp) { if (key.dsize > sizeof keybuf - 1) key.dsize = sizeof keybuf - 1; - bcopy(key.dptr, keybuf, key.dsize + 1); + bcopy(key.dptr, keybuf, key.dsize); + keybuf[key.dsize] = '\0'; makelower(keybuf); key.dptr = keybuf; } @@ -890,6 +900,7 @@ ndbm_map_store(map, lhs, rhs) datum key; datum data; int stat; + char keybuf[MAXNAME + 1]; if (tTd(38, 12)) printf("ndbm_map_store(%s, %s, %s)\n", @@ -897,6 +908,15 @@ ndbm_map_store(map, lhs, rhs) key.dsize = strlen(lhs); key.dptr = lhs; + if (!bitset(MF_NOFOLDCASE, map->map_mflags)) + { + if (key.dsize > sizeof keybuf - 1) + key.dsize = sizeof keybuf - 1; + bcopy(key.dptr, keybuf, key.dsize); + keybuf[key.dsize] = '\0'; + makelower(keybuf); + key.dptr = keybuf; + } data.dsize = strlen(rhs); data.dptr = rhs; @@ -920,7 +940,7 @@ ndbm_map_store(map, lhs, rhs) datum old; old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat); - if (old.dptr != NULL && *old.dptr != '\0') + if (old.dptr != NULL && *(char *) old.dptr != '\0') { old.dsize = strlen(old.dptr); if (data.dsize + old.dsize + 2 > bufsiz) @@ -959,7 +979,7 @@ ndbm_map_close(map) if (bitset(MF_WRITABLE, map->map_mflags)) { -#ifdef NIS +#ifdef NDBM_YP_COMPAT bool inclnull; char buf[200]; @@ -968,11 +988,17 @@ ndbm_map_close(map) if (strstr(map->map_file, "/yp/") != NULL) { + long save_mflags = map->map_mflags; + + map->map_mflags |= MF_NOFOLDCASE; + (void) snprintf(buf, sizeof buf, "%010ld", curtime()); ndbm_map_store(map, "YP_LAST_MODIFIED", buf); (void) gethostname(buf, sizeof buf); ndbm_map_store(map, "YP_MASTER_NAME", buf); + + map->map_mflags = save_mflags; } if (inclnull) @@ -983,6 +1009,12 @@ ndbm_map_close(map) ndbm_map_store(map, "@", "@"); } dbm_close((DBM *) map->map_db1); + + /* release lock (if needed) */ +#if !LOCK_ON_OPEN + if (map->map_lockfd >= 0) + (void) close(map->map_lockfd); +#endif } #endif @@ -1004,15 +1036,30 @@ ndbm_map_close(map) ** be pokey about it. That's hard to do. */ +extern bool db_map_open __P((MAP *, int, DBTYPE, const void *)); + +/* these should be K line arguments */ +#ifndef DB_CACHE_SIZE +# define DB_CACHE_SIZE (1024 * 1024) /* database memory cache size */ +#endif +#ifndef DB_HASH_NELEM +# define DB_HASH_NELEM 4096 /* (starting) size of hash table */ +#endif + bool bt_map_open(map, mode) MAP *map; int mode; { + BTREEINFO btinfo; + if (tTd(38, 2)) printf("bt_map_open(%s, %s, %d)\n", map->map_mname, map->map_file, mode); - return db_map_open(map, mode, DB_BTREE); + + bzero(&btinfo, sizeof btinfo); + btinfo.cachesize = DB_CACHE_SIZE; + return db_map_open(map, mode, DB_BTREE, &btinfo); } bool @@ -1020,17 +1067,24 @@ hash_map_open(map, mode) MAP *map; int mode; { + HASHINFO hinfo; + if (tTd(38, 2)) printf("hash_map_open(%s, %s, %d)\n", map->map_mname, map->map_file, mode); - return db_map_open(map, mode, DB_HASH); + + bzero(&hinfo, sizeof hinfo); + hinfo.nelem = DB_HASH_NELEM; + hinfo.cachesize = DB_CACHE_SIZE; + return db_map_open(map, mode, DB_HASH, &hinfo); } bool -db_map_open(map, mode, dbtype) +db_map_open(map, mode, dbtype, openinfo) MAP *map; int mode; DBTYPE dbtype; + const void *openinfo; { DB *db; int i; @@ -1044,6 +1098,7 @@ db_map_open(map, mode, dbtype) i = strlen(buf); if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) (void) strcat(buf, ".db"); + map->map_lockfd = -1; omode = mode; @@ -1068,8 +1123,8 @@ db_map_open(map, mode, dbtype) if (fd < 0) { - syserr("db_map_open: cannot pre-open database %s", - buf); + if (!bitset(MF_OPTIONAL, map->map_mflags)) + syserr("db_map_open: cannot pre-open database %s", buf); close(fd); return FALSE; } @@ -1080,12 +1135,14 @@ db_map_open(map, mode, dbtype) omode |= O_TRUNC; #endif - db = dbopen(buf, omode, DBMMODE, dbtype, NULL); + db = dbopen(buf, omode, DBMMODE, dbtype, openinfo); saveerrno = errno; #if !LOCK_ON_OPEN - /* we can safely unlock now because others will wait for @:@ */ - close(fd); + if (mode == O_RDWR) + map->map_lockfd = fd; + else + (void) close(fd); #endif if (db == NULL) @@ -1098,21 +1155,15 @@ db_map_open(map, mode, dbtype) syserr("Cannot open DB database %s", map->map_file); return FALSE; } + + if (mode == O_RDWR) + map->map_mflags |= MF_LOCKED; #if !OLD_NEWDB fd = db->fd(db); # if LOCK_ON_OPEN - if (fd >= 0) + if (fd >= 0 && mode == O_RDONLY) { - if (mode == O_RDONLY) - (void) lockfile(fd, map->map_file, ".db", LOCK_UN); - else - map->map_mflags |= MF_LOCKED; - } -# else - if (mode == O_RDWR && fd >= 0) - { - if (lockfile(fd, map->map_file, ".db", LOCK_EX)) - map->map_mflags |= MF_LOCKED; + (void) lockfile(fd, map->map_file, ".db", LOCK_UN); } # endif #endif @@ -1162,7 +1213,8 @@ db_map_lookup(map, name, av, statp) if (key.size > sizeof keybuf - 1) key.size = sizeof keybuf - 1; key.data = keybuf; - bcopy(name, keybuf, key.size + 1); + bcopy(name, keybuf, key.size); + keybuf[key.size] = '\0'; if (!bitset(MF_NOFOLDCASE, map->map_mflags)) makelower(keybuf); #if !OLD_NEWDB @@ -1217,6 +1269,7 @@ db_map_store(map, lhs, rhs) DBT key; DBT data; register DB *db = map->map_db2; + char keybuf[MAXNAME + 1]; if (tTd(38, 12)) printf("db_map_store(%s, %s, %s)\n", @@ -1224,6 +1277,15 @@ db_map_store(map, lhs, rhs) key.size = strlen(lhs); key.data = lhs; + if (!bitset(MF_NOFOLDCASE, map->map_mflags)) + { + if (key.size > sizeof keybuf - 1) + key.size = sizeof keybuf - 1; + bcopy(key.data, keybuf, key.size); + keybuf[key.size] = '\0'; + makelower(keybuf); + key.data = keybuf; + } data.size = strlen(rhs); data.data = rhs; @@ -1261,7 +1323,8 @@ db_map_store(map, lhs, rhs) data.size = data.size + old.size + 1; data.data = buf; if (tTd(38, 9)) - printf("db_map_store append=%s\n", data.data); + printf("db_map_store append=%s\n", + (char *) data.data); } } stat = db->put(db, &key, &data, 0); @@ -1282,7 +1345,7 @@ db_map_close(map) register DB *db = map->map_db2; if (tTd(38, 9)) - printf("db_map_close(%s, %s, %x)\n", + printf("db_map_close(%s, %s, %lx)\n", map->map_mname, map->map_file, map->map_mflags); if (bitset(MF_WRITABLE, map->map_mflags)) @@ -1293,6 +1356,11 @@ db_map_close(map) if (db->close(db) != 0) syserr("readaliases: db close failure"); + +#if !LOCK_ON_OPEN + if (map->map_lockfd >= 0) + (void) close(map->map_lockfd); +#endif } #endif @@ -1356,7 +1424,7 @@ nis_map_open(map, mode) if (yperr != 0) { if (!bitset(MF_OPTIONAL, map->map_mflags)) - syserr("421 NIS map %s specified, but NIS not running\n", + syserr("421 NIS map %s specified, but NIS not running", map->map_file); return FALSE; } @@ -1418,7 +1486,8 @@ nis_map_lookup(map, name, av, statp) buflen = strlen(name); if (buflen > sizeof keybuf - 1) buflen = sizeof keybuf - 1; - bcopy(name, keybuf, buflen + 1); + bcopy(name, keybuf, buflen); + keybuf[buflen] = '\0'; if (!bitset(MF_NOFOLDCASE, map->map_mflags)) makelower(keybuf); yperr = YPERR_KEY; @@ -1559,12 +1628,9 @@ nisplus_map_open(map, mode) MAP *map; int mode; { - register char *p; - char qbuf[MAXLINE + NIS_MAXNAMELEN]; nis_result *res = NULL; - u_int objs_len; - nis_object *obj_ptr; int retry_cnt, max_col, i; + char qbuf[MAXLINE + NIS_MAXNAMELEN]; if (tTd(38, 2)) printf("nisplus_map_open(%s, %s, %d)\n", @@ -1727,7 +1793,8 @@ nisplus_map_lookup(map, name, av, statp) buflen = strlen(name); if (buflen > sizeof search_key - 1) buflen = sizeof search_key - 1; - bcopy(name, search_key, buflen + 1); + bcopy(name, search_key, buflen); + search_key[buflen] = '\0'; if (!bitset(MF_NOFOLDCASE, map->map_mflags)) makelower(search_key); @@ -1851,7 +1918,6 @@ nisplus_getcanonname(name, hbsize, statp) if (result->status == NIS_SUCCESS) { int count; - char *str; char *domain; if ((count = NIS_RES_NUMOBJ(result)) != 1) @@ -1865,7 +1931,8 @@ nisplus_getcanonname(name, hbsize, statp) /* ignore second entry */ if (tTd(38, 20)) - printf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n", name); + printf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n", + name, count); } if (tTd(38, 20)) @@ -1934,6 +2001,559 @@ nisplus_default_domain() #endif /* NISPLUS */ /* +** LDAP Modules +** +** Contributed by Booker C. Bense <bbense@networking.stanford.edu>. +** Get your support from him. +*/ + +#ifdef LDAPMAP + +# undef NEEDGETOPT /* used for something else in LDAP */ + +# include <lber.h> +# include <ldap.h> +# include "ldap_map.h" + +/* +** LDAP_MAP_OPEN -- open LDAP map +** +** Since LDAP is TCP-based there is not much we can or should do +** here. It might be a good idea to attempt an open/close here. +*/ + +bool +ldap_map_open(map, mode) + MAP *map; + int mode; +{ + if (tTd(38, 2)) + printf("ldap_map_open(%s, %d)\n", map->map_mname, mode); + + if (mode != O_RDONLY) + { + /* issue a pseudo-error message */ +#ifdef ENOSYS + errno = ENOSYS; +#else +# ifdef EFTYPE + errno = EFTYPE; +# else + errno = ENXIO; +# endif +#endif + return FALSE; + } + return TRUE; +} + + +/* +** LDAP_MAP_START -- actually open LDAP map +** +** Caching should be investigated. +*/ + +bool +ldap_map_start(map) + MAP *map; +{ + LDAP_MAP_STRUCT *lmap; + LDAP *ld; + + if (tTd(38, 2)) + printf("ldap_map_start(%s)\n", map->map_mname); + + lmap = (LDAP_MAP_STRUCT *) map->map_db1; + + if (tTd(38,9)) + printf("ldap_open(%s, %d)\n", lmap->ldaphost, lmap->ldapport); + + if ((ld = ldap_open(lmap->ldaphost,lmap->ldapport)) == NULL) + { + if (!bitset(MF_OPTIONAL, map->map_mflags)) + { + syserr("ldapopen failed to %s in map %s", + lmap->ldaphost, map->map_mname); + } + return FALSE; + } + + ld->ld_deref = lmap->deref; + ld->ld_timelimit = lmap->timelimit; + ld->ld_sizelimit = lmap->sizelimit; + ld->ld_options = lmap->ldap_options; + + if (ldap_bind_s(ld, lmap->binddn,lmap->passwd,lmap->method) != LDAP_SUCCESS) + { + if (!bitset(MF_OPTIONAL, map->map_mflags)) + { + syserr("421 Cannot bind to map %s in ldap server %s", + map->map_mname, lmap->ldaphost); + } + } + else + { + /* We need to cast ld into the map structure */ + lmap->ld = ld; + return TRUE; + } + + return FALSE; +} + + +/* +** LDAP_MAP_CLOSE -- close ldap map +*/ + +void +ldap_map_close(map) + MAP *map; +{ + LDAP_MAP_STRUCT *lmap ; + lmap = (LDAP_MAP_STRUCT *) map->map_db1; + if (lmap->ld != NULL) + ldap_unbind(lmap->ld); +} + + +#ifdef SUNET_ID +/* +** SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form +** This only makes sense at Stanford University. +*/ + +char * +sunet_id_hash(str) + char *str; +{ + char *p, *p_last; + + p = str; + p_last = p; + while (*p != '\0') + { + if (islower(*p) || isdigit(*p)) + { + *p_last = *p; + p_last++; + } + else if (isupper(*p)) + { + *p_last = tolower(*p); + p_last++; + } + ++p; + } + if (*p_last != '\0') + *p_last = '\0'; + return (str); +} + + + +#endif /* SUNET_ID */ +/* +** LDAP_MAP_LOOKUP -- look up a datum in a LDAP map +*/ + +char * +ldap_map_lookup(map, name, av, statp) + MAP *map; + char *name; + char **av; + int *statp; +{ + LDAP_MAP_STRUCT *lmap = NULL; + LDAPMessage *entry; + char *vp; + auto int vsize; + char keybuf[MAXNAME + 1]; + char filter[LDAP_MAP_MAX_FILTER + 1]; + char **attr_values = NULL; + char *result; + int name_len; + + if (tTd(38, 20)) + printf("ldap_map_lookup(%s, %s)\n", map->map_mname, name); + + /* actually open the map */ + if (!ldap_map_start(map)) + { + result = NULL; + *statp = EX_TEMPFAIL; + goto quick_exit; + } + + /* Get ldap struct pointer from map */ + lmap = (LDAP_MAP_STRUCT *) map->map_db1; + + name_len = strlen(name); + if (name_len > MAXNAME) + name_len = MAXNAME; + strncpy(keybuf, name, name_len); + keybuf[name_len] = '\0'; + + if (!bitset(MF_NOFOLDCASE, map->map_mflags)) +#ifdef SUNET_ID + sunet_id_hash(keybuf); +#else + makelower(keybuf); +#endif /*SUNET_ID */ + + /* sprintf keybuf into filter */ + snprintf(filter, sizeof filter, lmap->filter, keybuf); + + if (ldap_search_st(lmap->ld, lmap->base,lmap->scope,filter, + &(lmap->attr), lmap->attrsonly, &(lmap->timeout), + &(lmap->res)) != LDAP_SUCCESS) + { + /* try close/opening map */ + ldap_map_close(map); + if (!ldap_map_start(map)) + { + result = NULL; + *statp = EX_TEMPFAIL; + goto quick_exit; + } + if (ldap_search_st(lmap->ld, lmap->base, lmap->scope, filter, + &(lmap->attr), lmap->attrsonly, + &(lmap->timeout), &(lmap->res)) + != LDAP_SUCCESS) + { + if (!bitset(MF_OPTIONAL, map->map_mflags)) + { + syserr("Error in ldap_search_st using %s in map %s", + filter, map->map_mname); + } + result = NULL; + *statp = EX_UNAVAILABLE; + goto quick_exit; + } + } + + entry = ldap_first_entry(lmap->ld,lmap->res); + if (entry == NULL) + { + result = NULL; + *statp = EX_NOTFOUND; + goto quick_exit; + } + + /* Need to build the args for map_rewrite here */ + attr_values = ldap_get_values(lmap->ld,entry,lmap->attr); + if (attr_values == NULL) + { + /* bad things happened */ + result = NULL; + *statp = EX_NOTFOUND; + goto quick_exit; + } + + *statp = EX_OK; + + /* If there is more that one use the first */ + vp = attr_values[0]; + vsize = strlen(vp); + +# ifdef LOG + if (LogLevel > 9) + syslog(LOG_INFO, "%s: ldap %.100s => %s", + CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, + name, vp); +# endif + if (bitset(MF_MATCHONLY, map->map_mflags)) + result = map_rewrite(map, name, strlen(name), NULL); + else + result = map_rewrite(map, vp, vsize, av); + + quick_exit: + if (attr_values != NULL) + ldap_value_free(attr_values); + if (lmap != NULL) + ldap_msgfree(lmap->res); + ldap_map_close(map); + return result ; +} + + +/* +** LDAP_MAP_DEQUOTE - helper routine for ldap_map_parseargs +*/ + +char * +ldap_map_dequote(str) + char *str; +{ + char *p; + char *start; + p = str; + + if (*p == '"') + { + start = ++p; + /* Should probably swallow initial whitespace here */ + } + else + { + return(str); + } + while (*p != '"' && *p != '\0') + { + p++; + } + if (*p != '\0') + *p = '\0'; + return start; +} + +/* +** LDAP_MAP_PARSEARGS -- parse ldap map definition args. +*/ + +bool +ldap_map_parseargs(map,args) + MAP *map; + char *args; +{ + register char *p = args; + register int done; + LDAP_MAP_STRUCT *lmap; + + /* We need to alloc an LDAP_MAP_STRUCT struct */ + lmap = (LDAP_MAP_STRUCT *) xalloc(sizeof(LDAP_MAP_STRUCT)); + + /* Set default int's here , default strings below */ + lmap->ldapport = DEFAULT_LDAP_MAP_PORT; + lmap->deref = DEFAULT_LDAP_MAP_DEREF; + lmap->timelimit = DEFAULT_LDAP_MAP_TIMELIMIT; + lmap->sizelimit = DEFAULT_LDAP_MAP_SIZELIMIT; + lmap->ldap_options = DEFAULT_LDAP_MAP_LDAP_OPTIONS; + lmap->method = DEFAULT_LDAP_MAP_METHOD; + lmap->scope = DEFAULT_LDAP_MAP_SCOPE; + lmap->attrsonly = DEFAULT_LDAP_MAP_ATTRSONLY; + lmap->timeout.tv_sec = DEFAULT_LDAP_MAP_TIMELIMIT; + lmap->timeout.tv_usec = 0; + + /* Default char ptrs to NULL */ + lmap->binddn = NULL; + lmap->passwd = NULL; + lmap->base = NULL; + lmap->ldaphost = NULL; + map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; + for (;;) + { + while (isascii(*p) && isspace(*p)) + p++; + if (*p != '-') + break; + switch (*++p) + { + case 'N': + map->map_mflags |= MF_INCLNULL; + map->map_mflags &= ~MF_TRY0NULL; + break; + + case 'O': + map->map_mflags &= ~MF_TRY1NULL; + break; + + case 'o': + map->map_mflags |= MF_OPTIONAL; + break; + + case 'f': + map->map_mflags |= MF_NOFOLDCASE; + break; + + case 'm': + map->map_mflags |= MF_MATCHONLY; + break; + + case 'A': + map->map_mflags |= MF_APPEND; + break; + + case 'q': + map->map_mflags |= MF_KEEPQUOTES; + break; + + case 't': + map->map_mflags |= MF_NODEFER; + break; + + case 'a': + map->map_app = ++p; + break; + + /* Start of ldap_map specific args */ + case 'k': /* search field */ + while (isascii(*++p) && isspace(*p)) + continue; + lmap->filter = p; + break; + + case 'v': /* attr to return */ + while (isascii(*++p) && isspace(*p)) + continue; + lmap->attr = p; + break; + + /* args stolen from ldapsearch.c */ + case 'R': /* don't auto chase referrals */ +#ifdef LDAP_REFERRALS + lmap->ldap_options &= ~LDAP_OPT_REFERRALS; +#else /* LDAP_REFERRALS */ + syserr("compile with -DLDAP_REFERRALS for referral support\n"); +#endif /* LDAP_REFERRALS */ + break; + + case 'n': /* retrieve attribute names only -- no values */ + lmap->attrsonly += 1; + break; + + case 's': /* search scope */ + if (strncasecmp(p, "base", 4) == 0) + { + lmap->scope = LDAP_SCOPE_BASE; + } + else if (strncasecmp(p, "one", 3) == 0) + { + lmap->scope = LDAP_SCOPE_ONELEVEL; + } + else if (strncasecmp(p, "sub", 3) == 0) + { + lmap->scope = LDAP_SCOPE_SUBTREE; + } + else + { /* bad config line */ + if (!bitset(MCF_OPTFILE, map->map_class->map_cflags)) + { + syserr("Scope must be [base|one|sub] not %s in map %s", + p, map->map_mname); + return FALSE; + } + } + break; + + case 'h': /* ldap host */ + while (isascii(*++p) && isspace(*p)) + continue; + map->map_domain = p; + lmap->ldaphost = p; + break; + + case 'b': /* search base */ + while (isascii(*++p) && isspace(*p)) + continue; + lmap->base = p; + break; + + case 'p': /* ldap port */ + while (isascii(*++p) && isspace(*p)) + continue; + lmap->ldapport = atoi(p); + break; + + case 'l': /* time limit */ + while (isascii(*++p) && isspace(*p)) + continue; + lmap->timelimit = atoi(p); + break; + + } + + /* need to account for quoted strings here arggg... */ + done = isascii(*p) && isspace(*p); + while (*p != '\0' && !done) + { + if (*p == '"') + { + while (*++p != '"' && *p != '\0') + { + continue; + } + if (*p != '\0') + p++; + } + else + { + p++; + } + done = isascii(*p) && isspace(*p); + } + + if (*p != '\0') + *p++ = '\0'; + } + + if (map->map_app != NULL) + map->map_app = newstr(ldap_map_dequote(map->map_app)); + + if (map->map_domain != NULL) + map->map_domain = newstr(ldap_map_dequote(map->map_domain)); + + /* + ** We need to swallow up all the stuff into a struct + ** and dump it into map->map_dbptr1 + */ + + if (lmap->ldaphost != NULL) + lmap->ldaphost = newstr(ldap_map_dequote(lmap->ldaphost)); + else + { + syserr("LDAP map: -h flag is required"); + return FALSE; + } + + if (lmap->binddn != NULL) + lmap->binddn = newstr(ldap_map_dequote(lmap->binddn)); + else + lmap->binddn = DEFAULT_LDAP_MAP_BINDDN; + + + if (lmap->passwd != NULL) + lmap->passwd = newstr(ldap_map_dequote(lmap->passwd)); + else + lmap->passwd = DEFAULT_LDAP_MAP_PASSWD; + + if (lmap->base != NULL) + lmap->base = newstr(ldap_map_dequote(lmap->base)); + else + { + syserr("LDAP map: -b flag is required"); + return FALSE; + } + + + if (lmap->filter != NULL) + lmap->filter = newstr(ldap_map_dequote(lmap->filter)); + else + { + if (!bitset(MCF_OPTFILE, map->map_class->map_cflags)) + { + syserr("No filter given in map %s", map->map_mname); + return FALSE; + } + } + if (lmap->attr != NULL) + lmap->attr = newstr(ldap_map_dequote(lmap->attr)); + else + { + if (!bitset(MCF_OPTFILE, map->map_class->map_cflags)) + { + syserr("No return attribute in %s", map->map_mname); + return FALSE; + } + } + + map->map_db1 = (ARBPTR_T) lmap; + return TRUE; +} + +#endif /* LDAP Modules */ +/* ** HESIOD Modules */ @@ -2066,7 +2686,7 @@ ni_map_open(map, mode) { char *p; - if (tTd(38, 20)) + if (tTd(38, 2)) printf("ni_map_open(%s, %s, %d)\n", map->map_mname, map->map_file, mode); @@ -2240,6 +2860,9 @@ ni_propval(keydir, keyprop, keyval, valprop, sepchar) } strcat(keybuf, keyval); + if (tTd(38, 21)) + printf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n", + keydir, keyprop, keyval, valprop, sepchar, keybuf); /* ** If the passed directory and property name are found ** in one of netinfo domains we need to search (starting @@ -2248,11 +2871,13 @@ ni_propval(keydir, keyprop, keyval, valprop, sepchar) ** and return it. */ - for (i = 0; i < MAX_NI_LEVELS; ++i) + for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++) { if (i == 0) { nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni); + if (tTd(38, 20)) + printf("ni_open(LOCAL) = %d\n", nis); } else { @@ -2260,6 +2885,8 @@ ni_propval(keydir, keyprop, keyval, valprop, sepchar) ni_free(lastni); lastni = ni; nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni); + if (tTd(38, 20)) + printf("ni_open(PARENT) = %d\n", nis); } /* @@ -2287,6 +2914,8 @@ ni_propval(keydir, keyprop, keyval, valprop, sepchar) if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0) continue; + if (tTd(38, 20)) + printf("ni_lookupprop: len=%d\n", ninl.ni_namelist_len); /* ** See if we have an acceptable number of values. */ @@ -2327,6 +2956,8 @@ ni_propval(keydir, keyprop, keyval, valprop, sepchar) ni_free(ni); if (lastni != NULL && ni != lastni) ni_free(lastni); + if (tTd(38, 20)) + printf("ni_propval returns: '%s'\n", propval); return propval; } @@ -2362,37 +2993,41 @@ text_map_open(map, mode) if (*map->map_file == '\0') { - if (tTd(38, 2)) - printf("text_map_open(%s): file name required\n", - map->map_mname); + syserr("text map \"%s\": file name required", + map->map_mname); return FALSE; } if (map->map_file[0] != '/') { - if (tTd(38, 2)) - printf("text_map_open(%s, %s): file name must be fully qualified\n", - map->map_mname, map->map_file); + syserr("text map \"%s\": file name must be fully qualified", + map->map_mname); return FALSE; } /* check to see if this map actually accessable */ if (access(map->map_file, R_OK) <0) + { + if (tTd(38, 2)) + printf("text_map_open(%s, %s): cannot access: %s\n", + map->map_mname, map->map_file, errstring(errno)); + if (!bitset(MF_OPTIONAL, map->map_mflags)) + syserr("text map \"%s\": cannot access file %s", + map->map_mname, map->map_file); return FALSE; + } /* check to see if this map actually exist */ if (stat(map->map_file, &sbuf) <0) { - if (tTd(38, 2)) - printf("text_map_open(%s, %s): cannot stat\n", - map->map_mname, map->map_file); + syserr("text_map_open(%s, %s): cannot stat", + map->map_mname, map->map_file); return FALSE; } if (!S_ISREG(sbuf.st_mode)) { - if (tTd(38, 2)) - printf("text_map_open(%s): %s is not a regular file\n", - map->map_mname, map->map_file); + syserr("text map \"%s\": %s is not a regular file", + map->map_mname, map->map_file); return FALSE; } @@ -2402,10 +3037,9 @@ text_map_open(map, mode) { if (!isdigit(*map->map_keycolnm)) { - if (tTd(38, 2)) - printf("text_map_open(%s, %s): -k should specify a number, not %s\n", - map->map_mname, map->map_file, - map->map_keycolnm); + syserr("text map \"%s\", file %s: -k should specify a number, not %s", + map->map_mname, map->map_file, + map->map_keycolnm); return FALSE; } map->map_keycolno = atoi(map->map_keycolnm); @@ -2417,8 +3051,7 @@ text_map_open(map, mode) { if (!isdigit(*map->map_valcolnm)) { - if (tTd(38, 2)) - printf("text_map_open(%s, %s): -v should specify a number, not %s\n", + syserr("text map \"%s\", file %s: -v should specify a number, not %s", map->map_mname, map->map_file, map->map_valcolnm); return FALSE; @@ -2470,7 +3103,8 @@ text_map_lookup(map, name, av, statp) buflen = strlen(name); if (buflen > sizeof search_key - 1) buflen = sizeof search_key - 1; - bcopy(name, search_key, buflen + 1); + bcopy(name, search_key, buflen); + search_key[buflen] = '\0'; if (!bitset(MF_NOFOLDCASE, map->map_mflags)) makelower(search_key); @@ -2526,19 +3160,17 @@ text_getcanonname(name, hbsize, statp) int hbsize; int *statp; { - int key_idx; bool found; FILE *f; char linebuf[MAXLINE]; char cbuf[MAXNAME + 1]; - char fbuf[MAXNAME + 1]; char nbuf[MAXNAME + 1]; extern char *get_column __P((char *, int, char, char *, int)); if (tTd(38, 20)) printf("text_getcanonname(%s)\n", name); - if (strlen(name) >= sizeof nbuf) + if (strlen(name) >= (SIZE_T) sizeof nbuf) { *statp = EX_UNAVAILABLE; return FALSE; @@ -2569,7 +3201,7 @@ text_getcanonname(name, hbsize, statp) return FALSE; } - if (hbsize >= strlen(cbuf)) + if ((SIZE_T) hbsize >= strlen(cbuf)) { strcpy(name, cbuf); *statp = EX_OK; @@ -2736,9 +3368,9 @@ impl_map_open(map, mode) map->map_mflags |= MF_IMPL_HASH; if (hash_map_open(map, mode)) { -#if defined(NDBM) && defined(NIS) +# ifdef NDBM_YP_COMPAT if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL) -#endif +# endif return TRUE; } else @@ -2775,7 +3407,7 @@ impl_map_close(map) MAP *map; { if (tTd(38, 9)) - printf("impl_map_close(%s, %s, %x)\n", + printf("impl_map_close(%s, %s, %lx)\n", map->map_mname, map->map_file, map->map_mflags); #ifdef NEWDB if (bitset(MF_IMPL_HASH, map->map_mflags)) @@ -2866,12 +3498,13 @@ user_map_lookup(map, key, av, statp) int *statp; { struct passwd *pw; + auto bool fuzzy; if (tTd(38, 20)) printf("user_map_lookup(%s, %s)\n", map->map_mname, key); - pw = sm_getpwnam(key); + pw = finduser(key, &fuzzy); if (pw == NULL) return NULL; if (bitset(MF_MATCHONLY, map->map_mflags)) @@ -2966,6 +3599,7 @@ prog_map_lookup(map, name, av, statp) printf(" %s", argv[i]); printf("\n"); } + (void) blocksignal(SIGCHLD); pid = prog_open(argv, &fd, CurEnv); if (pid < 0) { @@ -2986,13 +3620,14 @@ prog_map_lookup(map, name, av, statp) map->map_mname, errstring(errno)); rval = NULL; } - else if (i == 0 && tTd(38, 20)) + else if (i == 0) { - printf("prog_map_lookup(%s): empty answer\n", - map->map_mname); + if (tTd(38, 20)) + printf("prog_map_lookup(%s): empty answer\n", + map->map_mname); rval = NULL; } - if (i > 0) + else { buf[i] = '\0'; p = strchr(buf, '\n'); @@ -3013,6 +3648,7 @@ prog_map_lookup(map, name, av, statp) /* wait for the process to terminate */ close(fd); stat = waitfor(pid); + (void) releasesignal(SIGCHLD); if (stat == -1) { diff --git a/usr.sbin/sendmail/src/mci.c b/usr.sbin/sendmail/src/mci.c index beff0197735..a81e61de2c7 100644 --- a/usr.sbin/sendmail/src/mci.c +++ b/usr.sbin/sendmail/src/mci.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995 Eric P. Allman + * Copyright (c) 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,10 +33,11 @@ */ #ifndef lint -static char sccsid[] = "@(#)mci.c 8.22.1.1 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)mci.c 8.54 (Berkeley) 12/1/96"; #endif /* not lint */ #include "sendmail.h" +#include <dirent.h> /* ** Mail Connection Information (MCI) Caching Module. @@ -62,10 +63,17 @@ static char sccsid[] = "@(#)mci.c 8.22.1.1 (Berkeley) 9/16/96"; ** connection and reopen it. Note that this means that a ** server SMTP that doesn't support NOOP will hose the ** algorithm -- but that doesn't seem too likely. +** +** The persistent MCI code is donated by Mark Lovell and Paul +** Vixie. It is based on the long term host status code in KJS +** written by Paul but has been adapted by Mark to fit into the +** MCI structure. */ MCI **MciCache; /* the open connection cache */ +extern int mci_generate_persistent_path __P((const char *, char *, int, bool)); +extern void mci_load_persistent __P((MCI *)); extern void mci_uncache __P((MCI **, bool)); /* ** MCI_CACHE -- enter a connection structure into the open connection cache @@ -84,7 +92,6 @@ mci_cache(mci) register MCI *mci; { register MCI **mcislot; - extern MCI **mci_scan(); /* ** Find the best slot. This may cause expired connections @@ -107,8 +114,8 @@ mci_cache(mci) mci_uncache(mcislot, TRUE); if (tTd(42, 5)) - printf("mci_cache: caching %x (%s) in slot %d\n", - mci, mci->mci_host, mcislot - MciCache); + printf("mci_cache: caching %lx (%s) in slot %d\n", + (u_long) mci, mci->mci_host, mcislot - MciCache); #ifdef LOG if (tTd(91, 100)) syslog(LOG_DEBUG, "%s: mci_cache: caching %x (%.100s) in slot %d", @@ -204,9 +211,11 @@ mci_uncache(mcislot, doquit) return; *mcislot = NULL; + mci_unlock_host(mci); + if (tTd(42, 5)) - printf("mci_uncache: uncaching %x (%s) from slot %d (%d)\n", - mci, mci->mci_host, mcislot - MciCache, doquit); + printf("mci_uncache: uncaching %lx (%s) from slot %d (%d)\n", + (u_long) mci, mci->mci_host, mcislot - MciCache, doquit); #ifdef LOG if (tTd(91, 100)) syslog(LOG_DEBUG, "%s: mci_uncache: uncaching %x (%.100s) from slot %d (%d)", @@ -214,7 +223,7 @@ mci_uncache(mcislot, doquit) mci, mci->mci_host, mcislot - MciCache, doquit); #endif -#ifdef SMTP +#if SMTP if (doquit) { message("Closing connection to %s", mci->mci_host); @@ -279,9 +288,8 @@ mci_get(host, m) { register MCI *mci; register STAB *s; - extern MCI **mci_scan(); -#ifdef DAEMON +#if DAEMON extern SOCKADDR CurHostAddr; /* clear CurHostAddr so we don't get a bogus address with this name */ @@ -297,6 +305,8 @@ mci_get(host, m) mci = &s->s_mci; mci->mci_host = s->s_name; + mci_load_persistent(mci); + if (tTd(42, 2)) { printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n", @@ -304,11 +314,13 @@ mci_get(host, m) mci->mci_exitstat, mci->mci_errno); } -#ifdef SMTP +#if SMTP if (mci->mci_state == MCIS_OPEN) { + extern int smtpprobe __P((MCI *)); + /* poke the connection to see if it's still alive */ - smtpprobe(mci); + (void) smtpprobe(mci); /* reset the stored state in the event of a timeout */ if (mci->mci_state != MCIS_OPEN) @@ -317,7 +329,7 @@ mci_get(host, m) mci->mci_exitstat = EX_OK; mci->mci_state = MCIS_CLOSED; } -# ifdef DAEMON +# if DAEMON else { /* get peer host address for logging reasons only */ @@ -330,7 +342,6 @@ mci_get(host, m) # endif } #endif -#ifdef MAYBE_NEXT_RELEASE if (mci->mci_state == MCIS_CLOSED) { time_t now = curtime(); @@ -343,11 +354,41 @@ mci_get(host, m) mci->mci_exitstat = EX_OK; } } -#endif return mci; } /* +** MCI_SETSTAT -- set status codes in MCI structure. +** +** Parameters: +** mci -- the MCI structure to set. +** xstat -- the exit status code. +** dstat -- the DSN status code. +** rstat -- the SMTP status code. +** +** Returns: +** none. +*/ + +void +mci_setstat(mci, xstat, dstat, rstat) + MCI *mci; + int xstat; + char *dstat; + char *rstat; +{ + /* protocol errors should never be interpreted as sticky */ + if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL) + mci->mci_exitstat = xstat; + + mci->mci_status = dstat; + if (mci->mci_rstatus != NULL) + free(mci->mci_rstatus); + if (rstat != NULL) + rstat = newstr(rstat); + mci->mci_rstatus = rstat; +} +/* ** MCI_DUMP -- dump the contents of an MCI structure. ** ** Parameters: @@ -360,6 +401,32 @@ mci_get(host, m) ** none. */ +struct mcifbits +{ + int mcif_bit; /* flag bit */ + char *mcif_name; /* flag name */ +}; +struct mcifbits MciFlags[] = +{ + { MCIF_VALID, "VALID" }, + { MCIF_TEMP, "TEMP" }, + { MCIF_CACHED, "CACHED" }, + { MCIF_ESMTP, "ESMTP" }, + { MCIF_EXPN, "EXPN" }, + { MCIF_SIZE, "SIZE" }, + { MCIF_8BITMIME, "8BITMIME" }, + { MCIF_7BIT, "7BIT" }, + { MCIF_MULTSTAT, "MULTSTAT" }, + { MCIF_INHEADER, "INHEADER" }, + { MCIF_CVT8TO7, "CVT8TO7" }, + { MCIF_DSN, "DSN" }, + { MCIF_8BITOK, "8BITOK" }, + { MCIF_CVT7TO8, "CVT7TO8" }, + { MCIF_INMIME, "INMIME" }, + { 0, NULL } +}; + + void mci_dump(mci, logit) register MCI *mci; @@ -379,9 +446,25 @@ mci_dump(mci, logit) snprintf(p, SPACELEFT(buf, p), "NULL"); goto printit; } + snprintf(p, SPACELEFT(buf, p), "flags=%x", mci->mci_flags); + p += strlen(p); + if (mci->mci_flags != 0) + { + struct mcifbits *f; + + *p++ = '<'; + for (f = MciFlags; f->mcif_bit != 0; f++) + { + if (!bitset(f->mcif_bit, mci->mci_flags)) + continue; + snprintf(p, SPACELEFT(buf, p), "%s,", f->mcif_name); + p += strlen(p); + } + p[-1] = '>'; + } snprintf(p, SPACELEFT(buf, p), - "flags=%x, errno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", - mci->mci_flags, mci->mci_errno, mci->mci_herrno, + ",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", + sep, mci->mci_errno, mci->mci_herrno, mci->mci_exitstat, mci->mci_state, mci->mci_pid, sep); p += strlen(p); snprintf(p, SPACELEFT(buf, p), @@ -392,6 +475,12 @@ mci_dump(mci, logit) sep); p += strlen(p); snprintf(p, SPACELEFT(buf, p), + "status=%s, rstatus=%s,%s", + mci->mci_status == NULL ? "NULL" : mci->mci_status, + mci->mci_rstatus == NULL ? "NULL" : mci->mci_rstatus, + sep); + p += strlen(p); + snprintf(p, SPACELEFT(buf, p), "host=%s, lastuse=%s", mci->mci_host == NULL ? "NULL" : mci->mci_host, ctime(&mci->mci_lastuse)); @@ -426,3 +515,756 @@ mci_dump_all(logit) for (i = 0; i < MaxMciCache; i++) mci_dump(MciCache[i], logit); } +/* +** MCI_LOCK_HOST -- Lock host while sending. +** +** If we are contacting a host, we'll need to +** update the status information in the host status +** file, and if we want to do that, we ought to have +** locked it. This has the (according to some) +** desirable effect of serializing connectivity with +** remote hosts -- i.e.: one connection to a give +** host at a time. +** +** Parameters: +** mci -- containing the host we want to lock. +** +** Returns: +** EX_OK -- got the lock. +** EX_TEMPFAIL -- didn't get the lock. +*/ + +int +mci_lock_host(mci) + MCI *mci; +{ + if (mci == NULL) + { + if (tTd(56, 1)) + printf("mci_lock_host: NULL mci\n"); + return EX_OK; + } + + if (!SingleThreadDelivery) + return EX_OK; + + return mci_lock_host_statfile(mci); +} + +int +mci_lock_host_statfile(mci) + MCI *mci; +{ + int savedErrno = errno; + int retVal = EX_OK; + char fname[MAXPATHLEN+1]; + + if (HostStatDir == NULL || mci->mci_host == NULL) + return EX_OK; + + if (tTd(56, 2)) + printf("mci_lock_host: attempting to lock %s\n", + mci->mci_host); + + if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, TRUE) < 0) + { + /* of course this should never happen */ + if (tTd(56, 2)) + printf("mci_lock_host: Failed to generate host path for %s\n", + mci->mci_host); + + retVal = EX_TEMPFAIL; + goto cleanup; + } + + if ((mci->mci_statfile = fopen(fname, "r+")) == NULL) + mci->mci_statfile = fopen(fname, "w"); + + if (mci->mci_statfile == NULL) + { + syserr("mci_lock_host: cannot create host lock file %s", + fname); + goto cleanup; + } + + if (!lockfile(fileno(mci->mci_statfile), fname, "", LOCK_EX|LOCK_NB)) + { + if (tTd(56, 2)) + printf("mci_lock_host: couldn't get lock on %s\n", + fname); + fclose(mci->mci_statfile); + mci->mci_statfile = NULL; + retVal = EX_TEMPFAIL; + goto cleanup; + } + + if (tTd(56, 12) && mci->mci_statfile != NULL) + printf("mci_lock_host: Sanity check -- lock is good\n"); + +cleanup: + errno = savedErrno; + return retVal; +} +/* +** MCI_UNLOCK_HOST -- unlock host +** +** Clean up the lock on a host, close the file, let +** someone else use it. +** +** Parameters: +** mci -- us. +** +** Returns: +** nothing. +*/ + +void +mci_unlock_host(mci) + MCI *mci; +{ + int saveErrno = errno; + + if (mci == NULL) + { + if (tTd(56, 1)) + printf("mci_unlock_host: NULL mci\n"); + return; + } + + if (HostStatDir == NULL || mci->mci_host == NULL) + return; + + if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL) + { + if (tTd(56, 1)) + printf("mci_unlock_host: stat file already locked\n"); + } + else + { + if (tTd(56, 2)) + printf("mci_unlock_host: store prior to unlock\n"); + + mci_store_persistent(mci); + } + + if (mci->mci_statfile != NULL) + { + fclose(mci->mci_statfile); + mci->mci_statfile = NULL; + } + + errno = saveErrno; +} +/* +** MCI_LOAD_PERSISTENT -- load persistent host info +** +** Load information about host that is kept +** in common for all running sendmails. +** +** Parameters: +** mci -- the host/connection to load persistent info +** for. +** +** Returns: +** none. +*/ + +void +mci_load_persistent(mci) + MCI *mci; +{ + int saveErrno = errno; + FILE *fp; + char fname[MAXPATHLEN+1]; + + if (mci == NULL) + { + if (tTd(56, 1)) + printf("mci_load_persistent: NULL mci\n"); + return; + } + + if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL) + return; + + if (tTd(56, 1)) + printf("mci_load_persistent: Attempting to load persistent information for %s\n", + mci->mci_host); + + if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, FALSE) < 0) + { + /* Not much we can do if the file isn't there... */ + if (tTd(56, 1)) + printf("mci_load_persistent: Couldn't generate host path\n"); + goto cleanup; + } + + fp = fopen(fname, "r"); + if (fp == NULL) + { + /* I can't think of any reason this should ever happen */ + if (tTd(56, 1)) + printf("mci_load_persistent: open(%s): %s\n", + fname, errstring(errno)); + goto cleanup; + } + + FileName = fname; + (void) mci_read_persistent(fp, mci); + FileName = NULL; + fclose(fp); + +cleanup: + errno = saveErrno; + return; +} +/* +** MCI_READ_PERSISTENT -- read persistent host status file +** +** Parameters: +** fp -- the file pointer to read. +** mci -- the pointer to fill in. +** +** Returns: +** -1 -- if the file was corrupt. +** 0 -- otherwise. +** +** Warning: +** This code makes the assumption that this data +** will be read in an atomic fashion, and that the data +** was written in an atomic fashion. Any other functioning +** may lead to some form of insanity. This should be +** perfectly safe due to underlying stdio buffering. +*/ + +int +mci_read_persistent(fp, mci) + FILE *fp; + register MCI *mci; +{ + int ver; + register char *p; + char buf[MAXLINE]; + + if (fp == NULL) + syserr("mci_read_persistent: NULL fp"); + if (mci == NULL) + syserr("mci_read_persistent: NULL mci"); + if (tTd(56, 93)) + { + printf("mci_read_persistent: fp=%lx, mci=", (u_long) fp); + mci_dump(mci, FALSE); + } + + mci->mci_status = NULL; + if (mci->mci_rstatus != NULL) + free(mci->mci_rstatus); + mci->mci_rstatus = NULL; + + rewind(fp); + ver = -1; + while (fgets(buf, sizeof buf, fp) != NULL) + { + p = strchr(buf, '\n'); + if (p != NULL) + *p = '\0'; + switch (buf[0]) + { + case 'V': /* version stamp */ + ver = atoi(&buf[1]); + if (ver < 0 || ver > 0) + syserr("Unknown host status version %d: %d max", + ver, 0); + break; + + case 'E': /* UNIX error number */ + mci->mci_errno = atoi(&buf[1]); + break; + + case 'H': /* DNS error number */ + mci->mci_herrno = atoi(&buf[1]); + break; + + case 'S': /* UNIX exit status */ + mci->mci_exitstat = atoi(&buf[1]); + break; + + case 'D': /* DSN status */ + mci->mci_status = newstr(&buf[1]); + break; + + case 'R': /* SMTP status */ + mci->mci_rstatus = newstr(&buf[1]); + break; + + case 'U': /* last usage time */ + mci->mci_lastuse = atol(&buf[1]); + break; + + case '.': /* end of file */ + return 0; + + default: + syserr("Unknown host status line \"%s\"", buf); + return -1; + } + } + if (ver < 0) + return -1; + return 0; +} +/* +** MCI_STORE_PERSISTENT -- Store persistent MCI information +** +** Store information about host that is kept +** in common for all running sendmails. +** +** Parameters: +** mci -- the host/connection to store persistent info for. +** +** Returns: +** none. +*/ + +void +mci_store_persistent(mci) + MCI *mci; +{ + int saveErrno = errno; + + if (mci == NULL) + { + if (tTd(56, 1)) + printf("mci_store_persistent: NULL mci\n"); + return; + } + + if (HostStatDir == NULL || mci->mci_host == NULL) + return; + + if (tTd(56, 1)) + printf("mci_store_persistent: Storing information for %s\n", + mci->mci_host); + + if (mci->mci_statfile == NULL) + { + if (tTd(56, 1)) + printf("mci_store_persistent: no statfile\n"); + return; + } + + rewind(mci->mci_statfile); +#if !NOFTRUNCATE + (void) ftruncate(fileno(mci->mci_statfile), (off_t) 0); +#endif + + fprintf(mci->mci_statfile, "V0\n"); + fprintf(mci->mci_statfile, "E%d\n", mci->mci_errno); + fprintf(mci->mci_statfile, "H%d\n", mci->mci_herrno); + fprintf(mci->mci_statfile, "S%d\n", mci->mci_exitstat); + if (mci->mci_status != NULL) + fprintf(mci->mci_statfile, "D%.80s\n", + denlstring(mci->mci_status, TRUE, FALSE)); + if (mci->mci_rstatus != NULL) + fprintf(mci->mci_statfile, "R%.80s\n", + denlstring(mci->mci_rstatus, TRUE, FALSE)); + fprintf(mci->mci_statfile, "U%ld\n", mci->mci_lastuse); + fprintf(mci->mci_statfile, ".\n"); + + fflush(mci->mci_statfile); + + errno = saveErrno; + return; +} +/* +** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree +** +** Recursively find all the mci host files in `pathname'. Default to +** main host status directory if no path is provided. +** Call (*action)(pathname, host) for each file found. +** +** Note: all information is collected in a list before it is processed. +** This may not be the best way to do it, but it seems safest, since +** the file system would be touched while we are attempting to traverse +** the directory tree otherwise (during purges). +** +** Parameters: +** action -- function to call on each node. If returns < 0, +** return immediately. +** pathname -- root of tree. If null, use main host status +** directory. +** +** Returns: +** < 0 -- if any action routine returns a negative value, that +** value is returned. +** 0 -- if we successfully went to completion. +*/ + +int +mci_traverse_persistent(action, pathname) + int (*action)(); + char *pathname; +{ + struct stat statbuf; + DIR *d; + int ret; + + if (pathname == NULL) + pathname = HostStatDir; + if (pathname == NULL) + return -1; + + if (tTd(56, 1)) + printf("mci_traverse: pathname is %s\n", pathname); + + ret = stat(pathname, &statbuf); + if (ret < 0) + { + if (tTd(56, 2)) + printf("mci_traverse: Failed to stat %s: %s\n", + pathname, errstring(errno)); + return ret; + } + if (S_ISDIR(statbuf.st_mode)) + { + struct dirent *e; + char *newptr; + char newpath[MAXPATHLEN+1]; + + if ((d = opendir(pathname)) == NULL) + { + if (tTd(56, 2)) + printf("mci_traverse: opendir %s: %s\n", + pathname, errstring(errno)); + return -1; + } + + if (strlen(pathname) >= sizeof newpath - MAXNAMLEN - 3) + { + if (tTd(56, 2)) + printf("mci_traverse: path \"%s\" too long", + pathname); + return -1; + } + strcpy(newpath, pathname); + newptr = newpath + strlen(newpath); + *newptr++ = '/'; + + while ((e = readdir(d)) != NULL) + { + if (e->d_name[0] == '.') + continue; + + strncpy(newptr, e->d_name, + sizeof newpath - (newptr - newpath) - 1); + newpath[sizeof newpath - 1] = '\0'; + + ret = mci_traverse_persistent(action, newpath); + if (ret < 0) + break; + + /* + ** The following appears to be + ** necessary during purges, since + ** we modify the directory structure + */ + + if (action == mci_purge_persistent) + rewinddir(d); + } + + /* purge (or whatever) the directory proper */ + *--newptr = '\0'; + ret = (*action)(newpath, NULL); + closedir(d); + } + else if (S_ISREG(statbuf.st_mode)) + { + char *end = pathname + strlen(pathname) - 1; + char *start; + char *scan; + char host[MAXHOSTNAMELEN]; + char *hostptr = host; + + /* + ** Reconstruct the host name from the path to the + ** persistent information. + */ + + do + { + if (hostptr != host) + *(hostptr++) = '.'; + start = end; + while (*(start - 1) != '/') + start--; + + if (*end == '.') + end--; + + for (scan = start; scan <= end; scan++) + *(hostptr++) = *scan; + + end = start - 2; + } while (*end == '.'); + + *hostptr = '\0'; + + /* + ** Do something with the file containing the persistent + ** information. + */ + ret = (*action)(pathname, host); + } + + return ret; +} +/* +** MCI_PRINT_PERSISTENT -- print persisten info +** +** Dump the persistent information in the file 'pathname' +** +** Parameters: +** pathname -- the pathname to the status file. +** hostname -- the corresponding host name. +** +** Returns: +** 0 +*/ + +int +mci_print_persistent(pathname, hostname) + char *pathname; + char *hostname; +{ + static int initflag = FALSE; + FILE *fp; + int width = Verbose ? 78 : 25; + bool locked; + MCI mcib; + + /* skip directories */ + if (hostname == NULL) + return 0; + + if (!initflag) + { + initflag = TRUE; + printf(" -------------- Hostname --------------- How long ago ---------Results---------\n"); + } + + fp = fopen(pathname, "r+"); + + if (fp == NULL) + { + if (tTd(56, 1)) + printf("mci_print_persistent: cannot open %s: %s\n", + pathname, errstring(errno)); + return 0; + } + + bzero(&mcib, sizeof mcib); + if (mci_read_persistent(fp, &mcib) < 0) + { + syserr("%s: could not read status file", pathname); + fclose(fp); + return 0; + } + + locked = !lockfile(fileno(fp), pathname, "", LOCK_EX|LOCK_NB); + fclose(fp); + + printf("%c%-39s %12s ", + locked ? '*' : ' ', hostname, + pintvl(curtime() - mcib.mci_lastuse, TRUE)); + if (mcib.mci_rstatus != NULL) + printf("%.*s\n", width, mcib.mci_rstatus); + else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0) + printf("Deferred: %.*s\n", width - 10, errstring(mcib.mci_errno)); + else if (mcib.mci_exitstat != 0) + { + int i = mcib.mci_exitstat - EX__BASE; + extern int N_SysEx; + extern char *SysExMsg[]; + + if (i < 0 || i > N_SysEx) + { + char buf[80]; + + snprintf(buf, sizeof buf, "Unknown mailer error %d", + mcib.mci_exitstat); + printf("%.*s\n", width, buf); + } + else + printf("%.*s\n", width, &(SysExMsg[i])[5]); + } + else if (mcib.mci_errno == 0) + printf("OK\n"); + else + printf("OK: %.*s\n", width - 4, errstring(mcib.mci_errno)); + + return 0; +} +/* +** MCI_PURGE_PERSISTENT -- Remove a persistence status file. +** +** Parameters: +** pathname -- path to the status file. +** hostname -- name of host corresponding to that file. +** NULL if this is a directory (domain). +** +** Returns: +** 0 +*/ + +int +mci_purge_persistent(pathname, hostname) + char *pathname; + char *hostname; +{ + char *end = pathname + strlen(pathname) - 1; + + if (tTd(56, 1)) + printf("mci_purge_persistent: purging %s\n", pathname); + + if (hostname != NULL) + { + /* remove the file */ + if (unlink(pathname) < 0) + { + if (tTd(56, 2)) + printf("mci_purge_persistent: failed to unlink %s: %s\n", + pathname, errstring(errno)); + } + } + else + { + /* remove the directory */ + if (*end != '.') + return 0; + + if (tTd(56, 1)) + printf("mci_purge_persistent: dpurge %s\n", pathname); + + if (rmdir(pathname) < 0) + { + if (tTd(56, 2)) + printf("mci_purge_persistent: rmdir %s: %s\n", + pathname, errstring(errno)); + } + + } + + return 0; +} +/* +** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname +** +** Given `host', convert from a.b.c to $QueueDir/.hoststat/c./b./a, +** putting the result into `path'. if `createflag' is set, intervening +** directories will be created as needed. +** +** Parameters: +** host -- host name to convert from. +** path -- place to store result. +** pathlen -- length of path buffer. +** createflag -- if set, create intervening directories as +** needed. +** +** Returns: +** 0 -- success +** -1 -- failure +*/ + +int +mci_generate_persistent_path(host, path, pathlen, createflag) + const char *host; + char *path; + int pathlen; + bool createflag; +{ + char *elem, *p, *x, ch; + int ret = 0; + int len; + char t_host[MAXHOSTNAMELEN]; + + /* + ** Rationality check the arguments. + */ + + if (host == NULL) + syserr("mci_generate_persistent_path: null host"); + if (path == NULL) + syserr("mci_generate_persistent_path: null path"); + + if (tTd(56, 80)) + printf("mci_generate_persistent_path(%s): ", host); + + /* make certain this is not a bracketed host number */ + if (strlen(host) > sizeof t_host - 1) + return -1; + if (host[0] == '[') + strcpy(t_host, host + 1); + else + strcpy(t_host, host); + + /* + ** Delete any trailing dots from the hostname. + ** Leave 'elem' pointing at the \0. + */ + + elem = t_host + strlen(t_host); + while (elem > t_host && (elem[-1] == '.' || elem[-1] == ']')) + *--elem = '\0'; + + /* check for what will be the final length of the path */ + len = strlen(HostStatDir) + 2; + for (p = (char *) host; *p != '\0'; p++) + { + if (*p == '|' || *p != '.') + len++; + len++; + } + if (len > pathlen) + return -1; + + strcpy(path, HostStatDir); + p = path + strlen(path); + + while (elem > t_host) + { + if (!path_is_dir(path, createflag)) + { + ret = -1; + break; + } + elem--; + while (elem >= t_host && *elem != '.') + elem--; + *p++ = '/'; + x = elem + 1; + while ((ch = *x++) != '\0' && ch != '.') + { + if (isupper(ch)) + ch = tolower(ch); + if (ch == '|') + *p++ = '|'; /* | -> || */ + else if (ch == '/') + ch = '|'; /* / -> | */ + *p++ = ch; + } + if (elem >= t_host) + *p++ = '.'; + *p = '\0'; + } + + if (tTd(56, 80)) + { + if (ret < 0) + printf("FAILURE %d\n", ret); + else + printf("SUCCESS %s\n", path); + } + + return (ret); +} diff --git a/usr.sbin/sendmail/src/mime.c b/usr.sbin/sendmail/src/mime.c index 1c71a84ac6b..bdb91a2642d 100644 --- a/usr.sbin/sendmail/src/mime.c +++ b/usr.sbin/sendmail/src/mime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994 Eric P. Allman + * Copyright (c) 1994, 1996 Eric P. Allman * Copyright (c) 1994 * The Regents of the University of California. All rights reserved. * @@ -36,7 +36,7 @@ # include <string.h> #ifndef lint -static char sccsid[] = "@(#)mime.c 8.30.1.1 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)mime.c 8.51 (Berkeley) 11/24/96"; #endif /* not lint */ /* @@ -72,6 +72,10 @@ static char *MimeBoundaryNames[] = { "SYNTAX", "NOTSEP", "INTERMED", "FINAL" }; + +bool MapNLtoCRLF; + +extern int mimeboundary __P((char *, char **)); /* ** MIME8TO7 -- output 8 bit body in 7 bit format ** @@ -125,11 +129,14 @@ mime8to7(mci, header, e, boundaries, flags) char **pvp; int argc = 0; char *bp; + bool use_qp = FALSE; struct args argv[MAXMIMEARGS]; char bbuf[128]; char buf[MAXLINE]; char pvpbuf[MAXLINE]; extern u_char MimeTokenTab[256]; + extern int mime_getchar __P((FILE *, char **, int *)); + extern int mime_getchar_crlf __P((FILE *, char **, int *)); if (tTd(43, 1)) { @@ -143,6 +150,7 @@ mime8to7(mci, header, e, boundaries, flags) } printf("\n"); } + MapNLtoCRLF = TRUE; p = hvalue("Content-Transfer-Encoding", header); if (p == NULL || (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, @@ -226,6 +234,13 @@ mime8to7(mci, header, e, boundaries, flags) if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e'))) flags |= M87F_NO8BIT; +#ifdef USE_B_CLASS + if (wordinclass(buf, 'b') || wordinclass(type, 'b')) + MapNLtoCRLF = FALSE; +#endif + if (wordinclass(buf, 'q') || wordinclass(type, 'q')) + use_qp = TRUE; + /* ** Multipart requires special processing. ** @@ -246,8 +261,12 @@ mime8to7(mci, header, e, boundaries, flags) } if (i >= argc) { - syserr("mime8to7: Content-Type: %s missing boundary", p); + syserr("mime8to7: Content-Type: \"%s\": missing boundary", + p); p = "---"; + + /* avoid bounce loops */ + e->e_flags |= EF_DONT_MIME; } else { @@ -260,6 +279,9 @@ mime8to7(mci, header, e, boundaries, flags) syserr("mime8to7: multipart boundary \"%s\" too long", p); blen = sizeof bbuf - 1; + + /* avoid bounce loops */ + e->e_flags |= EF_DONT_MIME; } strncpy(bbuf, p, blen); bbuf[blen] = '\0'; @@ -269,7 +291,12 @@ mime8to7(mci, header, e, boundaries, flags) if (boundaries[i] == NULL) break; if (i >= MAXMIMENESTING) + { syserr("mime8to7: multipart nesting boundary too deep"); + + /* avoid bounce loops */ + e->e_flags |= EF_DONT_MIME; + } else { boundaries[i] = bbuf; @@ -332,7 +359,7 @@ mime8to7(mci, header, e, boundaries, flags) } /* - ** Message/* types -- recurse exactly once. + ** Message/xxx types -- recurse exactly once. ** ** Class 's' is predefined to have "rfc822" only. */ @@ -422,9 +449,11 @@ mime8to7(mci, header, e, boundaries, flags) if (tTd(43, 8)) { - printf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s\n", - sectionhighbits, sectionsize, - cte == NULL ? "[none]" : cte); + printf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s, type=%s/%s\n", + (long) sectionhighbits, (long) sectionsize, + cte == NULL ? "[none]" : cte, + type == NULL ? "[none]" : type, + subtype == NULL ? "[none]" : subtype); } if (cte != NULL && strcasecmp(cte, "binary") == 0) sectionsize = sectionhighbits; @@ -453,14 +482,19 @@ mime8to7(mci, header, e, boundaries, flags) if (feof(e->e_dfp)) bt = MBT_FINAL; } - else if (sectionsize / 8 < sectionhighbits) + else if (!MapNLtoCRLF || + (sectionsize / 8 < sectionhighbits && !use_qp)) { /* use base64 encoding */ int c1, c2; - putline("Content-Transfer-Encoding: base64", mci); if (tTd(43, 36)) printf(" ...Content-Transfer-Encoding: base64\n"); + putline("Content-Transfer-Encoding: base64", mci); + snprintf(buf, sizeof buf, + "X-MIME-Autoconverted: from 8bit to base64 by %s id %s", + MyHostName, e->e_id); + putline(buf, mci); putline("", mci); mci->mci_flags &= ~MCIF_INHEADER; while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != EOF) @@ -519,9 +553,13 @@ mime8to7(mci, header, e, boundaries, flags) for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++) setbitn(*p, badchars); - putline("Content-Transfer-Encoding: quoted-printable", mci); if (tTd(43, 36)) printf(" ...Content-Transfer-Encoding: quoted-printable\n"); + putline("Content-Transfer-Encoding: quoted-printable", mci); + snprintf(buf, sizeof buf, + "X-MIME-Autoconverted: from 8bit to quoted-printable by %s id %s", + MyHostName, e->e_id); + putline(buf, mci); putline("", mci); mci->mci_flags &= ~MCIF_INHEADER; fromstate = 0; @@ -693,7 +731,7 @@ mime_getchar(fp, boundaries, btp) *bp++ = c; } *bp = '\0'; - bt = mimeboundary(&buf[1], boundaries); + bt = mimeboundary((char *) &buf[1], boundaries); switch (bt) { case MBT_FINAL: @@ -746,7 +784,7 @@ mime_getchar_crlf(fp, boundaries, btp) return '\n'; } c = mime_getchar(fp, boundaries, btp); - if (c == '\n') + if (c == '\n' && MapNLtoCRLF) { sendlf = TRUE; return '\r'; @@ -776,6 +814,7 @@ mimeboundary(line, boundaries) int type = MBT_NOTSEP; int i; int savec; + extern int isboundary __P((char *, char **)); if (line[0] != '-' || line[1] != '-' || boundaries == NULL) return MBT_NOTSEP; @@ -864,4 +903,281 @@ isboundary(line, boundaries) return -1; } -#endif /* MIME */ +#endif /* MIME8TO7 */ + +#if MIME7TO8 + +/* +** MIME7TO8 -- output 7 bit encoded MIME body in 8 bit format +** +** This is a hack. Supports translating the two 7-bit body-encodings +** (quoted-printable and base64) to 8-bit coded bodies. +** +** There is not much point in supporting multipart here, as the UA +** will be able to deal with encoded MIME bodies if it can parse MIME +** multipart messages. +** +** Note also that we wont be called unless it is a text/plain MIME +** message, encoded base64 or QP and mailer flag '9' has been defined +** on mailer. +** +** Contributed by Marius Olaffson <marius@rhi.hi.is>. +** +** Parameters: +** mci -- mailer connection information. +** header -- the header for this body part. +** e -- envelope. +** +** Returns: +** none. +*/ + +extern int mime_fromqp __P((u_char *, u_char **, int, int)); + +static char index_64[128] = +{ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +}; + +#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) + + +void +mime7to8(mci, header, e) + register MCI *mci; + HDR *header; + register ENVELOPE *e; +{ + register char *p; + char *cte; + char **pvp; + u_char *obp; + u_char *fbufp; + char buf[MAXLINE]; + u_char obuf[MAXLINE + 1]; + u_char fbuf[MAXLINE + 1]; + char pvpbuf[MAXLINE]; + extern u_char MimeTokenTab[256]; + + p = hvalue("Content-Transfer-Encoding", header); + if (p == NULL || + (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, + MimeTokenTab)) == NULL || + pvp[0] == NULL) + { + /* "can't happen" -- upper level should have caught this */ + syserr("mime7to8: unparsable CTE %s", p == NULL ? "<NULL>" : p); + + /* avoid bounce loops */ + e->e_flags |= EF_DONT_MIME; + + /* cheap failsafe algorithm -- should work on text/plain */ + if (p != NULL) + { + snprintf(buf, sizeof buf, + "Content-Transfer-Encoding: %s", p); + putline(buf, mci); + } + putline("", mci); + mci->mci_flags &= ~MCIF_INHEADER; + while (fgets(buf, sizeof buf, e->e_dfp) != NULL) + putline(buf, mci); + return; + } + cataddr(pvp, NULL, buf, sizeof buf, '\0'); + cte = newstr(buf); + + putline("Content-Transfer-Encoding: 8bit", mci); + snprintf(buf, sizeof buf, + "X-MIME-Autoconverted: from %.200s to 8bit by %s id %s", + cte, MyHostName, e->e_id); + putline(buf, mci); + putline("", mci); + mci->mci_flags &= ~MCIF_INHEADER; + + /* + ** Translate body encoding to 8-bit. Supports two types of + ** encodings; "base64" and "quoted-printable". Assume qp if + ** it is not base64. + */ + + if (strcasecmp(cte, "base64") == 0) + { + int c1, c2, c3, c4; + + fbufp = fbuf; + while ((c1 = fgetc(e->e_dfp)) != EOF) + { + if (isascii(c1) && isspace(c1)) + continue; + + do + { + c2 = fgetc(e->e_dfp); + } while (isascii(c2) && isspace(c2)); + if (c2 == EOF) + break; + + do + { + c3 = fgetc(e->e_dfp); + } while (isascii(c3) && isspace(c3)); + if (c3 == EOF) + break; + + do + { + c4 = fgetc(e->e_dfp); + } while (isascii(c4) && isspace(c4)); + if (c4 == EOF) + break; + + if (c1 == '=' || c2 == '=') + continue; + c1 = CHAR64(c1); + c2 = CHAR64(c2); + + *fbufp = (c1 << 2) | ((c2 & 0x30) >> 4); + if (*fbufp++ == '\n' || fbuf >= &fbuf[MAXLINE]) + { + if (*--fbufp != '\n' || *--fbufp != '\r') + fbufp++; + *fbufp = '\0'; + putline((char *) fbuf, mci); + fbufp = fbuf; + } + if (c3 == '=') + continue; + c3 = CHAR64(c3); + *fbufp = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); + if (*fbufp++ == '\n' || fbuf >= &fbuf[MAXLINE]) + { + if (*--fbufp != '\n' || *--fbufp != '\r') + fbufp++; + *fbufp = '\0'; + putline((char *) fbuf, mci); + fbufp = fbuf; + } + if (c4 == '=') + continue; + c4 = CHAR64(c4); + *fbufp = ((c3 & 0x03) << 6) | c4; + if (*fbufp++ == '\n' || fbuf >= &fbuf[MAXLINE]) + { + if (*--fbufp != '\n' || *--fbufp != '\r') + fbufp++; + *fbufp = '\0'; + putline((char *) fbuf, mci); + fbufp = fbuf; + } + } + + /* force out partial last line */ + if (fbufp > fbuf) + { + *fbufp = '\0'; + putline((char *) fbuf, mci); + } + } + else + { + /* quoted-printable */ + obp = obuf; + while (fgets(buf, sizeof buf, e->e_dfp) != NULL) + { + if (mime_fromqp((u_char *) buf, &obp, 0, &obuf[MAXLINE] - obp) == 0) + continue; + + putline((char *) obuf, mci); + obp = obuf; + } + } + if (tTd(43, 3)) + printf("\t\t\tmime7to8 => %s to 8bit done\n", cte); +} +/* +** The following is based on Borenstein's "codes.c" module, with simplifying +** changes as we do not deal with multipart, and to do the translation in-core, +** with an attempt to prevent overrun of output buffers. +** +** What is needed here are changes to defned this code better against +** bad encodings. Questionable to always return 0xFF for bad mappings. +*/ + +static char index_hex[128] = +{ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 +}; + +#define HEXCHAR(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) + +int +mime_fromqp(infile, outfile, state, maxlen) + u_char *infile; + u_char **outfile; + int state; /* Decoding body (0) or header (1) */ + int maxlen; /* Max # of chars allowed in outfile */ +{ + int c1, c2; + int nchar = 0; + + while ((c1 = *infile++) != '\0') + { + if (c1 == '=') + { + if ((c1 = *infile++) == 0) + break; + + if (c1 == '\n') /* ignore it */ + { + if (state == 0) + return 0; + } + else + { + if ((c2 = *infile++) == '\0') + break; + + c1 = HEXCHAR(c1); + c2 = HEXCHAR(c2); + + if (++nchar > maxlen) + break; + + *(*outfile)++ = c1 << 4 | c2; + } + } + else + { + if (state == 1 && c1 == '_') + c1 = ' '; + + if (++nchar > maxlen) + break; + + *(*outfile)++ = c1; + + if (c1 == '\n') + break; + } + } + *(*outfile)++ = '\0'; + return 1; +} + + +#endif /* MIME7TO8 */ diff --git a/usr.sbin/sendmail/src/parseaddr.c b/usr.sbin/sendmail/src/parseaddr.c index 85f34a726a1..a10c329ffa8 100644 --- a/usr.sbin/sendmail/src/parseaddr.c +++ b/usr.sbin/sendmail/src/parseaddr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)parseaddr.c 8.87.1.1 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)parseaddr.c 8.115 (Berkeley) 11/24/96"; #endif /* not lint */ # include "sendmail.h" @@ -169,7 +169,7 @@ parseaddr(addr, a, flags, delim, delimptr, e) ** If there was a parsing failure, mark it for queueing. */ - if (queueup) + if (queueup && OpMode != MD_INITALIAS) { char *msg = "Transient parse error -- message queued for future delivery"; @@ -220,14 +220,6 @@ invalidaddr(addr, delimptr) if (savedelim != '\0') *delimptr = '\0'; } -#if 0 - /* for testing.... */ - if (strcmp(addr, "INvalidADDR") == 0) - { - usrerr("553 INvalid ADDRess"); - goto addrfailure; - } -#endif for (; *addr != '\0'; addr++) { if ((*addr & 0340) == 0200) @@ -241,7 +233,6 @@ invalidaddr(addr, delimptr) } setstat(EX_USAGE); usrerr("553 Address contained invalid control characters"); - addrfailure: if (delimptr != NULL && savedelim != '\0') *delimptr = savedelim; return TRUE; @@ -343,12 +334,12 @@ allocaddr(a, flags, paddr) static short StateTab[NSTATES][NSTATES] = { /* oldst chtype> OPR ATM QST SPC ONE ILL */ - /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB, - /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB, - /*QST*/ QST, QST, OPR, QST, QST, QST, - /*SPC*/ OPR, ATM, QST, SPC|M, ONE, ILL|MB, - /*ONE*/ OPR, OPR, OPR, OPR, OPR, ILL|MB, - /*ILL*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M, + /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, + /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, + /*QST*/ { QST, QST, OPR, QST, QST, QST }, + /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, + /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, + /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, }; /* token type table -- it gets modified with $o characters */ @@ -444,6 +435,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) register int c; char **avp; bool bslashmode; + bool route_syntax; int cmntcnt; int anglecnt; char *tok; @@ -483,6 +475,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) q = pvpbuf; bslashmode = FALSE; + route_syntax = FALSE; cmntcnt = 0; anglecnt = 0; avp = av; @@ -510,7 +503,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) if (q >= &pvpbuf[pvpbsize - 5]) { usrerr("553 Address too long"); - if (strlen(addr) > MAXNAME) + if (strlen(addr) > (SIZE_T) MAXNAME) addr[MAXNAME] = '\0'; returnnull: if (delimptr != NULL) @@ -548,9 +541,19 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) p--; } - else if (c == delim && anglecnt <= 0 && - cmntcnt <= 0 && state != QST) - break; + else if (c == delim && cmntcnt <= 0 && state != QST) + { + if (anglecnt <= 0) + break; + + /* special case for better error management */ + if (delim == ',' && !route_syntax) + { + usrerr("653 Unbalanced '<'"); + c = '>'; + p--; + } + } if (tTd(22, 101)) printf("c=%c, s=%d; ", c, state); @@ -600,7 +603,15 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) else if (cmntcnt > 0) c = NOCHAR; else if (c == '<') + { + char *q = p; + anglecnt++; + while (isascii(*q) && isspace(*q)) + q++; + if (*q == '@') + route_syntax = TRUE; + } else if (c == '>') { if (anglecnt <= 0) @@ -610,6 +621,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) } else anglecnt--; + route_syntax = FALSE; } else if (delim == ' ' && isascii(c) && isspace(c)) c = ' '; @@ -743,10 +755,11 @@ rewrite(pvp, ruleset, reclevel, e) int loopcount; struct match mlist[MAXMATCH]; /* stores match on LHS */ char *npvp[MAXATOM+1]; /* temporary space for rebuild */ + extern int callsubr __P((char**, int, ENVELOPE *)); if (OpMode == MD_TEST || tTd(21, 1)) { - printf("rewrite: ruleset %2d input:", ruleset); + printf("rewrite: ruleset %3d input:", ruleset); printav(pvp); } if (ruleset < 0 || ruleset >= MAXRWSETS) @@ -772,6 +785,12 @@ rewrite(pvp, ruleset, reclevel, e) loopcount = 0; for (rwr = RewriteRules[ruleset]; rwr != NULL; ) { + int stat; + + /* if already canonical, quit now */ + if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) + break; + if (tTd(21, 12)) { printf("-----trying rule:"); @@ -1002,8 +1021,6 @@ rewrite(pvp, ruleset, reclevel, e) rvp++; rwr = NULL; } - else if ((*rp & 0377) == CANONNET) - rwr = NULL; /* substitute */ for (avp = npvp; *rvp != NULL; rvp++) @@ -1028,7 +1045,7 @@ rewrite(pvp, ruleset, reclevel, e) pp = m->first; while (pp <= m->last) { - printf(" %x=\"", *pp); + printf(" %lx=\"", (u_long) *pp); (void) fflush(stdout); printf("%s\"", *pp++); } @@ -1091,6 +1108,7 @@ rewrite(pvp, ruleset, reclevel, e) char *argvect[10]; char pvpbuf[PSBUFSIZE]; char *nullpvp[1]; + extern char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); if ((**rvp & 0377) != HOSTBEGIN && (**rvp & 0377) != LOOKUPBEGIN) @@ -1160,7 +1178,7 @@ rewrite(pvp, ruleset, reclevel, e) if (xpvp != NULL) { cataddr(xpvp, NULL, replac, - &pvpbuf[sizeof pvpbuf] - replac, + &pvpbuf[sizeof pvpbuf] - replac, '\0'); *++arg_rvp = replac; } @@ -1173,55 +1191,7 @@ rewrite(pvp, ruleset, reclevel, e) /* look it up */ cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); argvect[0] = buf; - if (e->e_sendmode == SM_DEFER) - { - /* don't do any map lookups */ - if (tTd(60, 1)) - printf("map_lookup(%s, %s) => DEFERRED\n", - mapname, buf); - replac = NULL; - rstat = EX_TEMPFAIL; - } - else if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) - { - auto int stat = EX_OK; - - if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags)) - stripquotes(buf); - - /* XXX should try to auto-open the map here */ - - if (tTd(60, 1)) - printf("map_lookup(%s, %s) => ", - mapname, buf); - replac = (*map->s_map.map_class->map_lookup)(&map->s_map, - buf, argvect, &stat); - if (tTd(60, 1)) - printf("%s (%d)\n", - replac ? replac : "NOT FOUND", - stat); - - /* should recover if stat == EX_TEMPFAIL */ - if (stat == EX_TEMPFAIL) - { - rstat = EX_TEMPFAIL; - if (tTd(60, 1)) - printf("map_lookup(%s, %s) tempfail: errno=%d\n", - mapname, buf, errno); - if (e->e_message == NULL) - { - char mbuf[300]; - - snprintf(mbuf, sizeof mbuf, - "%.80s map: lookup (%s): deferred", - mapname, - shortenstring(buf, 203)); - e->e_message = newstr(mbuf); - } - } - } - else - replac = NULL; + replac = map_lookup(map, buf, argvect, &rstat, e); /* if no replacement, use default */ if (replac == NULL && default_rvp != NULL) @@ -1273,38 +1243,16 @@ rewrite(pvp, ruleset, reclevel, e) ** Check for subroutine calls. */ - if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) - { - int stat; + stat = callsubr(npvp, reclevel, e); + if (rstat == EX_OK || stat == EX_TEMPFAIL) + rstat = stat; - if (npvp[1] == NULL) - { - syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", - ruleset, ruleno); - *pvp = NULL; - } - else - { - int ruleset; - STAB *s; - - bcopy((char *) &npvp[2], (char *) pvp, - (int) (avp - npvp - 2) * sizeof *avp); - if (tTd(21, 3)) - printf("-----callsubr %s\n", npvp[1]); - ruleset = strtorwset(npvp[1], NULL, ST_FIND); - stat = rewrite(pvp, ruleset, reclevel, e); - if (rstat == EX_OK || stat == EX_TEMPFAIL) - rstat = stat; - if (*pvp != NULL && (**pvp & 0377) == CANONNET) - rwr = NULL; - } - } - else - { - bcopy((char *) npvp, (char *) pvp, - (int) (avp - npvp) * sizeof *avp); - } + /* copy vector back into original space. */ + for (avp = npvp; *avp++ != NULL;) + continue; + bcopy((char *) npvp, (char *) pvp, + (int) (avp - npvp) * sizeof *avp); + if (tTd(21, 4)) { printf("rewritten as:"); @@ -1314,13 +1262,192 @@ rewrite(pvp, ruleset, reclevel, e) if (OpMode == MD_TEST || tTd(21, 1)) { - printf("rewrite: ruleset %2d returns:", ruleset); + printf("rewrite: ruleset %3d returns:", ruleset); printav(pvp); } return rstat; } /* +** CALLSUBR -- call subroutines in rewrite vector +** +** Parameters: +** pvp -- pointer to token vector. +** reclevel -- the current recursion level. +** e -- the current envelope. +** +** Returns: +** The status from the subroutine call. +** +** Side Effects: +** pvp is modified. +*/ + +int +callsubr(pvp, reclevel, e) + char **pvp; + int reclevel; + ENVELOPE *e; +{ + char **avp; + char **rvp; + register int i; + int subr; + int stat; + int rstat = EX_OK; + char *tpvp[MAXATOM + 1]; + + for (avp = pvp; *avp != NULL; avp++) + { + if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) + { + subr = strtorwset(avp[1], NULL, ST_FIND); + if (subr < 0) + { + syserr("Unknown ruleset %s", avp[1]); + return EX_CONFIG; + } + + if (tTd(21, 3)) + printf("-----callsubr %s (%d)\n", avp[1], subr); + + /* + ** Take care of possible inner calls first. + ** use a full size temporary buffer to avoid + ** overflows in rewrite, but strip off the + ** subroutine call. + */ + + for (i = 2; avp[i] != NULL; i++) + tpvp[i - 2] = avp[i]; + tpvp[i - 2] = NULL; + + stat = callsubr(tpvp, reclevel, e); + if (rstat == EX_OK || stat == EX_TEMPFAIL) + rstat = stat; + + /* + ** Now we need to call the ruleset specified for + ** the subroutine. we can do this with the + ** temporary buffer that we set up earlier, + ** since it has all the data we want to rewrite. + */ + + stat = rewrite(tpvp, subr, reclevel, e); + if (rstat == EX_OK || stat == EX_TEMPFAIL) + rstat = stat; + + /* + ** Find length of tpvp and current offset into + ** pvp, if the total is greater than MAXATOM, + ** then it would overflow the buffer if we copied + ** it back in to pvp, in which case we throw a + ** fit. + */ + + for (rvp = tpvp; *rvp != NULL; rvp++) + continue; + if (((rvp - tpvp) + (avp - pvp)) > MAXATOM) + { + syserr("554 callsubr: expansion too long"); + return EX_DATAERR; + } + + /* + ** Now we can copy the rewritten code over + ** the initial subroutine call in the buffer. + */ + + for (i = 0; tpvp[i] != NULL; i++) + avp[i] = tpvp[i]; + avp[i] = NULL; + + /* + ** If we got this far, we've processed the left + ** most subroutine, and recursively called ourselves + ** to handle any other subroutines. We're done. + */ + + break; + } + } + return rstat; +} +/* +** MAP_LOOKUP -- do lookup in map +** +** Parameters: +** map -- the map to use for the lookup. +** key -- the key to look up. +** argvect -- arguments to pass to the map lookup. +** pstat -- a pointer to an integer in which to store the +** status from the lookup. +** e -- the current envelope. +** +** Returns: +** The result of the lookup. +** NULL -- if there was no data for the given key. +*/ + +char * +map_lookup(map, key, argvect, pstat, e) + STAB *map; + char key[]; + char **argvect; + int *pstat; + ENVELOPE *e; +{ + auto int stat = EX_OK; + char *replac; + + if (e->e_sendmode == SM_DEFER) + { + /* don't do any map lookups */ + if (tTd(60, 1)) + printf("map_lookup(%s, %s) => DEFERRED\n", + map->s_name, key); + *pstat = EX_TEMPFAIL; + return NULL; + } + if (map == NULL || !bitset(MF_OPEN, map->s_map.map_mflags)) + return NULL; + + if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags)) + stripquotes(key); + + /* XXX should try to auto-open the map here */ + + if (tTd(60, 1)) + printf("map_lookup(%s, %s) => ", + map->s_name, key); + replac = (*map->s_map.map_class->map_lookup)(&map->s_map, + key, argvect, &stat); + if (tTd(60, 1)) + printf("%s (%d)\n", + replac != NULL ? replac : "NOT FOUND", + stat); + + /* should recover if stat == EX_TEMPFAIL */ + if (stat == EX_TEMPFAIL && !bitset(MF_NODEFER, map->s_map.map_mflags)) + { + *pstat = EX_TEMPFAIL; + if (tTd(60, 1)) + printf("map_lookup(%s, %s) tempfail: errno=%d\n", + map->s_name, key, errno); + if (e->e_message == NULL) + { + char mbuf[300]; + + snprintf(mbuf, sizeof mbuf, + "%.80s map: lookup (%s): deferred", + map->s_name, + shortenstring(key, 203)); + e->e_message = newstr(mbuf); + } + } + return replac; +} +/* ** BUILDADDR -- build address from token vector. ** ** Parameters: @@ -1345,17 +1472,17 @@ struct errcodes int ec_code; /* numeric code */ } ErrorCodes[] = { - "usage", EX_USAGE, - "nouser", EX_NOUSER, - "nohost", EX_NOHOST, - "unavailable", EX_UNAVAILABLE, - "software", EX_SOFTWARE, - "tempfail", EX_TEMPFAIL, - "protocol", EX_PROTOCOL, + { "usage", EX_USAGE }, + { "nouser", EX_NOUSER }, + { "nohost", EX_NOHOST }, + { "unavailable", EX_UNAVAILABLE }, + { "software", EX_SOFTWARE }, + { "tempfail", EX_TEMPFAIL }, + { "protocol", EX_PROTOCOL }, #ifdef EX_CONFIG - "config", EX_CONFIG, + { "config", EX_CONFIG }, #endif - NULL, EX_UNAVAILABLE, + { NULL, EX_UNAVAILABLE } }; ADDRESS * @@ -1386,7 +1513,7 @@ buildaddr(tv, a, flags, e) bzero((char *) a, sizeof *a); /* set up default error return flags */ - a->q_flags |= QPINGONFAILURE|QPINGONDELAY; + a->q_flags |= DefaultNotify; /* figure out what net/mailer to use */ if (*tv == NULL || (**tv & 0377) != CANONNET) @@ -1407,7 +1534,7 @@ badaddr: mname = *++tv; /* extract host and user portions */ - if ((**++tv & 0377) == CANONHOST) + if (*++tv != NULL && (**tv & 0377) == CANONHOST) hostp = ++tv; else hostp = NULL; @@ -1433,6 +1560,8 @@ badaddr: if (strchr(hbuf, '.') != NULL) { + extern int dsntoexitstat __P((char *)); + a->q_status = newstr(hbuf); setstat(dsntoexitstat(hbuf)); } @@ -1703,27 +1832,27 @@ struct qflags struct qflags AddressFlags[] = { - "QDONTSEND", QDONTSEND, - "QBADADDR", QBADADDR, - "QGOODUID", QGOODUID, - "QPRIMARY", QPRIMARY, - "QQUEUEUP", QQUEUEUP, - "QSENT", QSENT, - "QNOTREMOTE", QNOTREMOTE, - "QSELFREF", QSELFREF, - "QVERIFIED", QVERIFIED, - "QBOGUSSHELL", QBOGUSSHELL, - "QUNSAFEADDR", QUNSAFEADDR, - "QPINGONSUCCESS", QPINGONSUCCESS, - "QPINGONFAILURE", QPINGONFAILURE, - "QPINGONDELAY", QPINGONDELAY, - "QHASNOTIFY", QHASNOTIFY, - "QRELAYED", QRELAYED, - "QEXPANDED", QEXPANDED, - "QDELIVERED", QDELIVERED, - "QDELAYED", QDELAYED, - "QTHISPASS", QTHISPASS, - NULL + { "QDONTSEND", QDONTSEND }, + { "QBADADDR", QBADADDR }, + { "QGOODUID", QGOODUID }, + { "QPRIMARY", QPRIMARY }, + { "QQUEUEUP", QQUEUEUP }, + { "QSENT", QSENT }, + { "QNOTREMOTE", QNOTREMOTE }, + { "QSELFREF", QSELFREF }, + { "QVERIFIED", QVERIFIED }, + { "QBOGUSSHELL", QBOGUSSHELL }, + { "QUNSAFEADDR", QUNSAFEADDR }, + { "QPINGONSUCCESS", QPINGONSUCCESS }, + { "QPINGONFAILURE", QPINGONFAILURE }, + { "QPINGONDELAY", QPINGONDELAY }, + { "QHASNOTIFY", QHASNOTIFY }, + { "QRELAYED", QRELAYED }, + { "QEXPANDED", QEXPANDED }, + { "QDELIVERED", QDELIVERED }, + { "QDELAYED", QDELAYED }, + { "QTHISPASS", QTHISPASS }, + { NULL } }; void @@ -1744,7 +1873,7 @@ printaddr(a, follow) while (a != NULL) { - printf("%x=", a); + printf("%lx=", (u_long) a); (void) fflush(stdout); /* find the mailer -- carefully */ @@ -1763,8 +1892,9 @@ printaddr(a, follow) printf("\tuser `%s', ruser `%s'\n", a->q_user, a->q_ruser == NULL ? "<null>" : a->q_ruser); - printf("\tnext=%x, alias %x, uid %d, gid %d\n", - a->q_next, a->q_alias, a->q_uid, a->q_gid); + printf("\tnext=%lx, alias %lx, uid %d, gid %d\n", + (u_long) a->q_next, (u_long) a->q_alias, + (int) a->q_uid, (int) a->q_gid); printf("\tflags=%lx<", a->q_flags); firstone = TRUE; for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) @@ -1781,10 +1911,14 @@ printaddr(a, follow) a->q_owner == NULL ? "(none)" : a->q_owner, a->q_home == NULL ? "(none)" : a->q_home, a->q_fullname == NULL ? "(none)" : a->q_fullname); - printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", + printf("\torcpt=\"%s\", statmta=%s, status=%s\n", a->q_orcpt == NULL ? "(none)" : a->q_orcpt, a->q_statmta == NULL ? "(none)" : a->q_statmta, + a->q_status == NULL ? "(none)" : a->q_status); + printf("\trstatus=\"%s\"\n", a->q_rstatus == NULL ? "(none)" : a->q_rstatus); + printf("\tspecificity=%d, statdate=%s\n", + a->q_specificity, ctime(&a->q_statdate)); if (!follow) return; @@ -1993,7 +2127,12 @@ maplocaluser(a, sendq, aliaslevel, e) if (pvp == NULL) return; - (void) rewrite(pvp, 5, 0, e); + if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL) + { + a->q_flags |= QQUEUEUP; + a->q_status = "4.4.3"; + return; + } if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) return; @@ -2154,5 +2293,111 @@ dequote_map(map, name, av, statp) quotemode || quotecnt <= 0 || spacecnt != 0) return NULL; *q++ = '\0'; - return name; + return map_rewrite(map, name, strlen(name), NULL); +} +/* +** RSCHECK -- check string(s) for validity using rewriting sets +** +** Parameters: +** rwset -- the rewriting set to use. +** p1 -- the first string to check. +** p2 -- the second string to check -- may be null. +** e -- the current envelope. +** +** Returns: +** EX_OK -- if the rwset doesn't resolve to $#error +** else -- the failure status (message printed) +*/ + +int +rscheck(rwset, p1, p2, e) + char *rwset; + char *p1; + char *p2; + ENVELOPE *e; +{ + char *buf; + int bufsize; + int saveexitstat; + int rstat; + char **pvp; + int rsno; + auto ADDRESS a1; + bool saveQuickAbort = QuickAbort; + char buf0[MAXLINE]; + char pvpbuf[PSBUFSIZE]; + extern char MsgBuf[]; + + if (tTd(48, 2)) + printf("rscheck(%s, %s, %s)\n", rwset, p1, + p2 == NULL ? "(NULL)" : p2); + + rsno = strtorwset(rwset, NULL, ST_FIND); + if (rsno < 0) + return EX_OK; + + if (p2 != NULL) + { + bufsize = strlen(p1) + strlen(p2) + 2; + if (bufsize > sizeof buf0) + buf = xalloc(bufsize); + else + { + buf = buf0; + bufsize = sizeof buf0; + } + (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); + } + else + { + bufsize = strlen(p1) + 1; + if (bufsize > sizeof buf0) + buf = xalloc(bufsize); + else + { + buf = buf0; + bufsize = sizeof buf0; + } + (void) snprintf(buf, bufsize, "%s", p1); + } + pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); + if (pvp == NULL) + { + rstat = EX_DATAERR; + goto finis; + } + (void) rewrite(pvp, rsno, 0, e); + if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || + pvp[1] == NULL || strcmp(pvp[1], "error") != 0) + return EX_OK; + + /* got an error -- process it */ + saveexitstat = ExitStat; + QuickAbort = FALSE; + (void) buildaddr(pvp, &a1, 0, e); + QuickAbort = saveQuickAbort; + rstat = ExitStat; + ExitStat = saveexitstat; + +#ifdef LOG + if (LogLevel >= 4) + { + if (p2 == NULL) + syslog(LOG_NOTICE, "Ruleset %s (%s) rejection: %s", + rwset, p1, MsgBuf); + else + syslog(LOG_NOTICE, "Ruleset %s (%s, %s) rejection: %s", + rwset, p1, p2, MsgBuf); + } +#endif + + if (QuickAbort) + longjmp(TopFrame, 2); + + /* clean up */ + finis: + setstat(rstat); + if (buf != buf0) + free(buf); + return rstat; } diff --git a/usr.sbin/sendmail/src/queue.c b/usr.sbin/sendmail/src/queue.c index eb5176eade9..c5100364000 100644 --- a/usr.sbin/sendmail/src/queue.c +++ b/usr.sbin/sendmail/src/queue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -35,17 +35,17 @@ # include "sendmail.h" #ifndef lint -#ifdef QUEUE -static char sccsid[] = "@(#)queue.c 8.98.1.3 (Berkeley) 9/16/96 (with queueing)"; +#if QUEUE +static char sccsid[] = "@(#)queue.c 8.145 (Berkeley) 12/2/96 (with queueing)"; #else -static char sccsid[] = "@(#)queue.c 8.98.1.3 (Berkeley) 9/16/96 (without queueing)"; +static char sccsid[] = "@(#)queue.c 8.145 (Berkeley) 12/2/96 (without queueing)"; #endif #endif /* not lint */ # include <errno.h> # include <dirent.h> -# ifdef QUEUE +# if QUEUE /* ** Work queue. @@ -71,6 +71,8 @@ WORK *WorkQ; /* queue of things to be done */ #if !defined(NGROUPS_MAX) && defined(NGROUPS) # define NGROUPS_MAX NGROUPS /* POSIX naming convention */ #endif + +extern int orderq __P((bool)); /* ** QUEUEUP -- queue a message up for future transmission. ** @@ -193,7 +195,7 @@ queueup(e, announce) if (!bitset(EF_HAS_DF, e->e_flags)) { - register FILE *dfp; + register FILE *dfp = NULL; char dfname[20]; struct stat stbuf; @@ -261,6 +263,12 @@ queueup(e, announce) *p++ = 'r'; if (bitset(EF_HAS8BIT, e->e_flags)) *p++ = '8'; + if (bitset(EF_DELETE_BCC, e->e_flags)) + *p++ = 'b'; + if (bitset(EF_RET_PARAM, e->e_flags)) + *p++ = 'd'; + if (bitset(EF_NO_BODY_RETN, e->e_flags)) + *p++ = 'n'; *p++ = '\0'; if (buf[0] != '\0') fprintf(tfp, "F%s\n", buf); @@ -288,38 +296,46 @@ queueup(e, announce) printctladdr(NULL, NULL); for (q = e->e_sendqueue; q != NULL; q = q->q_next) { - if (bitset(QQUEUEUP, q->q_flags) || - !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)) + if (bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)) { - printctladdr(q, tfp); - if (q->q_orcpt != NULL) - fprintf(tfp, "Q%s\n", - denlstring(q->q_orcpt, TRUE, FALSE)); - putc('R', tfp); - if (bitset(QPRIMARY, q->q_flags)) - putc('P', tfp); - if (bitset(QPINGONSUCCESS, q->q_flags)) - putc('S', tfp); - if (bitset(QPINGONFAILURE, q->q_flags)) - putc('F', tfp); - if (bitset(QPINGONDELAY, q->q_flags)) - putc('D', tfp); - putc(':', tfp); - fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE)); - if (announce) - { - e->e_to = q->q_paddr; - message("queued"); - if (LogLevel > 8) - logdelivery(q->q_mailer, NULL, "queued", - NULL, (time_t) 0, e); - e->e_to = NULL; - } - if (tTd(40, 1)) - { - printf("queueing "); - printaddr(q, FALSE); - } +#if XDEBUG + if (bitset(QQUEUEUP, q->q_flags)) + syslog(LOG_DEBUG, + "dropenvelope: %s: q_flags = %x, paddr = %s", + e->e_id, q->q_flags, q->q_paddr); +#endif + continue; + } + printctladdr(q, tfp); + if (q->q_orcpt != NULL) + fprintf(tfp, "Q%s\n", + denlstring(q->q_orcpt, TRUE, FALSE)); + putc('R', tfp); + if (bitset(QPRIMARY, q->q_flags)) + putc('P', tfp); + if (bitset(QHASNOTIFY, q->q_flags)) + putc('N', tfp); + if (bitset(QPINGONSUCCESS, q->q_flags)) + putc('S', tfp); + if (bitset(QPINGONFAILURE, q->q_flags)) + putc('F', tfp); + if (bitset(QPINGONDELAY, q->q_flags)) + putc('D', tfp); + putc(':', tfp); + fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE)); + if (announce) + { + e->e_to = q->q_paddr; + message("queued"); + if (LogLevel > 8) + logdelivery(q->q_mailer, NULL, "queued", + NULL, (time_t) 0, e); + e->e_to = NULL; + } + if (tTd(40, 1)) + { + printf("queueing "); + printaddr(q, FALSE); } } @@ -459,7 +475,6 @@ printctladdr(a, tfp) { char *uname; char *paddr; - register struct passwd *pw; register ADDRESS *q; uid_t uid; gid_t gid; @@ -516,9 +531,10 @@ printctladdr(a, tfp) ** forkflag -- TRUE if the queue scanning should be done in ** a child process. We double-fork so it is not our ** child and we don't have to clean up after it. +** verbose -- if TRUE, print out status information. ** ** Returns: -** none. +** TRUE if the queue run successfully began. ** ** Side Effects: ** runs things in the mail queue. @@ -526,14 +542,18 @@ printctladdr(a, tfp) ENVELOPE QueueEnvelope; /* the queue run envelope */ -void -runqueue(forkflag) +bool +runqueue(forkflag, verbose) bool forkflag; + bool verbose; { register ENVELOPE *e; int njobs; int sequenceno = 0; extern ENVELOPE BlankEnvelope; + extern void clrdaemon __P((void)); + extern void runqueueevent __P((bool)); + extern void drop_privileges __P((void)); /* ** If no work will ever be selected, don't even bother reading @@ -546,15 +566,15 @@ runqueue(forkflag) { char *msg = "Skipping queue run -- load average too high"; - if (Verbose) - printf("%s\n", msg); + if (verbose) + message("458 %s\n", msg); #ifdef LOG if (LogLevel > 8) syslog(LOG_INFO, "runqueue: %s", msg); #endif if (forkflag && QueueIntvl != 0) - (void) setevent(QueueIntvl, runqueue, TRUE); - return; + (void) setevent(QueueIntvl, runqueueevent, TRUE); + return FALSE; } /* @@ -563,35 +583,58 @@ runqueue(forkflag) if (forkflag) { - int pid; + pid_t pid; extern void intsig(); #ifdef SIGCHLD extern void reapchild(); + blocksignal(SIGCHLD); (void) setsignal(SIGCHLD, reapchild); #endif pid = dofork(); + if (pid == -1) + { + const char *msg = "Skipping queue run -- fork() failed"; + const char *err = errstring(errno); + + if (verbose) + message("458 %s: %s\n", msg, err); +#ifdef LOG + if (LogLevel > 8) + syslog(LOG_INFO, "runqueue: %s: %s", msg, err); +#endif + if (QueueIntvl != 0) + (void) setevent(QueueIntvl, runqueueevent, TRUE); + (void) releasesignal(SIGCHLD); + return FALSE; + } if (pid != 0) { /* parent -- pick up intermediate zombie */ #ifndef SIGCHLD (void) waitfor(pid); #else - CurChildren++; + (void) blocksignal(SIGALRM); + proc_list_add(pid); + (void) releasesignal(SIGALRM); + releasesignal(SIGCHLD); #endif /* SIGCHLD */ if (QueueIntvl != 0) - (void) setevent(QueueIntvl, runqueue, TRUE); - return; + (void) setevent(QueueIntvl, runqueueevent, TRUE); + return TRUE; } /* child -- double fork and clean up signals */ + proc_list_clear(); #ifndef SIGCHLD if (fork() != 0) exit(EX_OK); #else /* SIGCHLD */ + releasesignal(SIGCHLD); (void) setsignal(SIGCHLD, SIG_DFL); #endif /* SIGCHLD */ (void) setsignal(SIGHUP, intsig); + Verbose = FALSE; } setproctitle("running queue: %s", QueueDir); @@ -606,13 +649,17 @@ runqueue(forkflag) ** Release any resources used by the daemon code. */ -# ifdef DAEMON +# if DAEMON clrdaemon(); # endif /* DAEMON */ /* force it to run expensive jobs */ NoConnect = FALSE; + /* drop privileges */ + if (geteuid() == (uid_t) 0) + drop_privileges(); + /* ** Create ourselves an envelope */ @@ -628,6 +675,18 @@ runqueue(forkflag) initmaps(FALSE, e); /* + ** If we are running part of the queue, always ignore stored + ** host status. + */ + + if (QueueLimitId != NULL || QueueLimitSender != NULL || + QueueLimitRecipient != NULL) + { + IgnoreHostStatus = TRUE; + MinQueueAge = 0; + } + + /* ** Start making passes through the queue. ** First, read and sort the entire queue. ** Then, process the work in that order. @@ -643,6 +702,7 @@ runqueue(forkflag) WORK *w = WorkQ; WorkQ = WorkQ->w_next; + e->e_to = NULL; /* ** Ignore jobs that are too expensive for the moment. @@ -652,8 +712,11 @@ runqueue(forkflag) if (shouldqueue(w->w_pri, w->w_ctime)) { if (Verbose) - printf("\nSkipping %s (sequence %d of %d)\n", + { + message(""); + message("Skipping %s (sequence %d of %d)", w->w_name + 2, sequenceno, njobs); + } } else { @@ -661,8 +724,11 @@ runqueue(forkflag) extern pid_t dowork(); if (Verbose) - printf("\nRunning %s (sequence %d of %d)\n", + { + message(""); + message("Running %s (sequence %d of %d)", w->w_name + 2, sequenceno, njobs); + } pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e); errno = 0; if (pid != 0) @@ -677,6 +743,20 @@ runqueue(forkflag) /* exit without the usual cleanup */ e->e_id = NULL; finis(); + /*NOTREACHED*/ + return TRUE; +} + + +/* +** RUNQUEUEEVENT -- stub for use in setevent +*/ + +void +runqueueevent(forkflag) + bool forkflag; +{ + (void) runqueue(forkflag, FALSE); } /* ** ORDERQ -- order the work queue. @@ -850,10 +930,15 @@ orderq(doall) i |= NEED_R; while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) { + int qfver = 0; extern bool strcontainedin(); switch (lbuf[0]) { + case 'V': + qfver = atoi(&lbuf[1]); + break; + case 'P': w->w_pri = atol(&lbuf[1]); i &= ~NEED_P; @@ -868,8 +953,20 @@ orderq(doall) if (w->w_host == NULL && (p = strrchr(&lbuf[1], '@')) != NULL) w->w_host = newstr(&p[1]); - if (QueueLimitRecipient == NULL || - strcontainedin(QueueLimitRecipient, &lbuf[1])) + if (QueueLimitRecipient == NULL) + { + i &= ~NEED_R; + break; + } + if (qfver > 0) + { + p = strchr(&lbuf[1], ':'); + if (p == NULL) + p = &lbuf[1]; + } + else + p = &lbuf[1]; + if (strcontainedin(QueueLimitRecipient, p)) i &= ~NEED_R; break; @@ -958,6 +1055,16 @@ orderq(doall) qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2); } + else if (QueueSortOrder == QS_BYTIME) + { + extern workcmpf3(); + + /* + ** Simple sort based on submission time only. + */ + + qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3); + } else { extern workcmpf0(); @@ -1165,6 +1272,34 @@ workcmpf2(a, b) return a->w_pri - b->w_pri; } /* +** WORKCMPF3 -- simple submission-time-only compare function. +** +** Parameters: +** a -- the first argument. +** b -- the second argument. +** +** Returns: +** -1 if a < b +** 0 if a == b +** +1 if a > b +** +** Side Effects: +** none. +*/ + +int +workcmpf3(a, b) + register WORK *a; + register WORK *b; +{ + if (a->w_ctime > b->w_ctime) + return 1; + else if (a->w_ctime < b->w_ctime) + return -1; + else + return 0; +} +/* ** DOWORK -- do a work request. ** ** Parameters: @@ -1243,6 +1378,7 @@ dowork(id, forkflag, requeueflag, e) disconnect(1, e); OpMode = MD_DELIVER; } + setproctitle("%s: from queue", id); # ifdef LOG if (LogLevel > 76) syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id, @@ -1276,7 +1412,7 @@ dowork(id, forkflag, requeueflag, e) if (forkflag) finis(); else - dropenvelope(e); + dropenvelope(e, TRUE); } e->e_id = NULL; return pid; @@ -1304,13 +1440,13 @@ readqf(e) struct stat st; char *bp; int qfver = 0; + long hdrsize = 0; register char *p; char *orcpt = NULL; bool nomore = FALSE; char qf[20]; char buf[MAXLINE]; extern ADDRESS *setctluser __P((char *, int)); - extern void loseqfile(); /* ** Read and process the file. @@ -1355,7 +1491,8 @@ readqf(e) return FALSE; } - if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode)) + if ((st.st_uid != geteuid() && geteuid() != RealUid) || + bitset(S_IWOTH|S_IWGRP, st.st_mode)) { # ifdef LOG if (LogLevel > 0) @@ -1374,6 +1511,9 @@ readqf(e) if (st.st_size == 0) { /* must be a bogus file -- just remove it */ + qf[0] = 'd'; + (void) unlink(qf); + qf[0] = 'q'; (void) unlink(qf); fclose(qfp); return FALSE; @@ -1408,6 +1548,8 @@ readqf(e) register char *p; u_long qflags; ADDRESS *q; + int mid; + auto char *ep; if (tTd(40, 4)) printf("+++++ %s\n", bp); @@ -1448,6 +1590,10 @@ readqf(e) { switch (*p) { + case 'N': + qflags |= QHASNOTIFY; + break; + case 'S': qflags |= QPINGONSUCCESS; break; @@ -1472,6 +1618,8 @@ readqf(e) if (q != NULL) { q->q_alias = ctladdr; + if (qfver >= 1) + q->q_flags &= ~Q_PINGFLAGS; q->q_flags |= qflags; q->q_orcpt = orcpt; (void) recipient(q, &e->e_sendqueue, 0, e); @@ -1485,6 +1633,7 @@ readqf(e) case 'H': /* header */ (void) chompheader(&bp[1], FALSE, NULL, e); + hdrsize += strlen(&bp[1]); break; case 'M': /* message */ @@ -1508,8 +1657,7 @@ readqf(e) break; case 'I': /* data file's inode number */ - if (e->e_dfino == -1) - e->e_dfino = atol(&buf[1]); + /* regenerated below */ break; case 'K': /* time of last deliver attempt */ @@ -1518,6 +1666,26 @@ readqf(e) case 'N': /* number of delivery attempts */ e->e_ntries = atoi(&buf[1]); + + /* if this has been tried recently, let it be */ + if (e->e_ntries > 0 && + (curtime() - e->e_dtime) < MinQueueAge) + { + char *howlong = pintvl(curtime() - e->e_dtime, TRUE); + extern void unlockqueue(); + + if (Verbose || tTd(40, 8)) + printf("%s: too young (%s)\n", + e->e_id, howlong); +#ifdef LOG + if (LogLevel > 19) + syslog(LOG_DEBUG, "%s: too young (%s)", + e->e_id, howlong); +#endif + e->e_id = NULL; + unlockqueue(e); + return FALSE; + } break; case 'P': /* message priority */ @@ -1548,6 +1716,18 @@ readqf(e) case '8': /* has 8 bit data */ e->e_flags |= EF_HAS8BIT; break; + + case 'b': /* delete Bcc: header */ + e->e_flags |= EF_DELETE_BCC; + break; + + case 'd': /* envelope has DSN RET= */ + e->e_flags |= EF_RET_PARAM; + break; + + case 'n': /* don't return body */ + e->e_flags |= EF_NO_BODY_RETN; + break; } } break; @@ -1557,7 +1737,8 @@ readqf(e) break; case '$': /* define macro */ - define(bp[1], newstr(&bp[2]), e); + mid = macid(&bp[1], &ep); + define(mid, newstr(ep), e); break; case '.': /* terminate file */ @@ -1566,7 +1747,7 @@ readqf(e) default: syserr("readqf: %s: line %d: bad line \"%s\"", - qf, LineNumber, bp); + qf, LineNumber, shortenstring(bp, 203)); fclose(qfp); loseqfile(e, "unrecognized line"); return FALSE; @@ -1588,25 +1769,6 @@ readqf(e) return TRUE; } - /* if this has been tried recently, let it be */ - if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge) - { - char *howlong = pintvl(curtime() - e->e_dtime, TRUE); - extern void unlockqueue(); - - if (Verbose || tTd(40, 8)) - printf("%s: too young (%s)\n", - e->e_id, howlong); -#ifdef LOG - if (LogLevel > 19) - syslog(LOG_DEBUG, "%s: too young (%s)", - e->e_id, howlong); -#endif - e->e_id = NULL; - unlockqueue(e); - return FALSE; - } - /* ** Arrange to read the data file. */ @@ -1622,7 +1784,7 @@ readqf(e) e->e_flags |= EF_HAS_DF; if (fstat(fileno(e->e_dfp), &st) >= 0) { - e->e_msgsize = st.st_size; + e->e_msgsize = st.st_size + hdrsize; e->e_dfdev = st.st_dev; e->e_dfino = st.st_ino; } @@ -1706,8 +1868,8 @@ printqueue() CurrentLA = getla(); /* get load average */ printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); - if (nrequests > WorkListSize) - printf(", only %d printed", WorkListSize); + if (MaxQueueRun > 0 && nrequests > MaxQueueRun) + printf(", only %d printed", MaxQueueRun); if (Verbose) printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); else @@ -1775,7 +1937,7 @@ printqueue() case 'S': /* sender name */ if (Verbose) - printf("%8ld %10ld%c%.12s %.38s", + printf("%8ld %10ld%c%.12s %.78s", dfsize, w->w_pri, bitset(EF_WARNING, flags) ? '+' : ' ', @@ -1788,13 +1950,15 @@ printqueue() { printf("\n %10.10s", bodytype); if (statmsg[0] != '\0') - printf(" (%.60s)", statmsg); + printf(" (%.*s)", + Verbose ? 100 : 60, + statmsg); } break; case 'C': /* controlling user */ if (Verbose) - printf("\n\t\t\t\t (---%.34s---)", + printf("\n\t\t\t\t (---%.74s---)", &buf[1]); break; @@ -1808,7 +1972,7 @@ printqueue() p++; } if (Verbose) - printf("\n\t\t\t\t\t %.38s", p); + printf("\n\t\t\t\t\t %.78s", p); else printf("\n\t\t\t\t %.45s", p); break; @@ -1863,7 +2027,7 @@ queuename(e, type) register ENVELOPE *e; int type; { - static int pid = -1; + static pid_t pid = -1; static char c0; static char c1; static char c2; @@ -1929,7 +2093,8 @@ queuename(e, type) e->e_id = newstr(&qf[2]); define('i', e->e_id, e); if (tTd(7, 1)) - printf("queuename: assigned id %s, env=%x\n", e->e_id, e); + printf("queuename: assigned id %s, env=%lx\n", + e->e_id, (u_long) e); if (tTd(7, 9)) { printf(" lockfd="); @@ -1966,7 +2131,8 @@ unlockqueue(e) ENVELOPE *e; { if (tTd(51, 4)) - printf("unlockqueue(%s)\n", e->e_id); + printf("unlockqueue(%s)\n", + e->e_id == NULL ? "NOQUEUE" : e->e_id); /* if there is a lock file in the envelope, close it */ if (e->e_lockfp != NULL) @@ -2090,7 +2256,7 @@ loseqfile(e, why) if (e == NULL || e->e_id == NULL) return; - if (strlen(e->e_id) > sizeof buf - 4) + if (strlen(e->e_id) > (SIZE_T) sizeof buf - 4) return; strcpy(buf, queuename(e, 'q')); p = queuename(e, 'Q'); diff --git a/usr.sbin/sendmail/src/readcf.c b/usr.sbin/sendmail/src/readcf.c index e7528655ae4..58c4a3af21a 100644 --- a/usr.sbin/sendmail/src/readcf.c +++ b/usr.sbin/sendmail/src/readcf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)readcf.c 8.139 (Berkeley) 11/29/95"; +static char sccsid[] = "@(#)readcf.c 8.181 (Berkeley) 12/1/96"; #endif /* not lint */ # include "sendmail.h" @@ -112,10 +112,11 @@ readcf(cfname, safe, e) char exbuf[MAXLINE]; char pvpbuf[MAXLINE + MAXATOM]; static char *null_list[1] = { NULL }; - extern char *munchstring __P((char *, char **)); + extern char *munchstring __P((char *, char **, int)); extern void fileclass __P((int, char *, char *, bool, bool)); extern void toomany __P((int, int)); extern void translate_dollars __P((char *)); + extern void inithostmaps __P((void)); FileName = cfname; LineNumber = 0; @@ -246,10 +247,6 @@ readcf(cfname, safe, e) botch = "$?"; break; - case CONDELSE: - botch = "$|"; - break; - case CONDFI: botch = "$."; break; @@ -354,16 +351,17 @@ readcf(cfname, safe, e) rwp = RewriteRules[ruleset]; if (rwp != NULL) { + if (OpMode == MD_TEST || tTd(37, 1)) + printf("WARNING: Ruleset %s has multiple definitions\n", + &bp[1]); while (rwp->r_next != NULL) rwp = rwp->r_next; - fprintf(stderr, "WARNING: Ruleset %s redefined\n", - &bp[1]); } break; case 'D': /* macro definition */ mid = macid(&bp[1], &ep); - p = munchstring(ep, NULL); + p = munchstring(ep, NULL, '\0'); define(mid, newstr(p), e); break; @@ -441,6 +439,13 @@ readcf(cfname, safe, e) break; #endif +#ifdef SUN_EXTENSIONS + case 'L': /* lookup macro */ + case 'G': /* lookup class */ + /* reserved for Sun -- NIS+ database lookup */ + goto badline; +#endif + case 'M': /* define mailer */ makemailer(&bp[1]); break; @@ -499,6 +504,8 @@ readcf(cfname, safe, e) if (*ep++ == '/') { + extern bool setvendor __P((char *)); + /* extract vendor code */ for (p = ep; isascii(*p) && isalpha(*p); ) p++; @@ -708,7 +715,7 @@ fileclass(class, filename, fmt, safe, optional) { FILE *f; int sff; - int pid; + pid_t pid; register char *p; char buf[MAXLINE]; @@ -837,13 +844,11 @@ makemailer(line) auto char *endp; extern int NextMailer; extern char **makeargv(); - extern char *munchstring(); + extern char *munchstring __P((char *, char **, int)); /* allocate a mailer and set up defaults */ m = (struct mailer *) xalloc(sizeof *m); bzero((char *) m, sizeof *m); - m->m_eol = "\n"; - m->m_uid = m->m_gid = 0; /* collect the mailer name */ for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) @@ -875,7 +880,7 @@ makemailer(line) p++; /* p now points to the field body */ - p = munchstring(p, &delimptr); + p = munchstring(p, &delimptr, ','); /* install the field into the mailer struct */ switch (fcode) @@ -1019,6 +1024,10 @@ makemailer(line) m->m_uid = strtol(p, &q, 0); p = q; + while (isascii(*p) && isspace(*p)) + p++; + if (*p != '\0') + p++; } while (isascii(*p) && isspace(*p)) p++; @@ -1089,6 +1098,29 @@ makemailer(line) m->m_diagtype = "smtp"; } + if (m->m_eol == NULL) + { + char **pp; + + /* default for SMTP is \r\n; use \n for local delivery */ + for (pp = m->m_argv; *pp != NULL; pp++) + { + char *p; + + for (p = *pp; *p != '\0'; ) + { + if ((*p++ & 0377) == MACROEXPAND && *p == 'u') + break; + } + if (*p != '\0') + break; + } + if (*pp == NULL) + m->m_eol = "\r\n"; + else + m->m_eol = "\n"; + } + /* enter the mailer into the symbol table */ s = stab(m->m_name, ST_MAILER, ST_ENTER); if (s->s_mailer != NULL) @@ -1110,15 +1142,17 @@ makemailer(line) ** p -- the string to munch. ** delimptr -- if non-NULL, set to the pointer of the ** field delimiter character. +** delim -- the delimiter for the field. ** ** Returns: ** the munched string. */ char * -munchstring(p, delimptr) +munchstring(p, delimptr, delim) register char *p; char **delimptr; + int delim; { register char *q; bool backslash = FALSE; @@ -1157,7 +1191,7 @@ munchstring(p, delimptr) backslash = TRUE; else if (*p == '"') quotemode = !quotemode; - else if (quotemode || *p != ',') + else if (quotemode || *p != delim) *q++ = *p; else break; @@ -1264,7 +1298,7 @@ printmailer(m) m->m_mno, m->m_name, m->m_mailer, m->m_se_rwset, m->m_sh_rwset, m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, - m->m_uid, m->m_gid); + (int) m->m_uid, (int) m->m_gid); for (j = '\0'; j <= '\177'; j++) if (bitnset(j, m->m_flags)) (void) putchar(j); @@ -1322,17 +1356,17 @@ struct resolverflags long rf_bits; /* bits to set/clear */ } ResolverFlags[] = { - "debug", RES_DEBUG, - "aaonly", RES_AAONLY, - "usevc", RES_USEVC, - "primary", RES_PRIMARY, - "igntc", RES_IGNTC, - "recurse", RES_RECURSE, - "defnames", RES_DEFNAMES, - "stayopen", RES_STAYOPEN, - "dnsrch", RES_DNSRCH, - "true", 0, /* to avoid error on old syntax */ - NULL, 0 + { "debug", RES_DEBUG }, + { "aaonly", RES_AAONLY }, + { "usevc", RES_USEVC }, + { "primary", RES_PRIMARY }, + { "igntc", RES_IGNTC }, + { "recurse", RES_RECURSE }, + { "defnames", RES_DEFNAMES }, + { "stayopen", RES_STAYOPEN }, + { "dnsrch", RES_DNSRCH }, + { "true", 0 }, /* avoid error on old syntax */ + { NULL, 0 } }; #endif @@ -1344,108 +1378,112 @@ struct optioninfo bool o_safe; /* safe for random people to use */ } OptionTab[] = { - "SevenBitInput", '7', TRUE, + { "SevenBitInput", '7', TRUE }, #if MIME8TO7 - "EightBitMode", '8', TRUE, + { "EightBitMode", '8', TRUE }, #endif - "AliasFile", 'A', FALSE, - "AliasWait", 'a', FALSE, - "BlankSub", 'B', FALSE, - "MinFreeBlocks", 'b', TRUE, - "CheckpointInterval", 'C', TRUE, - "HoldExpensive", 'c', FALSE, - "AutoRebuildAliases", 'D', FALSE, - "DeliveryMode", 'd', TRUE, - "ErrorHeader", 'E', FALSE, - "ErrorMode", 'e', TRUE, - "TempFileMode", 'F', FALSE, - "SaveFromLine", 'f', FALSE, - "MatchGECOS", 'G', FALSE, - "HelpFile", 'H', FALSE, - "MaxHopCount", 'h', FALSE, - "ResolverOptions", 'I', FALSE, - "IgnoreDots", 'i', TRUE, - "ForwardPath", 'J', FALSE, - "SendMimeErrors", 'j', TRUE, - "ConnectionCacheSize", 'k', FALSE, - "ConnectionCacheTimeout", 'K', FALSE, - "UseErrorsTo", 'l', FALSE, - "LogLevel", 'L', FALSE, - "MeToo", 'm', TRUE, - "CheckAliases", 'n', FALSE, - "OldStyleHeaders", 'o', TRUE, - "DaemonPortOptions", 'O', FALSE, - "PrivacyOptions", 'p', TRUE, - "PostmasterCopy", 'P', FALSE, - "QueueFactor", 'q', FALSE, - "QueueDirectory", 'Q', FALSE, - "DontPruneRoutes", 'R', FALSE, - "Timeout", 'r', TRUE, - "StatusFile", 'S', FALSE, - "SuperSafe", 's', TRUE, - "QueueTimeout", 'T', FALSE, - "TimeZoneSpec", 't', FALSE, - "UserDatabaseSpec", 'U', FALSE, - "DefaultUser", 'u', FALSE, - "FallbackMXhost", 'V', FALSE, - "Verbose", 'v', TRUE, - "TryNullMXList", 'w', TRUE, - "QueueLA", 'x', FALSE, - "RefuseLA", 'X', FALSE, - "RecipientFactor", 'y', FALSE, - "ForkEachJob", 'Y', FALSE, - "ClassFactor", 'z', FALSE, - "RetryFactor", 'Z', FALSE, + { "AliasFile", 'A', FALSE }, + { "AliasWait", 'a', FALSE }, + { "BlankSub", 'B', FALSE }, + { "MinFreeBlocks", 'b', TRUE }, + { "CheckpointInterval", 'C', TRUE }, + { "HoldExpensive", 'c', FALSE }, + { "AutoRebuildAliases", 'D', FALSE }, + { "DeliveryMode", 'd', TRUE }, + { "ErrorHeader", 'E', FALSE }, + { "ErrorMode", 'e', TRUE }, + { "TempFileMode", 'F', FALSE }, + { "SaveFromLine", 'f', FALSE }, + { "MatchGECOS", 'G', FALSE }, + { "HelpFile", 'H', FALSE }, + { "MaxHopCount", 'h', FALSE }, + { "ResolverOptions", 'I', FALSE }, + { "IgnoreDots", 'i', TRUE }, + { "ForwardPath", 'J', FALSE }, + { "SendMimeErrors", 'j', TRUE }, + { "ConnectionCacheSize", 'k', FALSE }, + { "ConnectionCacheTimeout", 'K', FALSE }, + { "UseErrorsTo", 'l', FALSE }, + { "LogLevel", 'L', TRUE }, + { "MeToo", 'm', TRUE }, + { "CheckAliases", 'n', FALSE }, + { "OldStyleHeaders", 'o', TRUE }, + { "DaemonPortOptions", 'O', FALSE }, + { "PrivacyOptions", 'p', TRUE }, + { "PostmasterCopy", 'P', FALSE }, + { "QueueFactor", 'q', FALSE }, + { "QueueDirectory", 'Q', FALSE }, + { "DontPruneRoutes", 'R', FALSE }, + { "Timeout", 'r', FALSE }, + { "StatusFile", 'S', FALSE }, + { "SuperSafe", 's', TRUE }, + { "QueueTimeout", 'T', FALSE }, + { "TimeZoneSpec", 't', FALSE }, + { "UserDatabaseSpec", 'U', FALSE }, + { "DefaultUser", 'u', FALSE }, + { "FallbackMXhost", 'V', FALSE }, + { "Verbose", 'v', TRUE }, + { "TryNullMXList", 'w', FALSE }, + { "QueueLA", 'x', FALSE }, + { "RefuseLA", 'X', FALSE }, + { "RecipientFactor", 'y', FALSE }, + { "ForkEachJob", 'Y', FALSE }, + { "ClassFactor", 'z', FALSE }, + { "RetryFactor", 'Z', FALSE }, #define O_QUEUESORTORD 0x81 - "QueueSortOrder", O_QUEUESORTORD, TRUE, + { "QueueSortOrder", O_QUEUESORTORD, TRUE }, #define O_HOSTSFILE 0x82 - "HostsFile", O_HOSTSFILE, FALSE, + { "HostsFile", O_HOSTSFILE, FALSE }, #define O_MQA 0x83 - "MinQueueAge", O_MQA, TRUE, -#define O_MHSA 0x84 -/* - "MaxHostStatAge", O_MHSA, TRUE, -*/ + { "MinQueueAge", O_MQA, TRUE }, #define O_DEFCHARSET 0x85 - "DefaultCharSet", O_DEFCHARSET, TRUE, + { "DefaultCharSet", O_DEFCHARSET, TRUE }, #define O_SSFILE 0x86 - "ServiceSwitchFile", O_SSFILE, FALSE, + { "ServiceSwitchFile", O_SSFILE, FALSE }, #define O_DIALDELAY 0x87 - "DialDelay", O_DIALDELAY, TRUE, + { "DialDelay", O_DIALDELAY, TRUE }, #define O_NORCPTACTION 0x88 - "NoRecipientAction", O_NORCPTACTION, TRUE, + { "NoRecipientAction", O_NORCPTACTION, TRUE }, #define O_SAFEFILEENV 0x89 - "SafeFileEnvironment", O_SAFEFILEENV, FALSE, + { "SafeFileEnvironment", O_SAFEFILEENV, FALSE }, #define O_MAXMSGSIZE 0x8a - "MaxMessageSize", O_MAXMSGSIZE, FALSE, + { "MaxMessageSize", O_MAXMSGSIZE, FALSE }, #define O_COLONOKINADDR 0x8b - "ColonOkInAddr", O_COLONOKINADDR, TRUE, + { "ColonOkInAddr", O_COLONOKINADDR, TRUE }, #define O_MAXQUEUERUN 0x8c - "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, + { "MaxQueueRunSize", O_MAXQUEUERUN, TRUE }, #define O_MAXCHILDREN 0x8d -/* - "MaxDaemonChildren", O_MAXCHILDREN, FALSE, -*/ + { "MaxDaemonChildren", O_MAXCHILDREN, FALSE }, #define O_KEEPCNAMES 0x8e - "DontExpandCnames", O_KEEPCNAMES, FALSE, + { "DontExpandCnames", O_KEEPCNAMES, FALSE }, #define O_MUSTQUOTE 0x8f -/* - "MustQuoteChars", O_MUSTQUOTE, FALSE, -*/ + { "MustQuoteChars", O_MUSTQUOTE, FALSE }, #define O_SMTPGREETING 0x90 - "SmtpGreetingMessage", O_SMTPGREETING, FALSE, + { "SmtpGreetingMessage", O_SMTPGREETING, FALSE }, #define O_UNIXFROM 0x91 - "UnixFromLine", O_UNIXFROM, FALSE, + { "UnixFromLine", O_UNIXFROM, FALSE }, #define O_OPCHARS 0x92 - "OperatorChars", O_OPCHARS, FALSE, + { "OperatorChars", O_OPCHARS, FALSE }, #define O_DONTINITGRPS 0x93 - "DontInitGroups", O_DONTINITGRPS, TRUE, + { "DontInitGroups", O_DONTINITGRPS, FALSE }, #define O_SLFH 0x94 -#ifdef LOTUS_NOTES_HACK - "SingleLineFromHeader", O_SLFH, TRUE, -#endif - - NULL, '\0', FALSE, + { "SingleLineFromHeader", O_SLFH, TRUE }, +#define O_ABH 0x95 + { "AllowBogusHELO", O_ABH, TRUE }, +#define O_CONNTHROT 0x97 + { "ConnectionRateThrottle", O_CONNTHROT, FALSE }, +#define O_UGW 0x99 + { "UnsafeGroupWrites", O_UGW, FALSE }, +#define O_DBLBOUNCE 0x9a + { "DoubleBounceAddress", O_DBLBOUNCE, FALSE }, +#define O_HSDIR 0x9b + { "HostStatusDirectory", O_HSDIR, FALSE }, +#define O_SINGTHREAD 0x9c + { "SingleThreadDelivery", O_SINGTHREAD, FALSE }, +#define O_RUNASUSER 0x9d + { "RunAsUser", O_RUNASUSER, FALSE }, + + { NULL, '\0', FALSE } }; @@ -1461,12 +1499,18 @@ setoption(opt, val, safe, sticky, e) register char *p; register struct optioninfo *o; char *subopt; + int mid; + auto char *ep; char buf[50]; extern bool atobool(); extern time_t convtime(); extern int QueueLA; extern int RefuseLA; extern bool Warn_Q_option; + extern void setalias __P((char *)); + extern int atooct __P((char *)); + extern void setdefuser __P((void)); + extern void setdaemonoptions __P((char *)); errno = 0; if (opt == ' ') @@ -1684,7 +1728,7 @@ setoption(opt, val, safe, sticky, e) case SM_QUEUE: /* queue only */ case SM_DEFER: /* queue only and defer map lookups */ -#ifndef QUEUE +#if !QUEUE syserr("need QUEUE to set -odqueue or -oddefer"); #endif /* QUEUE */ /* fall through..... */ @@ -1805,7 +1849,7 @@ setoption(opt, val, safe, sticky, e) } if (tTd(8, 2)) printf("_res.options = %x, HasWildcardMX = %d\n", - _res.options, HasWildcardMX); + (u_int) _res.options, HasWildcardMX); #else usrerr("name server (I option) specified but BIND not compiled in"); #endif @@ -1843,10 +1887,11 @@ setoption(opt, val, safe, sticky, e) break; case 'M': /* define macro */ - p = newstr(&val[1]); + mid = macid(val, &ep); + p = newstr(ep); if (!safe) cleanstrcpy(p, p, MAXNAME); - define(val[0], p, CurEnv); + define(mid, p, CurEnv); sticky = FALSE; break; @@ -1861,7 +1906,7 @@ setoption(opt, val, safe, sticky, e) /* 'N' available -- was "net name" */ case 'O': /* daemon options */ -#ifdef DAEMON +#if DAEMON setdaemonoptions(val); #else syserr("DaemonPortOptions (O option) set but DAEMON not compiled in"); @@ -1986,6 +2031,14 @@ setoption(opt, val, safe, sticky, e) DefGid = pw->pw_gid; } } + +#ifdef UID_MAX + if (DefUid > UID_MAX) + { + syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", + DefUid, UID_MAX); + } +#endif setdefuser(); /* handle the group if it is there */ @@ -1995,7 +2048,8 @@ setoption(opt, val, safe, sticky, e) goto g_opt; case 'V': /* fallback MX host */ - FallBackMX = newstr(val); + if (val[0] != '\0') + FallBackMX = newstr(val); break; case 'v': /* run in verbose mode */ @@ -2045,6 +2099,11 @@ setoption(opt, val, safe, sticky, e) QueueSortOrder = QS_BYPRIORITY; break; + case 't': /* Submission time */ + case 'T': + QueueSortOrder = QS_BYTIME; + break; + default: syserr("Invalid queue sort order \"%s\"", val); } @@ -2058,10 +2117,6 @@ setoption(opt, val, safe, sticky, e) MinQueueAge = convtime(val, 'm'); break; - case O_MHSA: /* maximum age of cached host status */ - MaxHostStatAge = convtime(val, 'm'); - break; - case O_DEFCHARSET: /* default character set for mimefying */ DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); break; @@ -2115,21 +2170,21 @@ setoption(opt, val, safe, sticky, e) case O_MUSTQUOTE: /* must quote these characters in phrases */ strcpy(buf, "@,;:\\()[]"); - if (strlen(val) < sizeof buf - 10) + if (strlen(val) < (SIZE_T) sizeof buf - 10) strcat(buf, val); MustQuoteChars = newstr(buf); break; case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */ - SmtpGreeting = newstr(munchstring(val, NULL)); + SmtpGreeting = newstr(munchstring(val, NULL, '\0')); break; case O_UNIXFROM: /* UNIX From_ line (old $l macro) */ - UnixFromLine = newstr(munchstring(val, NULL)); + UnixFromLine = newstr(munchstring(val, NULL, '\0')); break; case O_OPCHARS: /* operator characters (old $o macro) */ - OperatorChars = newstr(munchstring(val, NULL)); + OperatorChars = newstr(munchstring(val, NULL, '\0')); break; case O_DONTINITGRPS: /* don't call initgroups(3) */ @@ -2140,6 +2195,75 @@ setoption(opt, val, safe, sticky, e) SingleLineFromHeader = atobool(val); break; + case O_ABH: /* allow HELO commands with syntax errors */ + AllowBogusHELO = atobool(val); + break; + + case O_CONNTHROT: /* connection rate throttle */ + ConnRateThrottle = atoi(val); + break; + + case O_UGW: /* group writable files are unsafe */ + UnsafeGroupWrites = atobool(val); + break; + + case O_DBLBOUNCE: /* address to which to send double bounces */ + if (val[0] != '\0') + DoubleBounceAddr = newstr(val); + else + syserr("readcf: option DoubleBounceAddress: value required"); + break; + + case O_HSDIR: /* persistent host status directory */ + if (val[0] != '\0') + HostStatDir = newstr(val); + break; + + case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ + SingleThreadDelivery = atobool(val); + break; + + case O_RUNASUSER: /* run bulk of code as this user */ + for (p = val; *p != '\0'; p++) + { + if (*p == '.' || *p == '/' || *p == ':') + { + *p++ = '\0'; + break; + } + } + if (isascii(*val) && isdigit(*val)) + RunAsUid = atoi(val); + else + { + register struct passwd *pw; + + pw = sm_getpwnam(val); + if (pw == NULL) + syserr("readcf: option RunAsUser: unknown user %s", val); + else + { + RunAsUid = pw->pw_uid; + RunAsGid = pw->pw_gid; + } + } + if (*p == '\0') + break; + if (isascii(*p) && isdigit(*p)) + DefGid = atoi(p); + else + { + register struct group *gr; + + gr = getgrnam(p); + if (gr == NULL) + syserr("readcf: option RunAsUser: unknown group %s", + p); + else + RunAsGid = gr->gr_gid; + } + break; + default: if (tTd(37, 1)) { @@ -2249,7 +2373,7 @@ makemapentry(line) if (tTd(37, 5)) { - printf("map %s, class %s, flags %x, file %s,\n", + printf("map %s, class %s, flags %lx, file %s,\n", s->s_map.map_mname, s->s_map.map_class->map_cname, s->s_map.map_mflags, s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); @@ -2327,10 +2451,7 @@ strtorwset(p, endp, stabmode) *p = delim; if (s == NULL) - { - syserr("unknown ruleset %s", q); return -1; - } if (stabmode == ST_ENTER && delim == '=') { @@ -2368,7 +2489,7 @@ strtorwset(p, endp, stabmode) if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) { syserr("%s: ruleset changed value (old %d, new %d)", - q, ruleset, s->s_ruleset); + q, s->s_ruleset, ruleset); ruleset = s->s_ruleset; } else if (ruleset > 0) @@ -2403,6 +2524,8 @@ inittimeouts(val) register char *p; extern time_t convtime(); + if (tTd(37, 2)) + printf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); if (val == NULL) { TimeOuts.to_connect = (time_t) 0 SECONDS; @@ -2423,6 +2546,24 @@ inittimeouts(val) TimeOuts.to_ident = (time_t) 0 SECONDS; #endif TimeOuts.to_fileopen = (time_t) 60 SECONDS; + if (tTd(37, 5)) + { + printf("Timeouts:\n"); + printf(" connect = %ld\n", TimeOuts.to_connect); + printf(" initial = %ld\n", TimeOuts.to_initial); + printf(" helo = %ld\n", TimeOuts.to_helo); + printf(" mail = %ld\n", TimeOuts.to_mail); + printf(" rcpt = %ld\n", TimeOuts.to_rcpt); + printf(" datainit = %ld\n", TimeOuts.to_datainit); + printf(" datablock = %ld\n", TimeOuts.to_datablock); + printf(" datafinal = %ld\n", TimeOuts.to_datafinal); + printf(" rset = %ld\n", TimeOuts.to_rset); + printf(" quit = %ld\n", TimeOuts.to_quit); + printf(" nextcommand = %ld\n", TimeOuts.to_nextcommand); + printf(" miscshort = %ld\n", TimeOuts.to_miscshort); + printf(" ident = %ld\n", TimeOuts.to_ident); + printf(" fileopen = %ld\n", TimeOuts.to_fileopen); + } return; } @@ -2482,6 +2623,9 @@ settimeout(name, val) time_t to; extern time_t convtime(); + if (tTd(37, 2)) + printf("settimeout(%s = %s)\n", name, val); + to = convtime(val, 'm'); p = strchr(name, '.'); if (p != NULL) @@ -2515,6 +2659,8 @@ settimeout(name, val) TimeOuts.to_fileopen = to; else if (strcasecmp(name, "connect") == 0) TimeOuts.to_connect = to; + else if (strcasecmp(name, "iconnect") == 0) + TimeOuts.to_iconnect = to; else if (strcasecmp(name, "queuewarn") == 0) { to = convtime(val, 'h'); @@ -2551,6 +2697,8 @@ settimeout(name, val) else syserr("settimeout: invalid queuereturn subtimeout %s", p); } + else if (strcasecmp(name, "hoststatus") == 0) + MciInfoTimeout = convtime(val, 'm'); else syserr("settimeout: invalid timeout %s", name); } diff --git a/usr.sbin/sendmail/src/recipient.c b/usr.sbin/sendmail/src/recipient.c index 4675247e11c..92e6bc379c1 100644 --- a/usr.sbin/sendmail/src/recipient.c +++ b/usr.sbin/sendmail/src/recipient.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)recipient.c 8.108.1.1 (Berkeley) 9/12/96"; +static char sccsid[] = "@(#)recipient.c 8.118 (Berkeley) 12/1/96"; #endif /* not lint */ # include "sendmail.h" @@ -241,7 +241,7 @@ recipient(a, sendq, aliaslevel, e) int i; char *buf; char buf0[MAXNAME + 1]; /* unquoted image of the user name */ - extern int safefile(); + extern void alias __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); e->e_to = a->q_paddr; m = a->q_mailer; @@ -267,7 +267,7 @@ recipient(a, sendq, aliaslevel, e) if (aliaslevel > MaxAliasRecursion) { a->q_status = "5.4.6"; - usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", + usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max)", aliaslevel, MaxAliasRecursion); return (a); } @@ -474,14 +474,16 @@ recipient(a, sendq, aliaslevel, e) if (tTd(29, 5)) { - printf("recipient: testing local? cl=%d, rr5=%x\n\t", - ConfigLevel, RewriteRules[5]); + printf("recipient: testing local? cl=%d, rr5=%lx\n\t", + ConfigLevel, (u_long) RewriteRules[5]); printaddr(a, FALSE); } if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && ConfigLevel >= 2 && RewriteRules[5] != NULL && bitnset(M_TRYRULESET5, m->m_flags)) { + extern void maplocaluser __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); + maplocaluser(a, sendq, aliaslevel + 1, e); } @@ -495,7 +497,7 @@ recipient(a, sendq, aliaslevel, e) { auto bool fuzzy; register struct passwd *pw; - extern struct passwd *finduser(); + extern void forward __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); /* warning -- finduser may trash buf */ pw = finduser(buf, &fuzzy); @@ -599,7 +601,7 @@ recipient(a, sendq, aliaslevel, e) if (aliaslevel == 0) { int nrcpts = 0; - ADDRESS *only; + ADDRESS *only = NULL; for (q = *sendq; q != NULL; q = q->q_next) { @@ -738,8 +740,7 @@ finduser(name, fuzzyp) { if (tTd(29, 4)) printf("found (case wrapped)\n"); - *fuzzyp = TRUE; - return pw; + break; } # endif @@ -749,17 +750,22 @@ finduser(name, fuzzyp) if (tTd(29, 4)) printf("fuzzy matches %s\n", pw->pw_name); message("sending to login name %s", pw->pw_name); - *fuzzyp = TRUE; - return (pw); + break; } } - if (tTd(29, 4)) + if (pw != NULL) + *fuzzyp = TRUE; + else if (tTd(29, 4)) printf("no fuzzy match found\n"); +# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */ + endpwent(); +# endif + return pw; #else if (tTd(29, 4)) printf("not found (fuzzy disabled)\n"); + return NULL; #endif - return (NULL); } /* ** WRITABLE -- predicate returning if the file is writable. @@ -901,7 +907,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) volatile gid_t savedgid, gid; char *volatile uname; int rval = 0; - int sfflags = SFF_REGONLY; + volatile int sfflags = SFF_REGONLY; struct stat st; char buf[MAXLINE]; #ifdef _POSIX_CHOWN_RESTRICTED @@ -926,7 +932,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) if (tTd(27, 2)) printf("include(%s)\n", fname); if (tTd(27, 4)) - printf(" ruid=%d euid=%d\n", getuid(), geteuid()); + printf(" ruid=%d euid=%d\n", (int) getuid(), (int) geteuid()); if (tTd(27, 14)) { printf("ctladdr "); @@ -934,7 +940,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) } if (tTd(27, 9)) - printf("include: old uid = %d/%d\n", getuid(), geteuid()); + printf("include: old uid = %d/%d\n", + (int) getuid(), (int) geteuid()); if (forwarding) sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOSLINK; @@ -979,7 +986,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) #endif if (tTd(27, 9)) - printf("include: new uid = %d/%d\n", getuid(), geteuid()); + printf("include: new uid = %d/%d\n", + (int) getuid(), (int) geteuid()); /* ** If home directory is remote mounted but server is down, @@ -1007,7 +1015,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) /* don't use this :include: file */ if (tTd(27, 4)) printf("include: not safe (uid=%d): %s\n", - uid, errstring(rval)); + (int) uid, errstring(rval)); } else { @@ -1047,7 +1055,8 @@ resetuid: #endif if (tTd(27, 9)) - printf("include: reset uid = %d/%d\n", getuid(), geteuid()); + printf("include: reset uid = %d/%d\n", + (int) getuid(), (int) geteuid()); if (rval == EOPENTIMEOUT) usrerr("451 open timeout on %s", fname); @@ -1077,7 +1086,7 @@ resetuid: ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; ctladdr->q_ruser = ca->q_ruser; } - else + else if (!forwarding) { register struct passwd *pw; @@ -1122,19 +1131,21 @@ resetuid: /* ** Check to see if some bad guy can write this file ** - ** This should really do something clever with group - ** permissions; currently we just view world writable - ** as unsafe. Also, we don't check for writable + ** Group write checking could be more clever, e.g., + ** guessing as to which groups are actually safe ("sys" + ** may be; "user" probably is not). + ** Also, we don't check for writable ** directories in the path. We've got to leave ** something for the local sysad to do. */ - if (bitset(S_IWOTH, st.st_mode)) + if (bitset(S_IWOTH | (UnsafeGroupWrites ? S_IWGRP : 0), st.st_mode)) { #ifdef LOG if (LogLevel >= 12) - syslog(LOG_INFO, "%s: world writable %s file, marked unsafe", + syslog(LOG_INFO, "%s: %s writable %s file, marked unsafe", shortenstring(fname, 203), + bitset(S_IWOTH, st.st_mode) ? "world" : "group", forwarding ? "forward" : ":include:"); #endif ctladdr->q_flags |= QUNSAFEADDR; diff --git a/usr.sbin/sendmail/src/savemail.c b/usr.sbin/sendmail/src/savemail.c index b7098789581..4abad53a836 100644 --- a/usr.sbin/sendmail/src/savemail.c +++ b/usr.sbin/sendmail/src/savemail.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)savemail.c 8.87.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)savemail.c 8.101 (Berkeley) 11/24/96"; #endif /* not lint */ # include "sendmail.h" @@ -86,7 +86,7 @@ savemail(e, sendbody) auto ADDRESS *q = NULL; register char *p; MCI mcibuf; - int sfflags; + int flags; char buf[MAXLINE+1]; extern char *ttypath(); typedef int (*fnptr)(); @@ -283,7 +283,9 @@ savemail(e, sendbody) break; } if (returntosender(e->e_message, e->e_errorqueue, - sendbody, e) == 0) + sendbody ? RTSF_SEND_BODY + : RTSF_NO_BODY, + e) == 0) { state = ESM_DONE; break; @@ -299,14 +301,17 @@ savemail(e, sendbody) */ q = NULL; - if (sendtolist("postmaster", NULL, &q, 0, e) <= 0) + if (sendtolist(DoubleBounceAddr, NULL, &q, 0, e) <= 0) { - syserr("553 cannot parse postmaster!"); + syserr("553 cannot parse %s!", DoubleBounceAddr); ExitStat = EX_SOFTWARE; state = ESM_USRTMP; break; } - if (returntosender(e->e_message, q, sendbody, e) == 0) + flags = RTSF_PM_BOUNCE; + if (sendbody) + flags |= RTSF_SEND_BODY; + if (returntosender(e->e_message, q, flags, e) == 0) { state = ESM_DONE; break; @@ -344,9 +349,9 @@ savemail(e, sendbody) /* we have a home directory; write dead.letter */ define('z', p, e); expand("\201z/dead.letter", buf, sizeof buf, e); - sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; + flags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; e->e_to = buf; - if (mailfile(buf, NULL, sfflags, e) == EX_OK) + if (mailfile(buf, NULL, flags, e) == EX_OK) { bool oldverb = Verbose; @@ -378,10 +383,10 @@ savemail(e, sendbody) snprintf(buf, sizeof buf, "%sdead.letter", _PATH_VARTMP); - sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT; - if (!writable(buf, NULL, sfflags) || + flags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT; + if (!writable(buf, NULL, flags) || (fp = safefopen(buf, O_WRONLY|O_CREAT|O_APPEND, - FileMode, sfflags)) == NULL) + FileMode, flags)) == NULL) { state = ESM_PANIC; break; @@ -398,7 +403,9 @@ savemail(e, sendbody) (*e->e_putbody)(&mcibuf, e, NULL); putline("\n", &mcibuf); (void) fflush(fp); - if (!ferror(fp)) + if (ferror(fp)) + state = ESM_PANIC; + else { bool oldverb = Verbose; @@ -410,9 +417,7 @@ savemail(e, sendbody) syslog(LOG_NOTICE, "Saved message in %s", buf); #endif state = ESM_DONE; - break; } - state = ESM_PANIC; (void) xfclose(fp, "savemail", buf); break; @@ -434,8 +439,10 @@ savemail(e, sendbody) ** Parameters: ** msg -- the explanatory message. ** returnq -- the queue of people to send the message to. -** sendbody -- if TRUE, also send back the body of the -** message; otherwise just send the header. +** flags -- flags tweaking the operation: +** RTSF_SENDBODY -- include body of message (otherwise +** just send the header). +** RTSF_PMBOUNCE -- this is a postmaster bounce. ** e -- the current envelope. ** ** Returns: @@ -451,10 +458,10 @@ savemail(e, sendbody) #define ERRORFUDGE 100 /* nominal size of error message text */ int -returntosender(msg, returnq, sendbody, e) +returntosender(msg, returnq, flags, e) char *msg; ADDRESS *returnq; - bool sendbody; + int flags; register ENVELOPE *e; { register ENVELOPE *ee; @@ -474,8 +481,8 @@ returntosender(msg, returnq, sendbody, e) if (tTd(6, 1)) { - printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=", - msg, returndepth, e); + printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%lx, returnq=", + msg, returndepth, (u_long) e); printaddr(returnq, TRUE); if (tTd(6, 20)) { @@ -509,16 +516,21 @@ returntosender(msg, returnq, sendbody, e) ee->e_flags &= ~EF_OLDSTYLE; ee->e_sendqueue = returnq; ee->e_msgsize = ERRORFUDGE; - if (sendbody) + if (bitset(RTSF_SEND_BODY, flags)) ee->e_msgsize += e->e_msgsize; else ee->e_flags |= EF_NO_BODY_RETN; initsys(ee); for (q = returnq; q != NULL; q = q->q_next) { + extern bool pruneroute __P((char *)); + if (bitset(QBADADDR, q->q_flags)) continue; + q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); + q->q_flags |= QPINGONFAILURE; + if (!DontPruneRoutes && pruneroute(q->q_paddr)) { register ADDRESS *p; @@ -543,8 +555,10 @@ returntosender(msg, returnq, sendbody, e) { if (bitset(EF_RESPONSE|EF_WARNING, e->e_flags)) p = "return to sender"; - else + else if (bitset(RTSF_PM_BOUNCE, flags)) p = "postmaster notify"; + else + p = "DSN"; syslog(LOG_INFO, "%s: %s: %s: %s", e->e_id, ee->e_id, p, shortenstring(msg, 203)); } @@ -589,6 +603,13 @@ returntosender(msg, returnq, sendbody, e) addheader("Subject", msg, &ee->e_header); p = "return-receipt"; } + else if (bitset(RTSF_PM_BOUNCE, flags)) + { + snprintf(buf, sizeof buf, "Postmaster notify: %.*s", + sizeof buf - 20, msg); + addheader("Subject", buf, &ee->e_header); + p = "postmaster-notification"; + } else { snprintf(buf, sizeof buf, "Returned mail: %.*s", @@ -608,6 +629,8 @@ returntosender(msg, returnq, sendbody, e) returndepth--; return (-1); } + ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); + ee->e_from.q_flags |= QPINGONFAILURE; ee->e_sender = ee->e_from.q_paddr; /* push state into submessage */ @@ -623,7 +646,7 @@ returntosender(msg, returnq, sendbody, e) sendall(ee, SM_DEFAULT); /* restore state */ - dropenvelope(ee); + dropenvelope(ee, TRUE); CurEnv = oldcur; returndepth--; @@ -647,7 +670,6 @@ returntosender(msg, returnq, sendbody, e) ** mci -- the mailer connection information. ** e -- the envelope we are working in. ** separator -- any possible MIME separator. -** flags -- to modify the behaviour. ** ** Returns: ** none @@ -667,8 +689,8 @@ errbody(mci, e, separator) register ADDRESS *q; bool printheader; bool sendbody; + bool pm_notify; char buf[MAXLINE]; - extern char *xuntextify(); if (bitset(MCIF_INHEADER, mci->mci_flags)) { @@ -699,10 +721,17 @@ errbody(mci, e, separator) ** Output introductory information. */ - for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) - if (bitset(QBADADDR, q->q_flags)) - break; - if (q == NULL && + pm_notify = FALSE; + p = hvalue("subject", e->e_header); + if (p != NULL && strncmp(p, "Postmaster ", 11) == 0) + pm_notify = TRUE; + else + { + for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) + if (bitset(QBADADDR, q->q_flags)) + break; + } + if (!pm_notify && q == NULL && !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags)) { putline(" **********************************************", @@ -757,16 +786,63 @@ errbody(mci, e, separator) printheader = TRUE; for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) { - if (bitset(QBADADDR, q->q_flags)) + if (!bitset(QBADADDR, q->q_flags) || + !bitset(QPINGONFAILURE, q->q_flags)) + continue; + + if (printheader) { - if (!bitset(QPINGONFAILURE, q->q_flags)) - continue; - p = "unrecoverable error"; + putline(" ----- The following addresses had permanent fatal errors -----", + mci); + printheader = FALSE; } - else if (!bitset(QPRIMARY, q->q_flags)) + + snprintf(buf, sizeof buf, "%s", shortenstring(q->q_paddr, 203)); + putline(buf, mci); + if (q->q_alias != NULL) + { + snprintf(buf, sizeof buf, " (expanded from: %s)", + shortenstring(q->q_alias->q_paddr, 203)); + putline(buf, mci); + } + } + if (!printheader) + putline("", mci); + + printheader = TRUE; + for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) + { + if (bitset(QBADADDR, q->q_flags) || + !bitset(QPRIMARY, q->q_flags) || + !bitset(QDELAYED, q->q_flags)) + continue; + + if (printheader) + { + putline(" ----- The following addresses had transient non-fatal errors -----", + mci); + printheader = FALSE; + } + + snprintf(buf, sizeof buf, "%s", shortenstring(q->q_paddr, 203)); + putline(buf, mci); + if (q->q_alias != NULL) + { + snprintf(buf, sizeof buf, " (expanded from: %s)", + shortenstring(q->q_alias->q_paddr, 203)); + putline(buf, mci); + } + } + if (!printheader) + putline("", mci); + + printheader = TRUE; + for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) + { + if (bitset(QBADADDR, q->q_flags) || + !bitset(QPRIMARY, q->q_flags) || + bitset(QDELAYED, q->q_flags)) continue; - else if (bitset(QDELAYED, q->q_flags)) - p = "transient failure"; else if (!bitset(QPINGONSUCCESS, q->q_flags)) continue; else if (bitset(QRELAYED, q->q_flags)) @@ -785,7 +861,7 @@ errbody(mci, e, separator) if (printheader) { - putline(" ----- The following addresses have delivery notifications -----", + putline(" ----- The following addresses had successful delivery notifications -----", mci); printheader = FALSE; } @@ -801,7 +877,7 @@ errbody(mci, e, separator) } } if (!printheader) - putline("\n", mci); + putline("", mci); /* ** Output transcript of errors @@ -1164,14 +1240,16 @@ smtptodsn(smtpstat) ** ** Parameters: ** t -- the text to convert. +** taboo -- additional characters that must be encoded. ** ** Returns: ** The xtext-ified version of the same string. */ char * -xtextify(t) +xtextify(t, taboo) register char *t; + char *taboo; { register char *p; int l; @@ -1179,6 +1257,9 @@ xtextify(t) static char *bp = NULL; static int bplen = 0; + if (taboo == NULL) + taboo = ""; + /* figure out how long this xtext will have to be */ nbogus = l = 0; for (p = t; *p != '\0'; p++) @@ -1186,7 +1267,8 @@ xtextify(t) register int c = (*p & 0xff); /* ASCII dependence here -- this is the way the spec words it */ - if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') + if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' || + strchr(taboo, c) != NULL) nbogus++; l++; } @@ -1209,7 +1291,8 @@ xtextify(t) register int c = (*t++ & 0xff); /* ASCII dependence here -- this is the way the spec words it */ - if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') + if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' || + strchr(taboo, c) != NULL) { *p++ = '+'; *p++ = "0123456789abcdef"[c >> 4]; @@ -1298,6 +1381,7 @@ xuntextify(t) c -= 'a' - 10; *p++ |= c; } + *p = '\0'; return bp; } /* diff --git a/usr.sbin/sendmail/src/sendmail.8 b/usr.sbin/sendmail/src/sendmail.8 index 5b48ffcda9a..f7c87507a2d 100644 --- a/usr.sbin/sendmail/src/sendmail.8 +++ b/usr.sbin/sendmail/src/sendmail.8 @@ -29,14 +29,14 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)sendmail.8 8.6 (Berkeley) 5/27/95 +.\" @(#)sendmail.8 8.10 (Berkeley) 9/20/96 .\" -.Dd May 27, 1995 +.Dd September 20, 1996 .Dt SENDMAIL 8 .Os BSD 4 .Sh NAME .Nm sendmail -.Nd send mail over the internet +.Nd an electronic mail transport agent .Sh SYNOPSIS .Nm sendmail .Op Ar flags @@ -108,6 +108,14 @@ listening on socket 25 for incoming connections. This is normally run from .Pa /etc/rc . +.It Fl bD +Same as +.Fl bd +except runs in foreground. +.It Fl bh +Print the persistent host status database. +.It Fl bH +Purge the persistent host status database. .It Fl bi Initialize the alias database. .It Fl bm @@ -165,14 +173,41 @@ the mail is returned with an error message, the victim of an aliasing loop. If not specified, ``Received:'' lines in the message are counted. +.It Fl i +Ignore dots alone on lines by themselves in incoming messages. +This should be set if you are reading data from a file. +.It Fl N Ar dsn +Set delivery status notification conditions to +.Ar dsn, +which can be +.Ql never +for no notifications +or a comma separated list of the values +.Ql failure +to be notified if delivery failed, +.Ql delay +to be notified if delivery is delayed, and +.Ql success +to be notified when the message is successfully delivered. .It Fl n Don't do aliasing. +.It Fl O Ar option Ns = Ns Em value +Set option +.Ar option +to the specified +.Em value . +This form uses long names. +See below for more details. .It Fl o Ns Ar x Em value Set option .Ar x to the specified .Em value . -Options are described below. +This form uses single character names only. +The short names are not described in this manual page; +see the +.%T "Sendmail Installation and Operation Guide" +for details. .It Fl p Ns Ar protocol Set the name of the protocol used to receive the message. This can be a simple protocol name such as ``UUCP'' @@ -221,6 +256,16 @@ as a substring of one of the recipients. Limit processed jobs to those containing .Ar substr as a substring of the sender. +.It Fl R Ar return +Set the amount of the message to be returned +if the message bounces. +The +.Ar return +parameter can be +.Ql full +to return the entire message or +.Ql hdrs +to return only the headers. .It Fl r Ns Ar name An alternate and obsolete form of the .Fl f @@ -234,6 +279,22 @@ that is, they will .Em not receive copies even if listed in the message header. +.It Fl U +Initial (user) submission. +This should +.Em always +be set when called from a user agent such as +.Nm Mail +or +.Nm exmh +and +.Em never +be set when called by a network delivery agent such as +.Nm rmail . +.It Fl V Ar envid +Set the original envelope id. +This is propogated across SMTP to servers that support DSNs +and is returned in DSN-compliant error messages. .It Fl v Go into verbose mode. Alias expansions will be announced, etc. @@ -249,22 +310,25 @@ Normally these will only be used by a system administrator. Options may be set either on the command line using the .Fl o -flag +flag (for short names), +the +.Fl O +flag (for long names), or in the configuration file. -This is a partial list; +This is a partial list limited to those options that are likely to be useful +on the command line +and only shows the long names; for a complete list (and details), consult the .%T "Sendmail Installation and Operation Guide" . The options are: .Bl -tag -width Fl -.It Li A Ns Ar file +.It Li AliasFile= Ns Ar file Use alternate alias file. -.It Li b Ns Ar nblocks -The minimum number of free blocks needed on the spool filesystem. -.It Li c +.It Li HoldExpensive On mailers that are considered ``expensive'' to connect to, don't initiate immediate connection. This requires queueing. -.It Li C Ar N +.It Li CheckpointInterval= Ns Ar N Checkpoint the queue file after every .Ar N successful deliveries (default 10). @@ -272,7 +336,7 @@ This avoids excessive duplicate deliveries when sending to long mailing lists interrupted by system crashes. .ne 1i -.It Li d Ns Ar x +.It Li DeliveryMode= Ns Ar x Set the delivery mode to .Ar x . Delivery modes are @@ -280,14 +344,14 @@ Delivery modes are for interactive (synchronous) delivery, .Ql b for background (asynchronous) delivery, -and .Ql q for queue only \- i.e., -actual delivery is done the next time the queue is run. -.It Li D -Try to automatically rebuild the alias database -if necessary. -.It Li e Ns Ar x +actual delivery is done the next time the queue is run, and +.Ql d +for deferred \- the same as +.Ql q +except that database lookups (notably DNS and NIS lookups) are avoided. +.It Li ErrorMode= Ns Ar x Set error processing to mode .Ar x . Valid modes are @@ -315,41 +379,33 @@ and if the sender is local to this machine, a copy of the message is appended to the file .Pa dead.letter in the sender's home directory. -.It Li f +.It Li SaveFromLine Save .Tn UNIX Ns \-style From lines at the front of messages. -.It Li G -Match local mail names against the GECOS portion of the password file. -.It Li g Ar N -The default group id to use when calling mailers. -.It Li H Ns Ar file -The -.Tn SMTP -help file. -.It Li h Ar N +.It Li MaxHopCount= Ar N The maximum number of times a message is allowed to ``hop'' before we decide it is in a loop. -.It Li i +.It Li IgnoreDots Do not take dots on a line by themselves as a message terminator. -.It Li j +.It Li SendMimeErrors Send error messages in MIME format. -.It Li K Ns Ar timeout +If not set, the DSN (Delivery Status Notification) SMTP extension +is disabled. +.It Li ConnectionCacheTimeout= Ns Ar timeout Set connection cache timeout. -.It Li k Ns Ar N +.It Li ConnectionCacheSize= Ns Ar N Set connection cache size. -.It Li L Ns Ar n +.It Li LogLevel= Ns Ar n The log level. -.It Li l -Pay attention to the Errors-To: header. -.It Li m +.It Li MeToo Send to ``me'' (the sender) also if I am in an alias expansion. -.It Li n +.It Li CheckAliases Validate the right hand side of aliases during a .Xr newaliases 1 command. -.It Li o +.It Li OldStyleHeaders If set, this message may have old style headers. If not set, @@ -357,24 +413,18 @@ this message is guaranteed to have new style headers (i.e., commas instead of spaces between addresses). If set, an adaptive algorithm is used that will correctly determine the header format in most cases. -.It Li Q Ns Ar queuedir +.It Li QueueDirectory= Ns Ar queuedir Select the directory in which to queue messages. -.It Li S Ns Ar file +.It Li StatusFile= Ns Ar file Save statistics in the named file. -.It Li s -Always instantiate the queue file, -even under circumstances where it is not strictly necessary. -This provides safety against system crashes during delivery. -.It Li T Ns Ar time +.It Li Timeout.queuereturn= Ns Ar time Set the timeout on undelivered messages in the queue to the specified time. After delivery has failed (e.g., because of a host being down) for this amount of time, failed messages will be returned to the sender. -The default is three days. -.It Li t Ns Ar stz , Ar dtz -Set the name of the time zone. -.It Li U Ns Ar userdatabase +The default is five days. +.It Li UserDatabaseSpec= Ns Ar userdatabase If set, a user database is consulted to get forwarding information. You can consider this an adjunct to the aliasing mechanism, except that the database is intended to be distributed; @@ -382,13 +432,54 @@ aliases are local to a particular host. This may not be available if your sendmail does not have the .Dv USERDB option compiled in. -.It Li u Ns Ar N -Set the default user id for mailers. -.It Li Y +.It Li ForkEachJob Fork each job during queue runs. May be convenient on memory-poor machines. -.It Li 7 +.It Li SevenBitInput Strip incoming messages to seven bits. +.It Li EightBitMode= Ns Ar mode +Set the handling of eight bit input to seven bit destinations to +.Ar mode : +.Li m +(mimefy) will convert to seven-bit MIME format, +.Li p +(pass) will pass it as eight bits (but violates protocols), +and +.Li s +(strict) will bounce the message. +.It Li MinQueueAge= Ns Ar timeout +Sets how long a job must ferment in the queue between attempts to send it. +.It Li DefaultCharSet= Ns Ar charset +Sets the default character set used to label 8-bit data +that is not otherwise labelled. +.It Li DialDelay= Ns Ar sleeptime +If opening a connection fails, +sleep for +.Ar sleeptime +seconds and try again. +Useful on dial-on-demand sites. +.It Li NoRecipientAction= Ns Ar action +Set the behaviour when there are no recipient headers (To:, Cc: or Bcc:) +in the message to +.Ar action : +.Li none +leaves the message unchanged, +.Li add-to +adds a To: header with the envelope recipients, +.Li add-apparently-to +adds an Apparently-To: header with the envelope recipients, +.Li add-bcc +adds an empty Bcc: header, and +.Li add-to-undisclosed +adds a header reading +.Ql "To: undisclosed-recipients:;" . +.It Li MaxDaemonChildren= Ns Ar N +Sets the maximum number of children that an incoming SMTP daemon +will allow to spawn at any time to +.Ar N . +.It Li ConnectionRateThrottle= Ns Ar N +Sets the maximum number of connections per second to the SMTP port to +.Ar N . .El .Pp In aliases, @@ -484,12 +575,12 @@ temp files The process id of the daemon .El .Sh SEE ALSO +.Xr binmail 1 , .Xr mail 1 , .Xr rmail 1 , .Xr syslog 3 , .Xr aliases 5 , .Xr mailaddr 7 , -.Xr mail.local 8 , .Xr rc 8 ; .Pp DARPA diff --git a/usr.sbin/sendmail/src/sendmail.h b/usr.sbin/sendmail/src/sendmail.h index 0f171587356..6aba9aba6bb 100644 --- a/usr.sbin/sendmail/src/sendmail.h +++ b/usr.sbin/sendmail/src/sendmail.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)sendmail.h 8.159.1.3 (Berkeley) 9/16/96 + * @(#)sendmail.h 8.216 (Berkeley) 12/1/96 */ /* @@ -41,7 +41,7 @@ # ifdef _DEFINE # define EXTERN # ifndef lint -static char SmailSccsId[] = "@(#)sendmail.h 8.159.1.3 9/16/96"; +static char SmailSccsId[] = "@(#)sendmail.h 8.216 12/1/96"; # endif # else /* _DEFINE */ # define EXTERN extern @@ -68,7 +68,7 @@ static char SmailSccsId[] = "@(#)sendmail.h 8.159.1.3 9/16/96"; # include <syslog.h> # endif /* LOG */ -# ifdef DAEMON +# if NETINET || NETUNIX || NETISO || NETNS || NETX25 # include <sys/socket.h> # endif # if NETUNIX @@ -179,12 +179,15 @@ typedef struct address ADDRESS; # define QEXPANDED 0x00020000 /* DSN: undergone list expansion */ # define QDELIVERED 0x00040000 /* DSN: successful final delivery */ # define QDELAYED 0x00080000 /* DSN: message delayed */ -# define QTHISPASS 0x80000000 /* temp: address set this pass */ +# define QTHISPASS 0x40000000 /* temp: address set this pass */ + +# define Q_PINGFLAGS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY) # define NULLADDR ((ADDRESS *) NULL) /* functions */ extern ADDRESS *parseaddr __P((char *, ADDRESS *, int, int, char **, ENVELOPE *)); +extern ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); extern ADDRESS *recipient __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); extern char **prescan __P((char *, int, char[], int, char **, u_char *)); extern int rewrite __P((char **, int, int, ENVELOPE *)); @@ -238,11 +241,11 @@ struct mailer # define M_NOCOMMENT 'c' /* don't include comment part of address */ # define M_CANONICAL 'C' /* make addresses canonical "u@dom" */ # define M_NOBRACKET 'd' /* never angle bracket envelope route-addrs */ - /* 'D' /* CF: include Date: */ + /* 'D' CF: include Date: */ # define M_EXPENSIVE 'e' /* it costs to use this mailer.... */ # define M_ESCFROM 'E' /* escape From lines to >From */ # define M_FOPT 'f' /* mailer takes picky -f flag */ - /* 'F' /* CF: include From: or Resent-From: */ + /* 'F' CF: include From: or Resent-From: */ # define M_NO_NULL_FROM 'g' /* sender of errors should be $g */ # define M_HST_UPPER 'h' /* preserve host case distinction */ # define M_PREHEAD 'H' /* MAIL11V3: preview headers */ @@ -250,15 +253,17 @@ struct mailer # define M_INTERNAL 'I' /* SMTP to another sendmail site */ # define M_UDBRECIPIENT 'j' /* do udbsender rewriting on recipient lines */ # define M_NOLOOPCHECK 'k' /* don't check for loops in HELO command */ +# define M_CHUNKING 'K' /* CHUNKING: reserved for future use */ # define M_LOCALMAILER 'l' /* delivery is to this host */ # define M_LIMITS 'L' /* must enforce SMTP line limits */ # define M_MUSER 'm' /* can handle multiple users at once */ - /* 'M' /* CF: include Message-Id: */ + /* 'M' CF: include Message-Id: */ # define M_NHDR 'n' /* don't insert From line */ # define M_MANYSTATUS 'N' /* MAIL11V3: DATA returns multi-status */ # define M_RUNASRCPT 'o' /* always run mailer as recipient */ # define M_FROMPATH 'p' /* use reverse-path in MAIL FROM: */ - /* 'P' /* CF: include Return-Path: */ + /* 'P' CF: include Return-Path: */ +# define M_VRFY250 'q' /* VRFY command returns 250 instead of 252 */ # define M_ROPT 'r' /* mailer takes picky -r flag */ # define M_SECURE_PORT 'R' /* try to send on a reserved TCP port */ # define M_STRIPQ 's' /* strip quote chars from user/host */ @@ -266,12 +271,16 @@ struct mailer # define M_USR_UPPER 'u' /* preserve user case distinction */ # define M_UGLYUUCP 'U' /* this wants an ugly UUCP from line */ # define M_CONTENT_LEN 'v' /* add Content-Length: header (SVr4) */ - /* 'V' /* UIUC: !-relativize all addresses */ + /* 'V' UIUC: !-relativize all addresses */ # define M_HASPWENT 'w' /* check for /etc/passwd entry */ - /* 'x' /* CF: include Full-Name: */ + /* 'x' CF: include Full-Name: */ # define M_XDOT 'X' /* use hidden-dot algorithm */ +# define M_LMTP 'z' /* run Local Mail Transport Protocol */ +# define M_NOMX '0' /* turn off MX lookups */ +# define M_NONULLS '1' /* don't send null bytes */ # define M_EBCDIC '3' /* extend Q-P encoding for EBCDIC */ # define M_TRYRULESET5 '5' /* use ruleset 5 after local aliasing */ +# define M_7BITHDRS '6' /* strip headers to 7 bits even in 8 bit path */ # define M_7BITS '7' /* use 7-bit path */ # define M_8BITS '8' /* force "just send 8" behaviour */ # define M_MAKE8BIT '9' /* convert 7 -> 8 bit if appropriate */ @@ -279,6 +288,7 @@ struct mailer # define M_CHECKPROG '|' /* check for |program addresses */ # define M_CHECKFILE '/' /* check for /file addresses */ # define M_CHECKUDB '@' /* user can be user database key */ +# define M_CHECKHDIR '~' /* SGI: check for valid home directory */ EXTERN MAILER *Mailer[MAXMAILERS+1]; @@ -287,52 +297,6 @@ EXTERN MAILER *ProgMailer; /* ptr to program mailer */ EXTERN MAILER *FileMailer; /* ptr to *file* mailer */ EXTERN MAILER *InclMailer; /* ptr to *include* mailer */ /* -** Header structure. -** This structure is used internally to store header items. -*/ - -struct header -{ - char *h_field; /* the name of the field */ - char *h_value; /* the value of that field */ - struct header *h_link; /* the next header */ - u_short h_flags; /* status bits, see below */ - BITMAP h_mflags; /* m_flags bits needed */ -}; - -typedef struct header HDR; - -/* -** Header information structure. -** Defined in conf.c, this struct declares the header fields -** that have some magic meaning. -*/ - -struct hdrinfo -{ - char *hi_field; /* the name of the field */ - u_short hi_flags; /* status bits, see below */ -}; - -extern struct hdrinfo HdrInfo[]; - -/* bits for h_flags and hi_flags */ -# define H_EOH 0x0001 /* this field terminates header */ -# define H_RCPT 0x0002 /* contains recipient addresses */ -# define H_DEFAULT 0x0004 /* if another value is found, drop this */ -# define H_RESENT 0x0008 /* this address is a "Resent-..." address */ -# define H_CHECK 0x0010 /* check h_mflags against m_flags */ -# define H_ACHECK 0x0020 /* ditto, but always (not just default) */ -# define H_FORCE 0x0040 /* force this field, even if default */ -# define H_TRACE 0x0080 /* this field contains trace information */ -# define H_FROM 0x0100 /* this is a from-type field */ -# define H_VALID 0x0200 /* this field has a validated value */ -# define H_RECEIPTTO 0x0400 /* this field has return receipt info */ -# define H_ERRORSTO 0x0800 /* this field has error address info */ -# define H_CTE 0x1000 /* this field is a content-transfer-encoding */ -# define H_CTYPE 0x2000 /* this is a content-type field */ -# define H_BCC 0x4000 /* Bcc: header: strip value or delete */ -/* ** Information about currently open connections to mailers, or to ** hosts that we have looked up recently. */ @@ -349,12 +313,14 @@ MCI long mci_maxsize; /* max size this server will accept */ FILE *mci_in; /* input side of connection */ FILE *mci_out; /* output side of connection */ - int mci_pid; /* process id of subordinate proc */ + pid_t mci_pid; /* process id of subordinate proc */ char *mci_phase; /* SMTP phase string */ struct mailer *mci_mailer; /* ptr to the mailer for this conn */ char *mci_host; /* host name */ char *mci_status; /* DSN status to be copied to addrs */ + char *mci_rstatus; /* SMTP status to be copied to addrs */ time_t mci_lastuse; /* last usage time */ + FILE *mci_statfile; /* long term status file */ }; @@ -388,6 +354,72 @@ MCI extern MCI *mci_get __P((char *, MAILER *)); extern void mci_cache __P((MCI *)); extern void mci_flush __P((bool, MCI *)); +extern void mci_dump __P((MCI *, bool)); +extern void mci_dump_all __P((bool)); +extern MCI **mci_scan __P((MCI *)); +extern int mci_traverse_persistent __P((int (), char *)); +extern int mci_print_persistent __P((char *, char *)); +extern int mci_purge_persistent __P((char *, char *)); +extern int mci_lock_host __P((MCI *)); +extern void mci_unlock_host __P((MCI *)); +extern int mci_lock_host_statfile __P((MCI *)); +extern void mci_store_persistent __P((MCI *)); +extern int mci_read_persistent __P((FILE *, MCI *)); +/* +** Header structure. +** This structure is used internally to store header items. +*/ + +struct header +{ + char *h_field; /* the name of the field */ + char *h_value; /* the value of that field */ + struct header *h_link; /* the next header */ + u_short h_flags; /* status bits, see below */ + BITMAP h_mflags; /* m_flags bits needed */ +}; + +typedef struct header HDR; + +/* +** Header information structure. +** Defined in conf.c, this struct declares the header fields +** that have some magic meaning. +*/ + +struct hdrinfo +{ + char *hi_field; /* the name of the field */ + u_short hi_flags; /* status bits, see below */ +}; + +extern struct hdrinfo HdrInfo[]; + +/* bits for h_flags and hi_flags */ +# define H_EOH 0x0001 /* this field terminates header */ +# define H_RCPT 0x0002 /* contains recipient addresses */ +# define H_DEFAULT 0x0004 /* if another value is found, drop this */ +# define H_RESENT 0x0008 /* this address is a "Resent-..." address */ +# define H_CHECK 0x0010 /* check h_mflags against m_flags */ +# define H_ACHECK 0x0020 /* ditto, but always (not just default) */ +# define H_FORCE 0x0040 /* force this field, even if default */ +# define H_TRACE 0x0080 /* this field contains trace information */ +# define H_FROM 0x0100 /* this is a from-type field */ +# define H_VALID 0x0200 /* this field has a validated value */ +# define H_RECEIPTTO 0x0400 /* this field has return receipt info */ +# define H_ERRORSTO 0x0800 /* this field has error address info */ +# define H_CTE 0x1000 /* this field is a content-transfer-encoding */ +# define H_CTYPE 0x2000 /* this is a content-type field */ +# define H_BCC 0x4000 /* Bcc: header: strip value or delete */ +# define H_ENCODABLE 0x8000 /* field can be RFC 1522 encoded */ + +/* functions */ +extern void addheader __P((char *, char *, HDR **)); +extern char *hvalue __P((char *, HDR *)); +extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *)); +extern void put_vanilla_header __P((HDR *, char *, MCI *)); +extern void eatheader __P((ENVELOPE *e, bool)); +extern int chompheader __P((char *, bool, HDR **, ENVELOPE *)); /* ** Envelope structure. ** This structure defines the message itself. There is usually @@ -403,7 +435,6 @@ struct envelope long e_msgpriority; /* adjusted priority of this message */ time_t e_ctime; /* time message appeared in the queue */ char *e_to; /* the target person */ - char *e_receiptto; /* return receipt address */ ADDRESS e_from; /* the person it is from */ char *e_sender; /* e_from.q_paddr w comments stripped */ char **e_fromdomain; /* the domain part of the sender */ @@ -472,7 +503,7 @@ EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */ /* functions */ extern ENVELOPE *newenvelope __P((ENVELOPE *, ENVELOPE *)); -extern void dropenvelope __P((ENVELOPE *)); +extern void dropenvelope __P((ENVELOPE *, bool)); extern void clearenvelope __P((ENVELOPE *, bool)); extern void putheader __P((MCI *, HDR *, ENVELOPE *)); @@ -636,7 +667,8 @@ MAP char *map_domain; /* the (nominal) NIS domain */ char *map_rebuild; /* program to run to do auto-rebuild */ time_t map_mtime; /* last database modification time */ - short map_specificity; /* specificity of alaases */ + int map_lockfd; /* auxiliary lock file descriptor */ + short map_specificity; /* specificity of aliases */ MAP *map_stack[MAXMAPSTACK]; /* list for stacked maps */ short map_return[MAXMAPACTIONS]; /* return bitmaps for stacked maps */ }; @@ -659,6 +691,7 @@ MAP # define MF_UNSAFEDB 0x00004000 /* this map is world writable */ # define MF_APPEND 0x00008000 /* append new entry on rebuiled */ # define MF_KEEPQUOTES 0x00010000 /* don't dequote key before lookup */ +# define MF_NODEFER 0x00020000 /* don't defer if map lookup fails */ /* indices for map_actions */ # define MA_NOTFOUND 0 /* member map returned "not found" */ @@ -695,6 +728,7 @@ MAPCLASS /* functions */ extern char *map_rewrite __P((MAP *, char *, int, char **)); extern MAP *makemapentry __P((char *)); +extern void initmaps __P((bool, ENVELOPE *)); /* ** Symbol table definitions */ @@ -702,7 +736,8 @@ extern MAP *makemapentry __P((char *)); struct symtab { char *s_name; /* name to be entered */ - char s_type; /* general type (see below) */ + short s_type; /* general type (see below) */ + short s_len; /* length of this entry */ struct symtab *s_next; /* pointer to next in chain */ union { @@ -717,6 +752,7 @@ struct symtab NAMECANON sv_namecanon; /* canonical name cache */ int sv_macro; /* macro name => id mapping */ int sv_ruleset; /* ruleset index */ + char *sv_service[MAXMAPSTACK]; /* service switch */ } s_value; }; @@ -734,6 +770,7 @@ typedef struct symtab STAB; # define ST_NAMECANON 8 /* cached canonical name */ # define ST_MACRO 9 /* macro name to id mapping */ # define ST_RULESET 10 /* ruleset index */ +# define ST_SERVICE 11 /* service switch entry */ # define ST_MCI 16 /* mailer connection info (offset) */ # define s_class s_value.sv_class @@ -747,6 +784,7 @@ typedef struct symtab STAB; # define s_namecanon s_value.sv_namecanon # define s_macro s_value.sv_macro # define s_ruleset s_value.sv_ruleset +# define s_service s_value.sv_service extern STAB *stab __P((char *, int, int)); extern void stabapply __P((void (*)(STAB *, int), int)); @@ -802,12 +840,14 @@ EXTERN char OpMode; /* operation mode, see below */ #define MD_SMTP 's' /* run SMTP on standard input */ #define MD_ARPAFTP 'a' /* obsolete ARPANET mode (Grey Book) */ #define MD_DAEMON 'd' /* run as a daemon */ +#define MD_FGDAEMON 'D' /* run daemon in foreground */ #define MD_VERIFY 'v' /* verify: don't collect or deliver */ #define MD_TEST 't' /* test mode: resolve addrs only */ #define MD_INITALIAS 'i' /* initialize alias database */ #define MD_PRINT 'p' /* print the queue */ #define MD_FREEZE 'z' /* freeze the configuration file */ - +#define MD_HOSTSTAT 'h' /* print persistent host stat info */ +#define MD_PURGESTAT 'H' /* purge persistent host stat info */ /* values for e_sendmode -- send modes */ #define SM_DELIVER 'i' /* interactive delivery */ @@ -841,6 +881,7 @@ EXTERN int QueueSortOrder; #define QS_BYPRIORITY 0 /* sort by message priority */ #define QS_BYHOST 1 /* sort by first host name */ +#define QS_BYTIME 2 /* sort by submission time */ /* how to handle messages without any recipient addresses */ @@ -856,7 +897,7 @@ EXTERN int NoRecipientAction; /* flags to putxline */ #define PXLF_NOTHINGSPECIAL 0 /* no special mapping */ #define PXLF_MAPFROM 0x0001 /* map From_ to >From_ */ -#define PXLF_STRIP8BIT 0x0002 /* strip 8th bit *e +#define PXLF_STRIP8BIT 0x0002 /* strip 8th bit */ /* ** Additional definitions */ @@ -918,6 +959,9 @@ struct prival /* flags that are actually specific to safefopen */ #define SFF_OPENASROOT 0x1000 /* open as root instead of real user */ +/* functions */ +extern int safefile __P((char *, UID_T, GID_T, char *, int, int, struct stat *)); + /* ** Flags passed to mime8to7. @@ -929,11 +973,20 @@ struct prival /* +** Flags passed to returntosender. +*/ + +#define RTSF_NO_BODY 0 /* send headers only */ +#define RTSF_SEND_BODY 0x0001 /* include body of message in return */ +#define RTSF_PM_BOUNCE 0x0002 /* this is a postmaster bounce */ + + +/* ** Regular UNIX sockaddrs are too small to handle ISO addresses, so ** we are forced to declare a supertype here. */ -#ifdef DAEMON +# if NETINET || NETUNIX || NETISO || NETNS || NETX25 union bigsockaddr { struct sockaddr sa; /* general version */ @@ -957,7 +1010,12 @@ union bigsockaddr #define SOCKADDR union bigsockaddr EXTERN SOCKADDR RealHostAddr; /* address of host we are talking to */ + +extern char *hostnamebyanyaddr __P((SOCKADDR *)); extern char *anynet_ntoa __P((SOCKADDR *)); +# if DAEMON +extern bool validate_connection __P((SOCKADDR *, char *, ENVELOPE *)); +# endif #endif @@ -983,6 +1041,34 @@ extern char *anynet_ntoa __P((SOCKADDR *)); #define VENDOR_IBM 4 /* IBM specific config syntax */ EXTERN int VendorCode; /* vendor-specific operation enhancements */ + +/* prototypes for vendor-specific hook routines */ +extern void vendor_set_uid __P((UID_T)); +extern void vendor_daemon_setup __P((ENVELOPE *)); + + +/* +** Terminal escape codes. +** +** To make debugging output clearer. +*/ + +struct termescape +{ + char *te_rv_on; /* turn reverse-video on */ + char *te_rv_off; /* turn reverse-video off */ +}; + +EXTERN struct termescape TermEscape; + + +/* +** Error return from inet_addr(3), in case not defined in /usr/include. +*/ + +#ifndef INADDR_NONE +# define INADDR_NONE 0xffffffff +#endif /* ** Global variables. */ @@ -1005,6 +1091,7 @@ EXTERN bool UseNameServer; /* using DNS -- interpret h_errno & MX RRs */ EXTERN bool UseHesiod; /* using Hesiod -- interpret Hesiod errors */ EXTERN bool SevenBitInput; /* force 7-bit data on input */ EXTERN bool HasEightBits; /* has at least one eight bit input byte */ +EXTERN bool ConfigFileRead; /* configuration file has been read */ EXTERN time_t SafeAlias; /* interval to wait until @:@ in alias file */ EXTERN FILE *InChannel; /* input connection */ EXTERN FILE *OutChannel; /* output connection */ @@ -1014,7 +1101,7 @@ EXTERN gid_t RealGid; /* real gid of caller */ EXTERN uid_t DefUid; /* default uid to run as */ EXTERN gid_t DefGid; /* default gid to run as */ EXTERN char *DefUser; /* default user to run as (from DefUid) */ -EXTERN int OldUmask; /* umask when sendmail starts up */ +EXTERN MODE_T OldUmask; /* umask when sendmail starts up */ EXTERN int Errors; /* set if errors (local to single pass) */ EXTERN int ExitStat; /* exit status code */ EXTERN int LineNumber; /* line number in current input */ @@ -1061,11 +1148,11 @@ EXTERN char *ForwardPath; /* path to search for .forward files */ EXTERN long MinBlocksFree; /* min # of blocks free on queue fs */ EXTERN char *FallBackMX; /* fall back MX host */ EXTERN long MaxMessageSize; /* advertised max size we will accept */ -EXTERN time_t MaxHostStatAge; /* max age of cached host status info */ EXTERN time_t MinQueueAge; /* min delivery interval */ EXTERN time_t DialDelay; /* delay between dial-on-demand tries */ EXTERN char *SafeFileEnv; /* chroot location for file delivery */ EXTERN char *HostsFile; /* path to /etc/hosts file */ +EXTERN char *HostStatDir; /* location of host status information */ EXTERN int MaxQueueRun; /* maximum number of jobs in one queue run */ EXTERN int MaxChildren; /* maximum number of daemonic children */ EXTERN int CurChildren; /* current number of daemonic children */ @@ -1073,8 +1160,18 @@ EXTERN char *SmtpGreeting; /* SMTP greeting message (old $e macro) */ EXTERN char *UnixFromLine; /* UNIX From_ line (old $l macro) */ EXTERN char *OperatorChars; /* operators (old $o macro) */ EXTERN bool DontInitGroups; /* avoid initgroups() because of NIS cost */ +EXTERN int DefaultNotify; /* default DSN notification flags */ +EXTERN bool AllowBogusHELO; /* allow syntax errors on HELO command */ +EXTERN bool UserSubmission; /* initial (user) mail submission */ +EXTERN uid_t RunAsUid; /* UID to become for bulk of run */ +EXTERN gid_t RunAsGid; /* GID to become for bulk of run */ +EXTERN bool IgnoreHostStatus; /* ignore long term host status files */ +EXTERN bool SingleThreadDelivery; /* single thread hosts on delivery */ +EXTERN bool UnsafeGroupWrites; /* group-writable files are unsafe */ EXTERN bool SingleLineFromHeader; /* force From: header to be one line */ +EXTERN int ConnRateThrottle; /* throttle for SMTP connection rate */ EXTERN int MaxAliasRecursion; /* maximum depth of alias recursion */ +EXTERN int MaxMacroRecursion; /* maximum depth of macro recursion */ EXTERN int MaxRuleRecursion; /* maximum depth of ruleset recursion */ EXTERN char *MustQuoteChars; /* quote these characters in phrases */ EXTERN char *ServiceSwitchFile; /* backup service switch */ @@ -1085,12 +1182,16 @@ EXTERN int CheckpointInterval; /* queue file checkpoint interval */ EXTERN bool DontPruneRoutes; /* don't prune source routes */ EXTERN bool DontExpandCnames; /* do not $[...$] expand CNAMEs */ EXTERN int MaxMciCache; /* maximum entries in MCI cache */ +EXTERN time_t ServiceCacheTime; /* time service switch was cached */ +EXTERN time_t ServiceCacheMaxAge; /* refresh interval for cache */ EXTERN time_t MciCacheTimeout; /* maximum idle time on connections */ EXTERN time_t MciInfoTimeout; /* how long 'til we retry down hosts */ EXTERN char *QueueLimitRecipient; /* limit queue runs to this recipient */ EXTERN char *QueueLimitSender; /* limit queue runs to this sender */ EXTERN char *QueueLimitId; /* limit queue runs to this id */ EXTERN FILE *TrafficLogFile; /* file in which to log all traffic */ +EXTERN char *DoubleBounceAddr; /* where to send double bounces */ +EXTERN char **ExternalEnviron; /* input environment */ EXTERN char *UserEnviron[MAXUSERENVIRON + 1]; /* saved user environment */ extern int errno; @@ -1113,7 +1214,8 @@ EXTERN struct time_t to_datafinal; /* DATA completion [10m] */ time_t to_nextcommand; /* next command [5m] */ /* following timeouts are not mentioned in RFC 1123 */ - time_t to_connect; /* initial connection timeout */ + time_t to_iconnect; /* initial connection timeout (first try) */ + time_t to_connect; /* initial connection timeout (later tries) */ time_t to_rset; /* RSET command */ time_t to_helo; /* HELO command */ time_t to_quit; /* QUIT command */ @@ -1161,6 +1263,7 @@ EXTERN u_char tTdvect[100]; #define STRUCTCOPY(s, d) d = s + /* ** Declarations of useful functions */ @@ -1181,8 +1284,6 @@ extern void openxscript __P((ENVELOPE *)); extern void closexscript __P((ENVELOPE *)); extern char *shortenstring __P((const char *, int)); extern bool usershellok __P((char *, char *)); -extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *)); -extern char *hvalue __P((char *, HDR *)); extern char *defcharset __P((ENVELOPE *)); extern bool wordinclass __P((char *, int)); extern char *denlstring __P((char *, bool, bool)); @@ -1197,6 +1298,7 @@ extern void logsender __P((ENVELOPE *, char *)); extern void smtprset __P((MAILER *, MCI *, ENVELOPE *)); extern void smtpquit __P((MAILER *, MCI *, ENVELOPE *)); extern void setuserenv __P((const char *, const char *)); +extern char *getextenv __P((const char *)); extern void disconnect __P((int, ENVELOPE *)); extern void putxline __P((char *, MCI *, int)); extern void dumpfd __P((int, bool, bool)); @@ -1208,15 +1310,67 @@ extern void inittimeouts __P((char *)); extern void logdelivery __P((MAILER *, MCI *, const char *, ADDRESS *, time_t, ENVELOPE *)); extern void giveresponse __P((int, MAILER *, MCI *, ADDRESS *, time_t, ENVELOPE *)); extern void buildfname __P((char *, char *, char *, int)); +extern void mci_setstat __P((MCI *, int, char *, char *)); +extern char *smtptodsn __P((int)); +extern int rscheck __P((char *, char *, char *, ENVELOPE *e)); +extern void mime7to8 __P((MCI *, HDR *, ENVELOPE *)); +extern int mime8to7 __P((MCI *, HDR *, ENVELOPE *, char **, int)); +extern void xfclose __P((FILE *, char *, char *)); +extern int switch_map_find __P((char *, char *[], short [])); +extern void shorten_hostname __P((char [])); +extern int waitfor __P((pid_t)); +extern void proc_list_add __P((pid_t)); +extern void proc_list_drop __P((pid_t)); +extern void proc_list_clear __P((void)); +extern void buffer_errors __P((void)); +extern void flush_errors __P((bool)); +extern void putline __P((char *, MCI *)); +extern void putxline __P((char *, MCI *, int)); +extern bool xtextok __P((char *)); +extern char *xtextify __P((char *, char *)); +extern char *xuntextify __P((char *)); +extern void cleanstrcpy __P((char *, char *, int)); +extern int getmxrr __P((char *, char **, bool, int *)); +extern int strtorwset __P((char *, char **, int)); +extern void printav __P((char **)); +extern void printopenfds __P((bool)); +extern int endmailer __P((MCI *, ENVELOPE *, char **)); +extern void fixcrlf __P((char *, bool)); +extern int dofork __P((void)); +extern void initsys __P((ENVELOPE *)); +extern void collect __P((FILE *, bool, bool, HDR **, ENVELOPE *)); +extern void stripquotes __P((char *)); +extern int include __P((char *, bool, ADDRESS *, ADDRESS **, int, ENVELOPE *)); +extern void unlockqueue __P((ENVELOPE *)); +extern void xunlink __P((char *)); +extern bool runqueue __P((bool, bool)); +extern int getla __P((void)); +extern void sendall __P((ENVELOPE *, int)); +extern void queueup __P((ENVELOPE *, bool)); +extern void checkfds __P((char *)); +extern int returntosender __P((char *, ADDRESS *, int, ENVELOPE *)); +extern void markstats __P((ENVELOPE *, ADDRESS *)); +extern void poststats __P((char *)); +extern char *arpadate __P((char *)); +extern int mailfile __P((char *, ADDRESS *, int, ENVELOPE *)); +extern void loseqfile __P((ENVELOPE *, char *)); +extern int prog_open __P((char **, int *, ENVELOPE *)); +extern bool getcanonname __P((char *, int, bool)); +extern bool path_is_dir __P((char *, bool)); +extern pid_t dowork __P((char *, bool, bool, ENVELOPE *)); extern const char *errstring __P((int)); extern sigfunc_t setsignal __P((int, sigfunc_t)); +extern int blocksignal __P((int)); +extern int releasesignal __P((int)); extern struct hostent *sm_gethostbyname __P((char *)); extern struct hostent *sm_gethostbyaddr __P((char *, int, int)); extern struct passwd *sm_getpwnam __P((char *)); extern struct passwd *sm_getpwuid __P((UID_T)); +extern struct passwd *finduser __P((char *, bool *)); #ifdef XDEBUG +extern void checkfdopen __P((int, char *)); extern void checkfd012 __P((char *)); #endif @@ -1227,12 +1381,14 @@ extern void syserr(const char *, ...); extern void usrerr(const char *, ...); extern void message(const char *, ...); extern void nmessage(const char *, ...); +extern void setproctitle(const char *fmt, ...); #else extern void auth_warning(); extern void syserr(); extern void usrerr(); extern void message(); extern void nmessage(); +extern void setproctitle(); #endif #if !HASSNPRINTF diff --git a/usr.sbin/sendmail/src/sendmail.hf b/usr.sbin/sendmail/src/sendmail.hf index 14db22c68ee..add62c1ae6d 100644 --- a/usr.sbin/sendmail/src/sendmail.hf +++ b/usr.sbin/sendmail/src/sendmail.hf @@ -1,14 +1,14 @@ cpyr -cpyr Copyright (c) 1983, 1995 Eric P. Allman +cpyr Copyright (c) 1983, 1995, 1996 Eric P. Allman cpyr Copyright (c) 1988, 1993 cpyr The Regents of the University of California. All rights reserved. cpyr -cpyr @(#)sendmail.hf 8.7 (Berkeley) 10/1/95 +cpyr @(#)sendmail.hf 8.11 (Berkeley) 9/11/96 cpyr -smtp Commands: +smtp Topics: smtp HELO EHLO MAIL RCPT DATA smtp RSET NOOP QUIT HELP VRFY -smtp EXPN VERB +smtp EXPN VERB ETRN DSN smtp For more info use "HELP <topic>". smtp To report bugs in the implementation send email to smtp sendmail-bugs@sendmail.org. @@ -19,10 +19,29 @@ helo HELO <hostname> helo Introduce yourself. ehlo EHLO <hostname> ehlo Introduce yourself, and request extended SMTP mode. -mail MAIL FROM: <sender> -mail Specifies the sender. -rcpt RCPT TO: <recipient> +ehlo Possible replies include: +ehlo SEND Send as mail [RFC821] +ehlo SOML Send as mail or terminal [RFC821] +ehlo SAML Send as mail and terminal [RFC821] +ehlo EXPN Expand the mailing list [RFC821] +ehlo HELP Supply helpful information [RFC821] +ehlo TURN Turn the operation around [RFC821] +ehlo 8BITMIME Use 8-bit data [RFC1652] +ehlo SIZE Message size declaration [RFC1870] +ehlo VERB Verbose [Allman] +ehlo ONEX One message transaction only [Allman] +ehlo CHUNKING Chunking [RFC1830] +ehlo BINARYMIME Binary MIME [RFC1830] +ehlo PIPELINING Command Pipelining [RFC1854] +ehlo DSN Delivery Status Notification [RFC1891] +ehlo ETRN Remote Message Queue Starting [RFC1985] +ehlo XUSR Initial (user) submission [Allman] +mail MAIL FROM: <sender> [ <parameters> ] +mail Specifies the sender. Parameters are ESMTP extensions. +mail See "HELP DSN" for details. +rcpt RCPT TO: <recipient> [ <parameters> ] rcpt Specifies the recipient. Can be used any number of times. +rcpt Parameters are ESMTP extensions. See "HELP DSN" for details. data DATA data Following text is collected as the message. data End with a single dot. @@ -56,6 +75,20 @@ saml implementation. turn TURN turn Reverses the direction of the connection. Not currently turn implemented. +etrn ETRN [ <hostname> | @<domain> | #<queuename> ] +etrn Run the queue for the specified <hostname>, or +etrn all hosts within a given <domain>, or a specially-named +etrn <queuename> (implementation-specific). +dsn MAIL FROM: <sender> [ RET={ FULL | HDRS} ] [ ENVID=<envid> ] +dsn RCPT TO: <recipient> [ NOTIFY={NEVER,SUCCESS,FAILURE,DELAY} ] +dsn [ ORCPT=<recipient> ] +dsn SMTP Delivery Status Notifications. +dsn Descriptions: +dsn RET Return either the full message or only headers. +dsn ENVID Sender's "envelope identifier" for tracking. +dsn NOTIFY When to send a DSN. Multiple options are OK, comma- +dsn delimited. NEVER must appear by itself. +dsn ORCPT Original recipient. -bt Help for test mode: -bt ? :this help message. -bt .Dmvalue :define macro `m' to `value'. @@ -76,3 +109,5 @@ turn implemented. -bt flags for header recipients. -bt /canon hostname :try to canonify hostname. -bt /map mapname key :look up `key' in the indicated `mapname'. +-bt rules addr :run the indicated address through the named rules. +-bt Rules can be a comma separated list of rules. diff --git a/usr.sbin/sendmail/src/srvrsmtp.c b/usr.sbin/sendmail/src/srvrsmtp.c index 5e7ab64b104..895cce5e3a9 100644 --- a/usr.sbin/sendmail/src/srvrsmtp.c +++ b/usr.sbin/sendmail/src/srvrsmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -35,16 +35,16 @@ # include "sendmail.h" #ifndef lint -#ifdef SMTP -static char sccsid[] = "@(#)srvrsmtp.c 8.97 (Berkeley) 11/18/95 (with SMTP)"; +#if SMTP +static char sccsid[] = "@(#)srvrsmtp.c 8.131 (Berkeley) 12/1/96 (with SMTP)"; #else -static char sccsid[] = "@(#)srvrsmtp.c 8.97 (Berkeley) 11/18/95 (without SMTP)"; +static char sccsid[] = "@(#)srvrsmtp.c 8.131 (Berkeley) 12/1/96 (without SMTP)"; #endif #endif /* not lint */ # include <errno.h> -# ifdef SMTP +# if SMTP /* ** SMTP -- run the SMTP protocol. @@ -79,9 +79,11 @@ struct cmd # define CMDHELO 9 /* helo -- be polite */ # define CMDHELP 10 /* help -- give usage info */ # define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ +# define CMDETRN 12 /* etrn -- flush queue */ /* non-standard commands */ # define CMDONEX 16 /* onex -- sending one transaction only */ # define CMDVERB 17 /* verb -- go into verbose mode */ +# define CMDXUSR 18 /* xusr -- initial (user) submission */ /* use this to catch and log "door handle" attempts on your system */ # define CMDLOGBOGUS 23 /* bogus command that should be logged */ /* debugging-only commands, only enabled if SMTPDEBUG is defined */ @@ -90,27 +92,27 @@ struct cmd static struct cmd CmdTab[] = { - "mail", CMDMAIL, - "rcpt", CMDRCPT, - "data", CMDDATA, - "rset", CMDRSET, - "vrfy", CMDVRFY, - "expn", CMDEXPN, - "help", CMDHELP, - "noop", CMDNOOP, - "quit", CMDQUIT, - "helo", CMDHELO, - "ehlo", CMDEHLO, - "verb", CMDVERB, - "onex", CMDONEX, - /* - * remaining commands are here only - * to trap and log attempts to use them - */ - "showq", CMDDBGQSHOW, - "debug", CMDDBGDEBUG, - "wiz", CMDLOGBOGUS, - NULL, CMDERROR, + { "mail", CMDMAIL }, + { "rcpt", CMDRCPT }, + { "data", CMDDATA }, + { "rset", CMDRSET }, + { "vrfy", CMDVRFY }, + { "expn", CMDEXPN }, + { "help", CMDHELP }, + { "noop", CMDNOOP }, + { "quit", CMDQUIT }, + { "helo", CMDHELO }, + { "ehlo", CMDEHLO }, + { "etrn", CMDETRN }, + { "verb", CMDVERB }, + { "onex", CMDONEX }, + { "xusr", CMDXUSR }, + /* remaining commands are here only to trap and log attempts to use them */ + { "showq", CMDDBGQSHOW }, + { "debug", CMDDBGDEBUG }, + { "wiz", CMDLOGBOGUS }, + + { NULL, CMDERROR } }; bool OneXact = FALSE; /* one xaction only this run */ @@ -122,10 +124,11 @@ static char *skipword(); #define MAXBADCOMMANDS 25 /* maximum number of bad commands */ void -smtp(e) +smtp(nullserver, e) + bool nullserver; register ENVELOPE *volatile e; { - register char *p; + register char *volatile p; register struct cmd *c; char *cmd; auto ADDRESS *vrfyqueue; @@ -141,10 +144,16 @@ smtp(e) volatile int nrcpts = 0; /* number of RCPT commands */ bool doublequeue; volatile int badcommands = 0; /* count of bad commands */ + volatile int nverifies = 0; /* count of VRFY/EXPN commands */ + volatile int n_etrn = 0; /* count of ETRN commands */ + bool ok; char inp[MAXLINE]; char cmdbuf[MAXLINE]; extern ENVELOPE BlankEnvelope; extern void help __P((char *)); + extern void settime __P((ENVELOPE *)); + extern bool enoughdiskspace __P((long)); + extern int runinchild __P((char *, ENVELOPE *)); if (fileno(OutChannel) != fileno(stdout)) { @@ -161,7 +170,7 @@ smtp(e) CurSmtpClient = CurHostName; setproctitle("server %s startup", CurSmtpClient); -#ifdef LOG +#if defined(LOG) && DAEMON if (LogLevel > 11) { /* log connection information */ @@ -253,6 +262,11 @@ smtp(e) if (e->e_xfp != NULL) fprintf(e->e_xfp, "<<< %s\n", inp); +#ifdef LOG + if (LogLevel >= 15) + syslog(LOG_INFO, "<-- %s", inp); +#endif + if (e->e_id == NULL) setproctitle("%s: %.80s", CurSmtpClient, inp); else @@ -282,7 +296,20 @@ smtp(e) /* reset errors */ errno = 0; - /* process command */ + /* + ** Process command. + ** + ** If we are running as a null server, return 550 + ** to everything. + */ + + if (nullserver && c->cmdcode != CMDQUIT) + { + message("550 Access denied"); + continue; + } + + /* non-null server */ switch (c->cmdcode) { case CMDHELO: /* hello -- introduce yourself */ @@ -299,7 +326,7 @@ smtp(e) } /* check for valid domain name (re 1123 5.2.5) */ - if (*p == '\0') + if (*p == '\0' && !AllowBogusHELO) { message("501 %s requires domain address", cmdbuf); @@ -325,11 +352,23 @@ smtp(e) } if (*q != '\0') { - message("501 Invalid domain name"); + if (!AllowBogusHELO) + message("501 Invalid domain name"); + else + message("250 %s Invalid domain name, accepting anyway", + MyHostName); break; } } + /* check for duplicate HELO/EHLO per RFC 1651 4.2 */ + if (gothello) + { + message("503 %s Duplicate HELO/EHLO", + MyHostName); + break; + } + sendinghost = newstr(p); gothello = TRUE; if (c->cmdcode != CMDEHLO) @@ -344,7 +383,10 @@ smtp(e) message("250-%s Hello %s, pleased to meet you", MyHostName, CurSmtpClient); if (!bitset(PRIV_NOEXPN, PrivacyFlags)) + { message("250-EXPN"); + message("250-VERB"); + } #if MIME8TO7 message("250-8BITMIME"); #endif @@ -356,8 +398,9 @@ smtp(e) if (SendMIMEErrors) message("250-DSN"); #endif - message("250-VERB"); message("250-ONEX"); + message("250-ETRN"); + message("250-XUSR"); message("250 HELP"); break; @@ -391,13 +434,17 @@ smtp(e) finis(); } + p = skipword(p, "from"); + if (p == NULL) + break; + /* fork a subprocess to process this command */ if (runinchild("SMTP-MAIL", e) > 0) break; if (!gothello) { auth_warning(e, - "Host %s didn't use HELO protocol", + "%s didn't use HELO protocol", CurSmtpClient); } #ifdef PICKY_HELO_CHECK @@ -420,12 +467,10 @@ smtp(e) setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); /* child -- go do the processing */ - p = skipword(p, "from"); - if (p == NULL) - break; if (setjmp(TopFrame) > 0) { /* this failed -- undo work */ + undo_subproc: if (InChild) { QuickAbort = FALSE; @@ -440,9 +485,12 @@ smtp(e) /* must parse sender first */ delimptr = NULL; setsender(p, e, &delimptr, FALSE); - p = delimptr; - if (p != NULL && *p != '\0') - *p++ = '\0'; + if (delimptr != NULL && *delimptr != '\0') + *delimptr++ = '\0'; + + /* do config file checking of the sender */ + if (rscheck("check_mail", p, NULL, e) != EX_OK) + goto undo_subproc; /* check for possible spoofing */ if (RealUid != 0 && OpMode == MD_SMTP && @@ -456,6 +504,7 @@ smtp(e) /* now parse ESMTP arguments */ e->e_msgsize = 0; + p = delimptr; while (p != NULL && *p != '\0') { char *kp; @@ -470,7 +519,7 @@ smtp(e) kp = p; /* skip to the value portion */ - while (isascii(*p) && isalnum(*p) || *p == '-') + while ((isascii(*p) && isalnum(*p)) || *p == '-') p++; if (*p == '=') { @@ -534,9 +583,15 @@ smtp(e) a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e); if (a == NULL) break; - p = delimptr; + if (delimptr != NULL && *delimptr != '\0') + *delimptr++ = '\0'; + + /* do config file checking of the recipient */ + if (rscheck("check_rcpt", p, NULL, e) != EX_OK) + break; /* now parse ESMTP arguments */ + p = delimptr; while (p != NULL && *p != '\0') { char *kp; @@ -551,7 +606,7 @@ smtp(e) kp = p; /* skip to the value portion */ - while (isascii(*p) && isalnum(*p) || *p == '-') + while ((isascii(*p) && isalnum(*p)) || *p == '-') p++; if (*p == '=') { @@ -582,7 +637,7 @@ smtp(e) break; /* no errors during parsing, but might be a duplicate */ - e->e_to = p; + e->e_to = a->q_paddr; if (!bitset(QBADADDR, a->q_flags)) { message("250 Recipient ok%s", @@ -698,7 +753,7 @@ smtp(e) /* clean up a bit */ gotmail = FALSE; - dropenvelope(e); + dropenvelope(e, TRUE); CurEnv = e = newenvelope(e, CurEnv); e->e_flags = BlankEnvelope.e_flags; break; @@ -714,12 +769,24 @@ smtp(e) /* clean up a bit */ gotmail = FALSE; - dropenvelope(e); + dropenvelope(e, TRUE); CurEnv = e = newenvelope(e, CurEnv); break; case CMDVRFY: /* vrfy -- verify address */ case CMDEXPN: /* expn -- expand address */ + if (++nverifies >= MAXBADCOMMANDS) + { +#ifdef LOG + if (nverifies == MAXBADCOMMANDS && + LogLevel > 5) + { + syslog(LOG_INFO, "%.100s: VRFY attack?", + CurSmtpClient); + } +#endif + sleep(1); + } vrfy = c->cmdcode == CMDVRFY; if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, PrivacyFlags)) @@ -778,20 +845,48 @@ smtp(e) } while (vrfyqueue != NULL) { - extern void printvrfyaddr __P((ADDRESS *, bool)); + extern void printvrfyaddr __P((ADDRESS *, bool, bool)); a = vrfyqueue; while ((a = a->q_next) != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) continue; if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) - printvrfyaddr(vrfyqueue, a == NULL); + printvrfyaddr(vrfyqueue, a == NULL, vrfy); vrfyqueue = vrfyqueue->q_next; } if (InChild) finis(); break; + case CMDETRN: /* etrn -- force queue flush */ + if (strlen(p) <= 0) + { + message("500 Parameter required"); + break; + } + + /* crude way to avoid denial-of-service attacks */ + if (n_etrn++ >= 3) + sleep(3); + id = p; + if (*id == '@') + id++; + else + *--id = '@'; +#ifdef LOG + if (LogLevel > 5) + syslog(LOG_INFO, "%.100s: ETRN %s", + CurSmtpClient, + shortenstring(id, 203)); +#endif + QueueLimitRecipient = id; + ok = runqueue(TRUE, TRUE); + QueueLimitRecipient = NULL; + if (ok) + message("250 Queuing for node %s started", p); + break; + case CMDHELP: /* help -- give user info */ help(p); break; @@ -831,7 +926,12 @@ doquit: message("250 Only one transaction"); break; -# ifdef SMTPDEBUG + case CMDXUSR: /* initial (user) submission */ + UserSubmission = TRUE; + message("250 Initial submission"); + break; + +# if SMTPDEBUG case CMDDBGQSHOW: /* show queues */ printf("Send Queue="); printaddr(e->e_sendqueue, TRUE); @@ -1112,6 +1212,7 @@ rcpt_esmtp_args(a, kp, vp, e) ** Parameters: ** a -- the address to print ** last -- set if this is the last one. +** vrfy -- set if this is a VRFY command. ** ** Returns: ** none. @@ -1121,13 +1222,18 @@ rcpt_esmtp_args(a, kp, vp, e) */ void -printvrfyaddr(a, last) +printvrfyaddr(a, last, vrfy) register ADDRESS *a; bool last; + bool vrfy; { char fmtbuf[20]; - strcpy(fmtbuf, "250"); + if (vrfy && a->q_mailer != NULL && + !bitnset(M_VRFY250, a->q_mailer->m_flags)) + strcpy(fmtbuf, "252"); + else + strcpy(fmtbuf, "250"); fmtbuf[3] = last ? ' ' : '-'; if (a->q_fullname == NULL) @@ -1166,14 +1272,22 @@ runinchild(label, e) char *label; register ENVELOPE *e; { - int childpid; + pid_t childpid; if (!OneXact) { + /* + ** Disable child process reaping, in case ETRN has preceeded + ** MAIL command, and then fork. + */ + + (void) blocksignal(SIGCHLD); + childpid = dofork(); if (childpid < 0) { syserr("451 %s: cannot fork", label); + (void) releasesignal(SIGCHLD); return (1); } if (childpid > 0) @@ -1196,6 +1310,9 @@ runinchild(label, e) finis(); } + /* restore the child signal */ + (void) releasesignal(SIGCHLD); + return (1); } else @@ -1204,6 +1321,8 @@ runinchild(label, e) InChild = TRUE; QuickAbort = FALSE; clearenvelope(e, FALSE); + (void) setsignal(SIGCHLD, SIG_DFL); + (void) releasesignal(SIGCHLD); } } diff --git a/usr.sbin/sendmail/src/stab.c b/usr.sbin/sendmail/src/stab.c index cfb02c69686..a9d8736a270 100644 --- a/usr.sbin/sendmail/src/stab.c +++ b/usr.sbin/sendmail/src/stab.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)stab.c 8.6 (Berkeley) 8/31/95"; +static char sccsid[] = "@(#)stab.c 8.10 (Berkeley) 11/23/96"; #endif /* not lint */ # include "sendmail.h" @@ -71,6 +71,7 @@ stab(name, type, op) register STAB **ps; register int hfunc; register char *p; + int len; extern char lower(); if (tTd(36, 5)) @@ -129,11 +130,73 @@ stab(name, type, op) if (tTd(36, 5)) printf("entered\n"); + /* determine size of new entry */ +#ifdef _FFR_MEMORY_MISER + if (type >= ST_MCI) + len = sizeof s->s_mci; + else + len = -1; + switch (type) + { + case ST_CLASS: + len = sizeof s->s_class; + break; + + case ST_ADDRESS: + len = sizeof s->s_address; + break; + + case ST_MAILER: + len = sizeof s->s_mailer; + + case ST_ALIAS: + len = sizeof s->s_alias; + break; + + case ST_MAPCLASS: + len = sizeof s->s_mapclass; + break; + + case ST_MAP: + len = sizeof s->s_map; + break; + + case ST_HOSTSIG: + len = sizeof s->s_hostsig; + break; + + case ST_NAMECANON: + len = sizeof s->s_namecanon; + break; + + case ST_MACRO: + len = sizeof s->s_macro; + break; + + case ST_RULESET: + len = sizeof s->s_ruleset; + break; + + case ST_SERVICE: + len = sizeof s->s_service; + break; + } + if (len < 0) + { + syserr("stab: unknown symbol type %d", type); + len = sizeof s->s_value; + } + len += sizeof *s - sizeof s->s_value; +#else + len = sizeof *s; +#endif + /* make new entry */ - s = (STAB *) xalloc(sizeof *s); - bzero((char *) s, sizeof *s); + s = (STAB *) xalloc(len); + bzero((char *) s, len); s->s_name = newstr(name); s->s_type = type; + s->s_len = len; /* link it in */ *ps = s; diff --git a/usr.sbin/sendmail/src/stats.c b/usr.sbin/sendmail/src/stats.c index f59885a6067..6d3aaedca4d 100644 --- a/usr.sbin/sendmail/src/stats.c +++ b/usr.sbin/sendmail/src/stats.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)stats.c 8.5 (Berkeley) 5/28/95"; +static char sccsid[] = "@(#)stats.c 8.6 (Berkeley) 2/21/96"; #endif /* not lint */ # include "sendmail.h" diff --git a/usr.sbin/sendmail/src/sysexits.c b/usr.sbin/sendmail/src/sysexits.c index ad4f1e1cffb..cc1022a14e7 100644 --- a/usr.sbin/sendmail/src/sysexits.c +++ b/usr.sbin/sendmail/src/sysexits.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)sysexits.c 8.5 (Berkeley) 5/24/95"; +static char sccsid[] = "@(#)sysexits.c 8.6 (Berkeley) 2/21/96"; #endif /* not lint */ #include <sendmail.h> diff --git a/usr.sbin/sendmail/src/trace.c b/usr.sbin/sendmail/src/trace.c index 9762cab18f5..380ecb56540 100644 --- a/usr.sbin/sendmail/src/trace.c +++ b/usr.sbin/sendmail/src/trace.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)trace.c 8.4 (Berkeley) 5/28/95"; +static char sccsid[] = "@(#)trace.c 8.5 (Berkeley) 2/21/96"; #endif /* not lint */ # include "sendmail.h" diff --git a/usr.sbin/sendmail/src/udb.c b/usr.sbin/sendmail/src/udb.c index 15327554c66..8c34c23edae 100644 --- a/usr.sbin/sendmail/src/udb.c +++ b/usr.sbin/sendmail/src/udb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #if USERDB -static char sccsid [] = "@(#)udb.c 8.33.1.2 (Berkeley) 9/16/96 (with USERDB)"; +static char sccsid [] = "@(#)udb.c 8.46 (Berkeley) 12/1/96 (with USERDB)"; #else -static char sccsid [] = "@(#)udb.c 8.33.1.2 (Berkeley) 9/16/96 (without USERDB)"; +static char sccsid [] = "@(#)udb.c 8.46 (Berkeley) 12/1/96 (without USERDB)"; #endif #endif @@ -119,6 +119,8 @@ struct option char *name; char *val; }; + +extern int _udbx_init __P((void)); /* ** UDBEXPAND -- look up user in database and expand ** @@ -159,7 +161,6 @@ udbexpand(a, sendq, aliaslevel, e) int keylen; int naddrs; char keybuf[MAXKEY]; - char buf[BUFSIZ]; if (tTd(28, 1)) printf("udbexpand(%s)\n", a->q_paddr); @@ -172,8 +173,6 @@ udbexpand(a, sendq, aliaslevel, e) /* on first call, locate the database */ if (!UdbInitialized) { - extern int _udbx_init(); - if (_udbx_init() == EX_TEMPFAIL) return EX_TEMPFAIL; } @@ -187,7 +186,7 @@ udbexpand(a, sendq, aliaslevel, e) return EX_OK; /* if name is too long, assume it won't match */ - if (strlen(a->q_user) > sizeof keybuf - 12) + if (strlen(a->q_user) > (SIZE_T) sizeof keybuf - 12) return EX_OK; /* if name begins with a colon, it indicates our metadata */ @@ -203,6 +202,17 @@ udbexpand(a, sendq, aliaslevel, e) for (up = UdbEnts; !breakout; up++) { char *user; + int usersize; + int userleft; + char userbuf[MEMCHUNKSIZE]; +#if defined(HESIOD) && defined(HES_GETMAILHOST) + char pobuf[MAXNAME]; +#endif + + user = userbuf; + userbuf[0] = '\0'; + usersize = sizeof userbuf; + userleft = sizeof userbuf - 1; /* ** Select action based on entry type. @@ -227,17 +237,19 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 2)) printf("udbexpand: no match on %s (%d)\n", keybuf, keylen); - continue; + break; } if (tTd(28, 80)) printf("udbexpand: match %.*s: %.*s\n", - key.size, key.data, info.size, info.data); + (int) key.size, (char *) key.data, + (int) info.size, (char *) info.data); - naddrs = 0; a->q_flags &= ~QSELFREF; while (i == 0 && key.size == keylen && bcmp(key.data, keybuf, keylen) == 0) { + char *p; + if (bitset(EF_VRFYONLY, e->e_flags)) { a->q_flags |= QVERIFIED; @@ -245,24 +257,26 @@ udbexpand(a, sendq, aliaslevel, e) } breakout = TRUE; - if (info.size < sizeof buf) - user = buf; - else - user = xalloc(info.size + 1); - bcopy(info.data, user, info.size); + if (info.size >= userleft - 1) + { + char *nuser = xalloc(usersize + MEMCHUNKSIZE); + + bcopy(user, nuser, usersize); + if (user != userbuf) + free(user); + user = nuser; + usersize += MEMCHUNKSIZE; + userleft += MEMCHUNKSIZE; + } + p = &user[strlen(user)]; + if (p != user) + { + *p++ = ','; + userleft--; + } + bcopy(info.data, p, info.size); user[info.size] = '\0'; - - message("expanded to %s", user); -#ifdef LOG - if (LogLevel >= 10) - syslog(LOG_INFO, "%s: expand %.100s => %s", - e->e_id, e->e_to, - shortenstring(user, 203)); -#endif - naddrs += sendtolist(user, a, sendq, aliaslevel + 1, e); - - if (user != buf) - free(user); + userleft -= info.size; /* get the next record */ i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); @@ -270,8 +284,16 @@ udbexpand(a, sendq, aliaslevel, e) /* if nothing ever matched, try next database */ if (!breakout) - continue; + break; + message("expanded to %s", user); +#ifdef LOG + if (LogLevel >= 10) + syslog(LOG_INFO, "%s: expand %.100s => %s", + e->e_id, e->e_to, + shortenstring(user, 203)); +#endif + naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) { if (tTd(28, 5)) @@ -357,13 +379,24 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 2)) printf("hes_getmailhost(%s): %d\n", a->q_user, hes_error()); - continue; + break; } + if (strlen(hp->po_name) + strlen(hp->po_host) > + sizeof pobuf - 2) + { + if (tTd(28, 2)) + printf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n", + a->q_user, + hp->po_name, + hp->po_host); + break; + } + info.data = pobuf; snprintf(pobuf, sizeof pobuf, "%s@%s", hp->po_name, hp->po_host); info.size = strlen(info.data); #else - continue; + break; #endif } if (tTd(28, 80)) @@ -378,9 +411,7 @@ udbexpand(a, sendq, aliaslevel, e) } breakout = TRUE; - if (info.size < sizeof buf) - user = buf; - else + if (info.size >= usersize) user = xalloc(info.size + 1); bcopy(info.data, user, info.size); user[info.size] = '\0'; @@ -394,9 +425,6 @@ udbexpand(a, sendq, aliaslevel, e) #endif naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); - if (user != buf) - free(user); - if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) { if (tTd(28, 5)) @@ -428,17 +456,18 @@ udbexpand(a, sendq, aliaslevel, e) case UDB_REMOTE: /* not yet implemented */ - continue; + break; case UDB_FORWARD: if (bitset(EF_VRFYONLY, e->e_flags)) return EX_OK; i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; - if (i < sizeof buf) - user = buf; - else - user = xalloc(i + 1); - (void) snprintf(user, i, "%s@%s", + if (i >= usersize) + { + usersize = i + 1; + user = xalloc(usersize); + } + (void) snprintf(user, usersize, "%s@%s", a->q_user, up->udb_fwdhost); message("expanded to %s", user); a->q_flags &= ~QSELFREF; @@ -452,19 +481,19 @@ udbexpand(a, sendq, aliaslevel, e) } a->q_flags |= QDONTSEND; } - if (user != buf) - free(user); breakout = TRUE; break; case UDB_EOLIST: breakout = TRUE; - continue; + break; default: /* unknown entry type */ - continue; + break; } + if (user != userbuf) + free(user); } return EX_OK; } @@ -790,6 +819,7 @@ _udbx_init() { char *spec; int nopts; + int l; # if 0 auto int rcode; int nmx; @@ -798,6 +828,7 @@ _udbx_init() char *mxhosts[MAXMXHOSTS + 1]; # endif struct option opts[MAXUDBOPTS + 1]; + extern int _udb_parsespec __P((char *, struct option [], int)); while (*p == ' ' || *p == '\t' || *p == ',') p++; @@ -906,9 +937,20 @@ _udbx_init() #ifdef NEWDB case '/': /* look up remote name */ - up->udb_dbname = spec; + l = strlen(spec); + if (l > 3 && strcmp(&spec[l - 3], ".db") == 0) + { + up->udb_dbname = spec; + } + else + { + up->udb_dbname = xalloc(l + 4); + strcpy(up->udb_dbname, spec); + strcat(up->udb_dbname, ".db"); + } errno = 0; - up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); + up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY, + 0644, DB_BTREE, NULL); if (up->udb_dbp == NULL) { if (tTd(28, 1)) @@ -916,7 +958,8 @@ _udbx_init() int saveerrno = errno; printf("dbopen(%s): %s", - spec, errstring(errno)); + up->udb_dbname, + errstring(errno)); errno = saveerrno; } if (errno != ENOENT && errno != EACCES) @@ -924,11 +967,16 @@ _udbx_init() #ifdef LOG if (LogLevel > 2) syslog(LOG_ERR, "dbopen(%s): %s", - spec, errstring(errno)); + up->udb_dbname, + errstring(errno)); #endif up->udb_type = UDB_EOLIST; + if (up->udb_dbname != spec) + free(up->udb_dbname); goto tempfail; } + if (up->udb_dbname != spec) + free(up->udb_dbname); break; } up->udb_type = UDB_DBFETCH; @@ -950,7 +998,7 @@ badspec: { switch (up->udb_type) { -#ifdef DAEMON +#if DAEMON case UDB_REMOTE: printf("REMOTE: addr %s, timeo %d\n", anynet_ntoa((SOCKADDR *) &up->udb_addr), diff --git a/usr.sbin/sendmail/src/useful.h b/usr.sbin/sendmail/src/useful.h index 8f9009ecf0b..309a0df9db0 100644 --- a/usr.sbin/sendmail/src/useful.h +++ b/usr.sbin/sendmail/src/useful.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995 Eric P. Allman + * Copyright (c) 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)useful.h 8.4 (Berkeley) 4/21/95 + * @(#)useful.h 8.5 (Berkeley) 2/21/96 */ # include <sys/types.h> diff --git a/usr.sbin/sendmail/src/usersmtp.c b/usr.sbin/sendmail/src/usersmtp.c index c858658107d..7bd976bd4fa 100644 --- a/usr.sbin/sendmail/src/usersmtp.c +++ b/usr.sbin/sendmail/src/usersmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -35,17 +35,17 @@ # include "sendmail.h" #ifndef lint -#ifdef SMTP -static char sccsid[] = "@(#)usersmtp.c 8.65.1.2 (Berkeley) 9/16/96 (with SMTP)"; +#if SMTP +static char sccsid[] = "@(#)usersmtp.c 8.79 (Berkeley) 12/1/96 (with SMTP)"; #else -static char sccsid[] = "@(#)usersmtp.c 8.65.1.2 (Berkeley) 9/16/96 (without SMTP)"; +static char sccsid[] = "@(#)usersmtp.c 8.79 (Berkeley) 12/1/96 (without SMTP)"; #endif #endif /* not lint */ # include <sysexits.h> # include <errno.h> -# ifdef SMTP +# if SMTP /* ** USERSMTP -- run SMTP protocol from the user end. @@ -64,6 +64,7 @@ int SmtpPid; /* pid of mailer */ bool SmtpNeedIntro; /* need "while talking" in transcript */ extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); +extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)())); /* ** SMTPINIT -- initialize SMTP. ** @@ -83,7 +84,7 @@ extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); void smtpinit(m, mci, e) - struct mailer *m; + MAILER *m; register MCI *mci; ENVELOPE *e; { @@ -142,8 +143,10 @@ smtpinit(m, mci, e) SmtpPhase = mci->mci_phase = "client greeting"; setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); - if (r < 0 || REPLYTYPE(r) == 4) + if (r < 0) goto tempfail1; + if (REPLYTYPE(r) == 4) + goto tempfail2; if (REPLYTYPE(r) != 2) goto unavailable; @@ -152,11 +155,24 @@ smtpinit(m, mci, e) ** My mother taught me to always introduce myself. */ +#if _FFR_LMTP + if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags)) +#else if (bitnset(M_ESMTP, m->m_flags)) +#endif mci->mci_flags |= MCIF_ESMTP; tryhelo: +#if _FFR_LMTP + if (bitnset(M_LMTP, m->m_flags)) + { + smtpmessage("LHLO %s", m, mci, MyHostName); + SmtpPhase = mci->mci_phase = "client LHLO"; + } + else if (bitset(MCIF_ESMTP, mci->mci_flags)) +#else if (bitset(MCIF_ESMTP, mci->mci_flags)) +#endif { smtpmessage("EHLO %s", m, mci, MyHostName); SmtpPhase = mci->mci_phase = "client EHLO"; @@ -172,7 +188,12 @@ tryhelo: goto tempfail1; else if (REPLYTYPE(r) == 5) { +#if _FFR_LMTP + if (bitset(MCIF_ESMTP, mci->mci_flags) && + !bitnset(M_LMTP, m->m_flags)) +#else if (bitset(MCIF_ESMTP, mci->mci_flags)) +#endif { /* try old SMTP instead */ mci->mci_flags &= ~MCIF_ESMTP; @@ -181,7 +202,7 @@ tryhelo: goto unavailable; } else if (REPLYTYPE(r) != 2) - goto tempfail1; + goto tempfail2; /* ** Check to see if we actually ended up talking to ourself. @@ -193,11 +214,14 @@ tryhelo: if (p != NULL) *p = '\0'; if (!bitnset(M_NOLOOPCHECK, m->m_flags) && +#if _FFR_LMTP + !bitnset(M_LMTP, m->m_flags) && +#endif strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) { syserr("553 %s config error: mail loops back to me (MX problem?)", mci->mci_host); - mci->mci_exitstat = EX_CONFIG; + mci_setstat(mci, EX_CONFIG, NULL, NULL); mci->mci_errno = 0; smtpquit(m, mci, e); return; @@ -214,7 +238,7 @@ tryhelo: smtpmessage("VERB", m, mci); r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); if (r < 0) - goto tempfail2; + goto tempfail1; } if (mci->mci_state != MCIS_CLOSED) @@ -226,17 +250,25 @@ tryhelo: /* got a 421 error code during startup */ tempfail1: + if (mci->mci_errno == 0) + mci->mci_errno = errno; + mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); + if (mci->mci_state != MCIS_CLOSED) + smtpquit(m, mci, e); + return; + tempfail2: - mci->mci_exitstat = EX_TEMPFAIL; if (mci->mci_errno == 0) mci->mci_errno = errno; + /* XXX should use code from other end iff ENHANCEDSTATUSCODES */ + mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer); if (mci->mci_state != MCIS_CLOSED) smtpquit(m, mci, e); return; unavailable: - mci->mci_exitstat = EX_UNAVAILABLE; mci->mci_errno = errno; + mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer); smtpquit(m, mci, e); return; } @@ -327,7 +359,7 @@ helo_options(line, firstline, m, mci, e) int smtpmailfrom(m, mci, e) - struct mailer *m; + MAILER *m; MCI *mci; ENVELOPE *e; { @@ -383,14 +415,16 @@ smtpmailfrom(m, mci, e) else if (!bitset(MM_PASS8BIT, MimeMode)) { /* cannot just send a 8-bit version */ + extern char MsgBuf[]; + usrerr("%s does not support 8BITMIME", mci->mci_host); - mci->mci_status = "5.6.3"; + mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf); return EX_DATAERR; } if (bitset(MCIF_DSN, mci->mci_flags)) { - if (e->e_envid != NULL && strlen(e->e_envid) < (SIZE_T) l) + if (e->e_envid != NULL && strlen(e->e_envid) < (SIZE_T) (l - 7)) { strcat(optbuf, " ENVID="); strcat(optbuf, e->e_envid); @@ -444,16 +478,24 @@ smtpmailfrom(m, mci, e) SmtpPhase = mci->mci_phase = "client MAIL"; setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); r = reply(m, mci, e, TimeOuts.to_mail, NULL); - if (r < 0 || r == 421) + if (r < 0) { - /* communications failure/service shutting down */ - mci->mci_exitstat = EX_TEMPFAIL; + /* communications failure */ mci->mci_errno = errno; + mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); + smtpquit(m, mci, e); + return EX_TEMPFAIL; + } + else if (r == 421) + { + /* service shutting down */ + mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer); smtpquit(m, mci, e); return EX_TEMPFAIL; } else if (REPLYTYPE(r) == 4) { + mci_setstat(mci, EX_TEMPFAIL, smtptodsn(r), SmtpReplyBuffer); return EX_TEMPFAIL; } else if (REPLYTYPE(r) == 2) @@ -463,24 +505,25 @@ smtpmailfrom(m, mci, e) else if (r == 501) { /* syntax error in arguments */ - mci->mci_status = "5.5.2"; + mci_setstat(mci, EX_NOTSTICKY, "5.5.2", SmtpReplyBuffer); return EX_DATAERR; } else if (r == 553) { /* mailbox name not allowed */ - mci->mci_status = "5.1.3"; + mci_setstat(mci, EX_NOTSTICKY, "5.1.3", SmtpReplyBuffer); return EX_DATAERR; } else if (r == 552) { /* exceeded storage allocation */ - mci->mci_status = "5.2.2"; + mci_setstat(mci, EX_NOTSTICKY, "5.2.2", SmtpReplyBuffer); return EX_UNAVAILABLE; } else if (REPLYTYPE(r) == 5) { /* unknown error */ + mci_setstat(mci, EX_NOTSTICKY, "5.0.0", SmtpReplyBuffer); return EX_UNAVAILABLE; } @@ -494,6 +537,7 @@ smtpmailfrom(m, mci, e) #endif /* protocol error -- close up */ + mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); smtpquit(m, mci, e); return EX_PROTOCOL; } @@ -523,7 +567,6 @@ smtprcpt(to, m, mci, e) register int r; int l; char optbuf[MAXLINE]; - extern char *smtptodsn(); strcpy(optbuf, ""); l = sizeof optbuf - 1; @@ -531,7 +574,8 @@ smtprcpt(to, m, mci, e) { /* NOTIFY= parameter */ if (bitset(QHASNOTIFY, to->q_flags) && - bitset(QPRIMARY, to->q_flags)) + bitset(QPRIMARY, to->q_flags) && + !bitnset(M_LOCALMAILER, m->m_flags)) { bool firstone = TRUE; @@ -581,10 +625,25 @@ smtprcpt(to, m, mci, e) return EX_TEMPFAIL; else if (REPLYTYPE(r) == 2) return EX_OK; - else if (r == 550 || r == 551 || r == 553) + else if (r == 550) + { + to->q_status = "5.1.1"; + return EX_NOUSER; + } + else if (r == 551) + { + to->q_status = "5.1.6"; + return EX_NOUSER; + } + else if (r == 553) + { + to->q_status = "5.1.3"; return EX_NOUSER; + } else if (REPLYTYPE(r) == 5) + { return EX_UNAVAILABLE; + } #ifdef LOG if (LogLevel > 1) @@ -595,6 +654,7 @@ smtprcpt(to, m, mci, e) } #endif + mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); return EX_PROTOCOL; } /* @@ -602,6 +662,7 @@ smtprcpt(to, m, mci, e) ** ** Parameters: ** m -- mailer being sent to. +** mci -- the mailer connection information. ** e -- the envelope for this message. ** ** Returns: @@ -616,12 +677,13 @@ static void datatimeout(); int smtpdata(m, mci, e) - struct mailer *m; + MAILER *m; register MCI *mci; register ENVELOPE *e; { register int r; register EVENT *ev; + int rstat; time_t timeout; /* @@ -658,6 +720,7 @@ smtpdata(m, mci, e) } #endif smtprset(m, mci, e); + mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); return (EX_PROTOCOL); } @@ -670,8 +733,8 @@ smtpdata(m, mci, e) if (setjmp(CtxDataTimeout) != 0) { mci->mci_errno = errno; - mci->mci_exitstat = EX_TEMPFAIL; mci->mci_state = MCIS_ERROR; + mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); syserr("451 timeout writing message to %s", mci->mci_host); smtpquit(m, mci, e); return EX_TEMPFAIL; @@ -700,8 +763,8 @@ smtpdata(m, mci, e) { /* error during processing -- don't send the dot */ mci->mci_errno = EIO; - mci->mci_exitstat = EX_IOERR; mci->mci_state = MCIS_ERROR; + mci_setstat(mci, EX_IOERR, "4.4.2", NULL); smtpquit(m, mci, e); return EX_IOERR; } @@ -709,13 +772,17 @@ smtpdata(m, mci, e) /* terminate the message */ fprintf(mci->mci_out, ".%s", m->m_eol); if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d >>> .\n", getpid()); + fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid()); if (Verbose) nmessage(">>> ."); /* check for the results of the transaction */ - SmtpPhase = mci->mci_phase = "client DATA 250"; + SmtpPhase = mci->mci_phase = "client DATA status"; setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); +#if _FFR_LMTP + if (bitnset(M_LMTP, m->m_flags)) + return EX_OK; +#endif r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); if (r < 0) { @@ -723,15 +790,22 @@ smtpdata(m, mci, e) return EX_TEMPFAIL; } mci->mci_state = MCIS_OPEN; - e->e_statmsg = newstr(&SmtpReplyBuffer[4]); if (REPLYTYPE(r) == 4) - return EX_TEMPFAIL; + rstat = EX_TEMPFAIL; else if (REPLYCLASS(r) != 5) - /* fall through */ ; + rstat = EX_PROTOCOL; else if (REPLYTYPE(r) == 2) - return EX_OK; + rstat = EX_OK; else if (REPLYTYPE(r) == 5) - return EX_UNAVAILABLE; + rstat = EX_UNAVAILABLE; + else + rstat = EX_PROTOCOL; + mci_setstat(mci, rstat, smtptodsn(r), SmtpReplyBuffer); + if (e->e_statmsg != NULL) + free(e->e_statmsg); + e->e_statmsg = newstr(&SmtpReplyBuffer[4]); + if (rstat != EX_PROTOCOL) + return rstat; #ifdef LOG if (LogLevel > 1) { @@ -740,7 +814,7 @@ smtpdata(m, mci, e) shortenstring(SmtpReplyBuffer, 403)); } #endif - return EX_PROTOCOL; + return rstat; } @@ -750,10 +824,66 @@ datatimeout() longjmp(CtxDataTimeout, 1); } /* +** SMTPGETSTAT -- get status code from DATA in LMTP +** +** Parameters: +** m -- the mailer to which we are sending the message. +** mci -- the mailer connection structure. +** e -- the current envelope. +** +** Returns: +** The exit status corresponding to the reply code. +*/ + +#if _FFR_LMTP + +int +smtpgetstat(m, mci, e) + MAILER *m; + MCI *mci; + ENVELOPE *e; +{ + int r; + int stat; + + /* check for the results of the transaction */ + r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); + if (r < 0) + { + smtpquit(m, mci, e); + return EX_TEMPFAIL; + } + if (e->e_statmsg != NULL) + free(e->e_statmsg); + e->e_statmsg = newstr(&SmtpReplyBuffer[4]); + if (REPLYTYPE(r) == 4) + stat = EX_TEMPFAIL; + else if (REPLYCLASS(r) != 5) + stat = EX_PROTOCOL; + else if (REPLYTYPE(r) == 2) + stat = EX_OK; + else if (REPLYTYPE(r) == 5) + stat = EX_UNAVAILABLE; + mci_setstat(mci, stat, smtptodsn(r), SmtpReplyBuffer); +#ifdef LOG + if (LogLevel > 1 && stat == EX_PROTOCOL) + { + syslog(LOG_CRIT, "%s: %.100s: SMTP DATA-3 protocol error: %s", + e->e_id, mci->mci_host, + shortenstring(SmtpReplyBuffer, 403)); + } +#endif + return stat; +} + +#endif +/* ** SMTPQUIT -- close the SMTP connection. ** ** Parameters: ** m -- a pointer to the mailer. +** mci -- the mailer connection information. +** e -- the current envelope. ** ** Returns: ** none. @@ -906,6 +1036,7 @@ reply(m, mci, e, timeout, pfunc) if (p == NULL) { bool oldholderrs; + extern char MsgBuf[]; /* if the remote end closed early, fake an error */ if (errno == 0) @@ -916,10 +1047,10 @@ reply(m, mci, e, timeout, pfunc) # endif /* ECONNRESET */ mci->mci_errno = errno; - mci->mci_exitstat = EX_TEMPFAIL; oldholderrs = HoldErrs; HoldErrs = TRUE; usrerr("451 reply: read error from %s", mci->mci_host); + mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf); /* if debugging, pause so we can see state */ if (tTd(18, 100)) @@ -1054,7 +1185,8 @@ smtpmessage(f, m, mci, va_alist) if (tTd(18, 1) || Verbose) nmessage(">>> %s", SmtpMsgBuffer); if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer); + fprintf(TrafficLogFile, "%05d >>> %s\n", + (int) getpid(), SmtpMsgBuffer); if (mci->mci_out != NULL) { fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, diff --git a/usr.sbin/sendmail/src/util.c b/usr.sbin/sendmail/src/util.c index 2a77fad6b67..eae587ba25e 100644 --- a/usr.sbin/sendmail/src/util.c +++ b/usr.sbin/sendmail/src/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)util.c 8.84.1.4 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)util.c 8.113 (Berkeley) 11/24/96"; #endif /* not lint */ # include "sendmail.h" @@ -215,7 +215,7 @@ printav(av) while (*av != NULL) { if (tTd(0, 44)) - printf("\n\t%08x=", *av); + printf("\n\t%08lx=", (u_long) *av); else (void) putchar(' '); xputs(*av++); @@ -260,50 +260,71 @@ xputs(s) { register int c; register struct metamac *mp; + bool shiftout = FALSE; extern struct metamac MetaMacros[]; if (s == NULL) { - printf("<null>"); + printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off); return; } while ((c = (*s++ & 0377)) != '\0') { + if (shiftout) + { + printf("%s", TermEscape.te_rv_off); + shiftout = FALSE; + } if (!isascii(c)) { if (c == MATCHREPL) { - putchar('$'); - continue; + printf("%s$", TermEscape.te_rv_on); + shiftout = TRUE; + if (*s == '\0') + continue; + c = *s++ & 0377; + goto printchar; } if (c == MACROEXPAND) { - putchar('$'); + printf("%s$", TermEscape.te_rv_on); + shiftout = TRUE; if (strchr("=~&?", *s) != NULL) putchar(*s++); if (bitset(0200, *s)) printf("{%s}", macname(*s++ & 0377)); + else + printf("%c", *s++); continue; } for (mp = MetaMacros; mp->metaname != '\0'; mp++) { if ((mp->metaval & 0377) == c) { - printf("$%c", mp->metaname); + printf("%s$%c", + TermEscape.te_rv_on, + mp->metaname); + shiftout = TRUE; break; } } if (c == MATCHCLASS || c == MATCHNCLASS) { - if (!bitset(0200, *s)) - continue; - printf("{%s}", macname(*s++ & 0377)); + if (bitset(0200, *s)) + printf("{%s}", macname(*s++ & 0377)); + else + printf("%c", *s++); } if (mp->metaname != '\0') continue; - (void) putchar('\\'); + + /* unrecognized meta character */ + printf("%sM-", TermEscape.te_rv_on); + shiftout = TRUE; c &= 0177; } + printchar: if (isprint(c)) { putchar(c); @@ -324,15 +345,25 @@ xputs(s) case '\t': c = 't'; break; - - default: + } + if (!shiftout) + { + printf("%s", TermEscape.te_rv_on); + shiftout = TRUE; + } + if (isprint(c)) + { + (void) putchar('\\'); + (void) putchar(c); + } + else + { (void) putchar('^'); (void) putchar(c ^ 0100); - continue; } - (void) putchar('\\'); - (void) putchar(c); } + if (shiftout) + printf("%s", TermEscape.te_rv_off); (void) fflush(stdout); } /* @@ -384,11 +415,11 @@ makelower(p) */ void -buildfname(gecos, login, buf, bufsiz) +buildfname(gecos, login, buf, buflen) register char *gecos; char *login; char *buf; - int bufsiz; + int buflen; { register char *p; register char *bp = buf; @@ -396,16 +427,21 @@ buildfname(gecos, login, buf, bufsiz) if (*gecos == '*') gecos++; - for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%' - && ((bp - buf) <= (bufsiz - 1)); p++) + /* copy gecos, interpolating & to be full name */ + for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) { + if (bp >= &buf[buflen - 1]) + { + /* buffer overflow -- just use login name */ + snprintf(buf, buflen, "%s", login); + return; + } if (*p == '&') { - (void) strncpy(bp, login, (bufsiz - (bp - buf) - 1)); - buf[bufsiz - 1] = '\0'; + /* interpolate full name */ + snprintf(bp, buflen - (bp - buf), "%s", login); *bp = toupper(*bp); - while (*bp != '\0') - bp++; + bp += strlen(bp); } else *bp++ = *p; @@ -455,8 +491,8 @@ buildfname(gecos, login, buf, bufsiz) int safefile(fn, uid, gid, uname, flags, mode, st) char *fn; - uid_t uid; - gid_t gid; + UID_T uid; + GID_T gid; char *uname; int flags; int mode; @@ -470,7 +506,7 @@ safefile(fn, uid, gid, uname, flags, mode, st) if (tTd(44, 4)) printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n", - fn, uid, gid, flags, mode); + fn, (int) uid, (int) gid, flags, mode); errno = 0; if (st == NULL) st = &fstbuf; @@ -537,7 +573,7 @@ safefile(fn, uid, gid, uname, flags, mode, st) bitset(S_IXGRP, stbuf.st_mode)) continue; #ifndef NO_GROUP_SET - if (uname != NULL && + if (uname != NULL && !DontInitGroups && ((gr != NULL && gr->gr_gid == stbuf.st_gid) || (gr = getgrgid(stbuf.st_gid)) != NULL)) { @@ -598,8 +634,8 @@ safefile(fn, uid, gid, uname, flags, mode, st) } ret = errno; if (tTd(44, 4)) - printf("\t[final dir %s uid %d mode %o] %s\n", - fn, stbuf.st_uid, stbuf.st_mode, + printf("\t[final dir %s uid %d mode %lo] %s\n", + fn, (int) stbuf.st_uid, (u_long) stbuf.st_mode, errstring(ret)); *p = '/'; st->st_mode = ST_MODE_NOFILE; @@ -627,6 +663,12 @@ safefile(fn, uid, gid, uname, flags, mode, st) printf("\t[exec bits %o]\tEPERM]\n", st->st_mode); return EPERM; } + if (st->st_nlink > 1) + { + if (tTd(44, 4)) + printf("\t[link count %d]\tEPERM\n", st->st_nlink); + return EPERM; + } if (uid == 0 && !bitset(SFF_ROOTOK, flags)) mode >>= 6; @@ -636,7 +678,7 @@ safefile(fn, uid, gid, uname, flags, mode, st) if (st->st_gid == gid) ; #ifndef NO_GROUP_SET - else if (uname != NULL && + else if (uname != NULL && !DontInitGroups && ((gr != NULL && gr->gr_gid == st->st_gid) || (gr = getgrgid(st->st_gid)) != NULL)) { @@ -653,8 +695,9 @@ safefile(fn, uid, gid, uname, flags, mode, st) mode >>= 3; } if (tTd(44, 4)) - printf("\t[uid %d, stat %o, mode %o] ", - st->st_uid, st->st_mode, mode); + printf("\t[uid %d, nlink %d, stat %lo, mode %lo] ", + (int) st->st_uid, (int) st->st_nlink, + (u_long) st->st_mode, (u_long) mode); if ((st->st_uid == uid || st->st_uid == 0 || !bitset(SFF_MUSTOWN, flags)) && (st->st_mode & mode) == mode) @@ -800,12 +843,12 @@ struct omodes char *farg; } OpenModes[] = { - O_ACCMODE, O_RDONLY, "r", - O_ACCMODE|O_APPEND, O_WRONLY, "w", - O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a", - O_TRUNC, 0, "w+", - O_APPEND, O_APPEND, "a+", - 0, 0, "r+", + { O_ACCMODE, O_RDONLY, "r" }, + { O_ACCMODE|O_APPEND, O_WRONLY, "w" }, + { O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a" }, + { O_TRUNC, 0, "w+" }, + { O_APPEND, O_APPEND, "a+" }, + { 0, 0, "r+" }, }; FILE * @@ -929,7 +972,7 @@ putxline(l, mci, pxflags) p = &l[strlen(l)]; if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d >>> ", getpid()); + fprintf(TrafficLogFile, "%05d >>> ", (int) getpid()); /* check for line overflow */ while (mci->mci_mailer->m_linelimit > 0 && @@ -961,7 +1004,7 @@ putxline(l, mci, pxflags) (void) putc(' ', mci->mci_out); if (TrafficLogFile != NULL) fprintf(TrafficLogFile, "%s!\n%05d >>> ", - l, getpid()); + l, (int) getpid()); *q = svchar; l = q; slop = 1; @@ -975,6 +1018,15 @@ putxline(l, mci, pxflags) if (TrafficLogFile != NULL) (void) putc('.', TrafficLogFile); } + else if (l[0] == 'F' && slop == 0 && + bitset(PXLF_MAPFROM, pxflags) && + strncmp(l, "From ", 5) == 0 && + bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) + { + (void) putc('>', mci->mci_out); + if (TrafficLogFile != NULL) + (void) putc('>', TrafficLogFile); + } if (TrafficLogFile != NULL) fprintf(TrafficLogFile, "%.*s\n", p - l, l); for ( ; l < p; ++l) @@ -1041,7 +1093,7 @@ xfclose(fp, a, b) char *a, *b; { if (tTd(53, 99)) - printf("xfclose(%x) %s %s\n", fp, a, b); + printf("xfclose(%lx) %s %s\n", (u_long) fp, a, b); #if XDEBUG if (fileno(fp) == 1) syserr("xfclose(%s %s): fd = 1", a, b); @@ -1094,9 +1146,11 @@ sfgets(buf, siz, fp, timeout, during) if (setjmp(CtxReadTimeout) != 0) { # ifdef LOG - syslog(LOG_NOTICE, - "timeout waiting for input from %.100s during %s", - CurHostName? CurHostName: "local", during); + if (LogLevel > 1) + syslog(LOG_NOTICE, + "timeout waiting for input from %.100s during %s", + CurHostName ? CurHostName : "local", + during); # endif errno = 0; usrerr("451 timeout waiting for input during %s", @@ -1130,11 +1184,11 @@ sfgets(buf, siz, fp, timeout, during) { buf[0] = '\0'; if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid()); + fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid()); return (NULL); } if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf); + fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf); if (SevenBitInput) { for (p = buf; *p != '\0'; p++) @@ -1324,19 +1378,21 @@ atooct(s) int waitfor(pid) - int pid; + pid_t pid; { #ifdef WAITUNION union wait st; #else auto int st; #endif - int i; + pid_t i; do { errno = 0; i = wait(&st); + if (i > 0) + proc_list_drop(i); } while ((i >= 0 || errno == EINTR) && i != pid); if (i < 0) return -1; @@ -1455,7 +1511,7 @@ checkfd012(where) for (i = 0; i < 3; i++) { - if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP) + if (fstat(i, &stbuf) < 0 && errno == EBADF) { /* oops.... */ int fd; @@ -1472,6 +1528,90 @@ checkfd012(where) #endif /* XDEBUG */ } /* +** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging +** +** Parameters: +** fd -- file descriptor to check. +** where -- tag to print on failure. +** +** Returns: +** none. +*/ + +void +checkfdopen(fd, where) + int fd; + char *where; +{ +#if XDEBUG + struct stat st; + + if (fstat(fd, &st) < 0 && errno == EBADF) + { + syserr("checkfdopen(%d): %s not open as expected!", fd, where); + printopenfds(TRUE); + } +#endif +} +/* +** CHECKFDS -- check for new or missing file descriptors +** +** Parameters: +** where -- tag for printing. If null, take a base line. +** +** Returns: +** none +** +** Side Effects: +** If where is set, shows changes since the last call. +*/ + +void +checkfds(where) + char *where; +{ + int maxfd; + register int fd; + bool printhdr = TRUE; + int save_errno = errno; + static BITMAP baseline; + extern int DtableSize; + + if (DtableSize > 256) + maxfd = 256; + else + maxfd = DtableSize; + if (where == NULL) + clrbitmap(baseline); + + for (fd = 0; fd < maxfd; fd++) + { + struct stat stbuf; + + if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP) + { + if (!bitnset(fd, baseline)) + continue; + clrbitn(fd, baseline); + } + else if (!bitnset(fd, baseline)) + setbitn(fd, baseline); + else + continue; + + /* file state has changed */ + if (where == NULL) + continue; + if (printhdr) + { + syslog(LOG_DEBUG, "%s: changed fds:", where); + printhdr = FALSE; + } + dumpfd(fd, TRUE, TRUE); + } + errno = save_errno; +} +/* ** PRINTOPENFDS -- print the open file descriptors (for debugging) ** ** Parameters: @@ -1527,12 +1667,17 @@ dumpfd(fd, printclosed, logit) if (fstat(fd, &st) < 0) { - if (printclosed || errno != EBADF) + if (errno != EBADF) { snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)", errstring(errno)); goto printit; } + else if (printclosed) + { + snprintf(p, SPACELEFT(buf, p), "CLOSED"); + goto printit; + } return; } @@ -1797,8 +1942,10 @@ prog_open(argv, pfd, e) /* run as default user */ endpwent(); - setgid(DefGid); - setuid(DefUid); + if (setgid(DefGid) < 0) + syserr("prog_open: setgid(%ld) failed", (long) DefGid); + if (setuid(DefUid) < 0) + syserr("prog_open: setuid(%ld) failed", (long) DefUid); /* run in some directory */ if (ProgMailer != NULL) @@ -1841,6 +1988,7 @@ prog_open(argv, pfd, e) if (transienterror(saveerrno)) _exit(EX_OSERR); _exit(EX_CONFIG); + return -1; /* avoid compiler warning on IRIX */ } /* ** GET_COLUMN -- look up a Column in a line buffer @@ -1889,7 +2037,7 @@ get_column(line, col, delim, buf, buflen) if (col == 0 && delim == '\0') { - while (*begin && isspace(*begin)) + while (*begin != '\0' && isascii(*begin) && isspace(*begin)) begin++; } @@ -1900,14 +2048,14 @@ get_column(line, col, delim, buf, buflen) begin++; if (delim == '\0') { - while (*begin && isspace(*begin)) + while (*begin != '\0' && isascii(*begin) && isspace(*begin)) begin++; } } end = strpbrk(begin, delimbuf); if (end == NULL) - i = strlen(buf); + i = strlen(begin); else i = end - begin; if (i >= buflen) @@ -2007,3 +2155,178 @@ denlstring(s, strict, logattacks) return bp; } +/* +** PATH_IS_DIR -- check to see if file exists and is a directory. +** +** Parameters: +** pathname -- pathname to check for directory-ness. +** createflag -- if set, create directory if needed. +** +** Returns: +** TRUE -- if the indicated pathname is a directory +** FALSE -- otherwise +*/ + +int +path_is_dir(pathname, createflag) + char *pathname; + bool createflag; +{ + struct stat statbuf; + + if (stat(pathname, &statbuf) < 0) + { + if (errno != ENOENT || !createflag) + return FALSE; + if (mkdir(pathname, 0755) < 0) + return FALSE; + return TRUE; + } + if (!S_ISDIR(statbuf.st_mode)) + { + errno = ENOTDIR; + return FALSE; + } + return TRUE; +} +/* +** PROC_LIST_ADD -- add process id to list of our children +** +** Parameters: +** pid -- pid to add to list. +** +** Returns: +** none +*/ + +static pid_t *ProcListVec = NULL; +static int ProcListSize = 0; + +#define NO_PID ((pid_t) 0) +#ifndef PROC_LIST_SEG +# define PROC_LIST_SEG 32 /* number of pids to alloc at a time */ +#endif + +void +proc_list_add(pid) + pid_t pid; +{ + int i; + extern void proc_list_probe __P((void)); + + for (i = 0; i < ProcListSize; i++) + { + if (ProcListVec[i] == NO_PID) + break; + } + if (i >= ProcListSize) + { + /* probe the existing vector to avoid growing infinitely */ + proc_list_probe(); + + /* now scan again */ + for (i = 0; i < ProcListSize; i++) + { + if (ProcListVec[i] == NO_PID) + break; + } + } + if (i >= ProcListSize) + { + /* grow process list */ + pid_t *npv; + + npv = (pid_t *) xalloc(sizeof (pid_t) * (ProcListSize + PROC_LIST_SEG)); + if (ProcListSize > 0) + { + bcopy(ProcListVec, npv, ProcListSize * sizeof (pid_t)); + free(ProcListVec); + } + for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) + npv[i] = NO_PID; + i = ProcListSize; + ProcListSize += PROC_LIST_SEG; + ProcListVec = npv; + } + ProcListVec[i] = pid; + CurChildren++; +} +/* +** PROC_LIST_DROP -- drop pid from process list +** +** Parameters: +** pid -- pid to drop +** +** Returns: +** none. +*/ + +void +proc_list_drop(pid) + pid_t pid; +{ + int i; + + for (i = 0; i < ProcListSize; i++) + { + if (ProcListVec[i] == pid) + { + ProcListVec[i] = NO_PID; + break; + } + } + if (CurChildren > 0) + CurChildren--; +} +/* +** PROC_LIST_CLEAR -- clear the process list +** +** Parameters: +** none. +** +** Returns: +** none. +*/ + +void +proc_list_clear() +{ + int i; + + for (i = 0; i < ProcListSize; i++) + ProcListVec[i] = NO_PID; + CurChildren = 0; +} +/* +** PROC_LIST_PROBE -- probe processes in the list to see if they still exist +** +** Parameters: +** none +** +** Returns: +** none +*/ + +void +proc_list_probe() +{ + int i; + + for (i = 0; i < ProcListSize; i++) + { + if (ProcListVec[i] == NO_PID) + continue; + if (kill(ProcListVec[i], 0) < 0) + { +#ifdef LOG + if (LogLevel > 3) + syslog(LOG_DEBUG, "proc_list_probe: lost pid %d", + ProcListVec[i]); +#endif + ProcListVec[i] = NO_PID; + CurChildren--; + } + } + if (CurChildren < 0) + CurChildren = 0; +} diff --git a/usr.sbin/sendmail/src/version.c b/usr.sbin/sendmail/src/version.c index 6197db912f9..617e11afbfe 100644 --- a/usr.sbin/sendmail/src/version.c +++ b/usr.sbin/sendmail/src/version.c @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)version.c 8.7.6.4 (Berkeley) 9/17/96"; +static char sccsid[] = "@(#)version.c 8.8.4.4 (Berkeley) 12/2/96"; #endif /* not lint */ -char Version[] = "8.7.6"; +char Version[] = "8.8.4"; diff --git a/usr.sbin/sendmail/test/Results b/usr.sbin/sendmail/test/Results index 133f28bdf62..e889cadca3c 100644 --- a/usr.sbin/sendmail/test/Results +++ b/usr.sbin/sendmail/test/Results @@ -10,8 +10,11 @@ SunOS 4.1.3 OK 93.09.25 Robert Elz BSD 4.4 OK 93.07.19 eric (wierd results, but functional) BSD 4.3Utah OK 93.07.19 eric +FreeBSD 2.1-sta OK 96.04.14 Jaye Mathisen <mrcpu@cdsnet.net> + Ultrix 4.2A OK 93.07.19 eric Ultrix 4.3A OK 93.07.19 Allan Johannesen +Ultrix 4.5 OK 96.09.18 Gregory Neil Shapiro <gshapiro@wpi.edu> HP-UX 8.07 OK 93.07.19 eric (on 7xx series) HP-UX 8.02 OK 93.07.19 Michael Corrigan (on 8xx series) @@ -21,10 +24,15 @@ HP-UX 9.01 OK 93.11.19 Cassidy (on 7xx series) Solaris 2.1 Solaris 2.2 FAIL 93.07.19 Bill Wisner Solaris 2.3 FAIL 95.11.22 Scott J. Kramer <sjk@lux.com> +Solaris 2.5 OK 96.02.29 Carson Gaspar <carson@lehman.com> +Solaris 2.5.1 OK 96.11.29 Gregory Neil Shapiro <gshapiro@wpi.edu> OSF/1 T1.3-4 OK 93.07.19 eric (on DEC Alpha) OSF/1 1.3 OK 94.12.10 Jeff A. Earickson (on Intel Paragon) +OSF/1 3.2D OK 96.09.18 Gregory Neil Shapiro <gshapiro@wpi.edu> +OSF/1 4.0 OK 96.09.18 Gregory Neil Shapiro <gshapiro@wpi.edu> +CxOS 11.5 OK 96.07.08 Eric Schnoebelen <eric@cirr.com> CxOS 11.0 OK 93.01.21 Eric Schnoebelen (CxOS 11.0 beta 1) CxOS 10.x OK 93.01.21 Eric Schnoebelen @@ -32,10 +40,13 @@ AIX 3.1.5 FAIL 93.08.07 David J. N. Begley AIX 3.2.3e FAIL 93.07.26 Steve Bauer <sbauer@silver.sdsmt.edu> AIX 3.2.4 FAIL 93.10.07 David J. N. Begley AIX 3.2.5 FAIL 94.05.17 Steve Bauer <sbauer@hpcmmib.hpc.sdsmt.edu> +AIX 4.1 FAIL 96.10.21 Hakan Lindholm <hakan@af.lu.se> +AIX 4.2 OK 96.10.16 Steve Bauer <sbauer@krypton.hpc.sdsmt.edu> IRIX 4.0.4 OK 93.09.25 Robert Elz IRIX 5.2 OK 94.12.06 Mark Andrews <mandrews@alias.com> IRIX 5.3 OK 94.12.06 Mark Andrews <mandrews@alias.com> +IRIX 6.2 OK 96.09.16 Kari E. Hurtta <Kari.Hurtta@ozone.FMI.FI> SCO 3.2v4.0 OK 93.10.02 Peter Wemm (with -lsocket from 3.2v4 devsys) @@ -47,6 +58,7 @@ Linux 0.99p13 OK 93.09.27 Christian Kuhtz Linux 0.99p14 OK 93.11.30 Christian Kuhtz <chk@data-hh.Hanse.DE> Linux 1.0 OK 94.03.19 Shayne Smith <snsmith@rastus.brisnet.org.au> Linux 1.2.13 OK 95.11.02 Sven Neuhaus <sven@ping.de> +Linux 2.0.17 OK 96.09.03 Horst von Brand <vonbrand@sleipnir.valparaiso.cl> BSD/386 1.0 OK 93.11.13 Tony Sanders @@ -63,8 +75,23 @@ OPSYS VERSION STATUS DATE TESTER/NOTES Solaris 2.3 OK 95.11.22 Scott J. Kramer <sjk@lux.com> Solaris 2.4 OK 95.09.22 Thomas 'Mike' Michlmayr <mike@cosy.sbg.ac.at> +Solaris 2.5 OK 96.02.29 Carson Gaspar <carson@lehman.com> +Solaris 2.5.1 OK 96.11.29 Gregory Neil Shapiro <gshapiro@wpi.edu> Linux 1.2.13 FAIL 95.11.02 Sven Neuhaus <sven@ping.de> +Linux 2.0.17 FAIL 96.09.03 Horst von Brand <vonbrand@sleipnir.valparaiso.cl> + +AIX 4.1 OK 96.10.21 Hakan Lindholm <hakan@af.lu.se> IRIX 5.2 OK 95.12.01 Mark Andrews <mandrews@aw.sgi.com> IRIX 5.3 OK 95.12.01 Mark Andrews <mandrews@aw.sgi.com> +IRIX 6.2 OK 96.09.16 Kari E. Hurtta <Kari.Hurtta@ozone.FMI.FI> + +FreeBSD 2.1-sta OK 96.04.14 Jaye Mathisen <mrcpu@cdsnet.net> + +Ultrix 4.5 FAIL 96.09.18 Gregory Neil Shapiro <gshapiro@wpi.edu> + +OSF/1 3.2D OK 96.09.18 Gregory Neil Shapiro <gshapiro@wpi.edu> +OSF/1 4.0 OK 96.09.18 Gregory Neil Shapiro <gshapiro@wpi.edu> + +CxOS 11.5 FAIL 96.07.08 Eric Schnoebelen <eric@cirr.com> diff --git a/usr.sbin/sendmail/test/t_seteuid.c b/usr.sbin/sendmail/test/t_seteuid.c index 4dfe3d63bf7..f3bd52902f9 100644 --- a/usr.sbin/sendmail/test/t_seteuid.c +++ b/usr.sbin/sendmail/test/t_seteuid.c @@ -108,6 +108,7 @@ main() exit(1); } + printf("\nIt is safe to define USESETEUID on this system\n"); exit(0); } diff --git a/usr.sbin/sendmail/test/t_setreuid.c b/usr.sbin/sendmail/test/t_setreuid.c index ca9a06f448b..66220682224 100644 --- a/usr.sbin/sendmail/test/t_setreuid.c +++ b/usr.sbin/sendmail/test/t_setreuid.c @@ -120,6 +120,7 @@ main() exit(1); } + printf("\nIt is safe to define HASSETREUID on this system\n"); exit(0); } |