From: Jeremy Harris Date: Tue, 23 Jul 2024 11:36:19 +0000 (+0100) Subject: Retire Exim 3 up-conversion scripts and docs X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/56ed4f42c83f576badd797a6ec6ba81ad73166ea Retire Exim 3 up-conversion scripts and docs --- diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index abf90ca1f..2a7a70c47 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -19,6 +19,9 @@ JH/02 Add transaction support for hintsdbs. The providers supported are tdb and JH/03 With dkim_verify_minimal, avoid calling the DKIM ACL after the first good verify. +JH/04 Remove the docs and support scripts dealing with conversion of Exim + version 3 installations. + Exim version 4.98 ----------------- diff --git a/doc/doc-txt/Exim3.upgrade b/doc/doc-txt/Exim3.upgrade deleted file mode 100644 index 4ab94c4e9..000000000 --- a/doc/doc-txt/Exim3.upgrade +++ /dev/null @@ -1,671 +0,0 @@ -This document contains information about upgrading Exim to the last of the 3.xx -releases. It is provided to help anybody who is upgrading to release 4.xx from -a release that is earlier than 3.33. It goes back as far as release 2.12. If -you are upgrading to release 4.xx from an even earlier release, it is probably -best to start again from the default configuration. - - -Upgrading from release 3.16 ---------------------------- - -1. The way LDAP returns values for multiple attributes has been changed to be -the same as the NIS+ lookup. - -If you specify multiple attributes, they are returned as space-separated -strings, quoted if necessary. - -e.g. ldap:///o=base?attr1,attr2?sub?(uid=fred) - - used to give: attr1=value one, attr2=value2 - now gives: attr1="value one" attr2=value2 - -If you don't specify any attributes in the search, you now get them in -the tagged format as well. - -e.g. ldap:///o=base??sub?(uid=fred) - - used to give: top, value one, value2 - now gives: objectClass=top attr1="value one" attr2=value2 - -The reason for these changes is so that the results can be safely parsed - -in fact, the existing ${extract{key}{val}} function does this nicely. -This in turn allows a single LDAP query to be reused - one query can return -the destination delivery address, the quota, and so forth. - -This is NOT a backwards compatible change, so there is a compile-time option -to reverse it in the src/lookups/ldap.c module, for use in emergency. But it is -not thought that the old behaviour was particularly useful as it stood, because -a field that contained ',' or '=' would make the result unparseable. - -In the common case where you explicitly ask for a single attribute in your -LDAP query, the behaviour is unchanged - the result is not quoted, and if there -are multiple values they are comma-separated. - -2. The hosts_max_try option in the smtp transport limits the number of IP -addresses that will actually be tried during one delivery attempt. The default -is 5. Previously, all available addresses were tried. - -3. The extension of the "extract" expansion item has resulted in a change to -the way Exim decides between the keyed form and the numeric form. If the first -argument consists entirely of digits, the numeric form is assumed. This means -that it is impossible to have keys that are digit strings, without manipulating -the data first (e.g. by using ${sg} to add a letter to each key). - - -Upgrading from release 3.15 ---------------------------- - -1. The handling of "freeze" and "fail" in system filter files has changed. -Previously, any deliveries set up by a filter that ended with "freeze" or -"fail" were discarded. This no longer happens; such deliveries are honoured. -A consequence of this is that first_delivery becomes false after freezing in a -system filter; previously it remained true until a real delivery attempt -happened. - - -Upgrading from release 3.13 ---------------------------- - -1. The handling of maildir_tag has been changed (see NewStuff). There are two -small incompatibilities: (a) Exim now inserts a leading colon only if the -string begins with an alphanumeric character. So if you were using a string -starting with a special character, you will have to add the leading colon to -it to remain compatible. (b) The expansion of maildir_tag now happens after the -file has been written, and $message_size is updated to the correct file size -before the expansion. The tag is not used on the temporary file (it was -previously). - -2. The handling of Exim's configuration has changed in two ways: - - (a) Any line may be continued by ending it with a backslash. Trailing white - space after the backslash, and leading white space on continuation lines is - ignored. This means that quotes are no longer needed just to make it possible - to continue an option setting. The difference between quoted and non-quoted - strings is that quoted strings are processed for internal backslashed items - such as \n. The only possible incompatibility of this change is if any - existing configuration has a non-quoted line ended in backslash, which seems - a very remote possibility. - - (b) All lists, with the exception of log_file_path, can now use a different - character to colon as the separator. This is specified by starting the list - with /opt/exim/configure.new - -The way the script merges an accept/reject/reject_except triple into a single -accept option is to put the reject_except list first, followed by the reject -list with every item negated, followed by the accept list. For example, if an -old configuration file contains - - sender_host_accept_relay = *.c.d : e.f.g - sender_host_reject_relay = *.b.c.d - sender_host_reject_relay_except = a.b.c.d - -the new configuration will contain - - host_accept_relay = a.b.c.d : ! *.b.c.d : *.c.d : e.f.g - -The same ordering is used to merge a triple into a reject option, but this time -the first and third sublists are negated. For example, if an old configuration -file contains - - sender_host_accept = *.c.d : e.f.g - sender_host_reject = *.b.c.d - sender_host_reject_except = a.b.c.d - -the new configuration file will contain - - host_reject = ! a.b.c.d : *.b.c.d : ! *.c.d : ! e.f.g : * - -The output file should be checked before trying to use it. Each option change -is preceded by an identifying comment. There are several specific things that -you should look out for when checking: - -(1) If you are using macros to contain lists of items, and these have to be - negated in the new world, convert4r3 won't get it right. For example, if - the old configuration contains - - ACCEPTHOSTS = *.c.d : e.f.g - sender_host_reject = ACCEPTHOSTS - - then the rewritten configuration will be - - ACCEPTHOSTS = *.c.d : e.f.g - host_reject = !ACCEPTHOSTS - - but because this is just textual macro handling, that is equivalent to - - host_reject = !*.c.d : e.f.g - - which is not the correct translation, because the second item is not - negated. There is unfortunately no easy way to use a macro to provide a - list of things that are sometimes negated. - -(2) The conversion adds some settings of file_transport, pipe_transport, and - reply_transport to aliasfile and forwardfile directors. This is done - because the global implicit defaults for these options have been removed. - The default configuration now contains explicit settings, so convert4r3 - makes these additions to be compatible with that. If your aliasfile and - forwardfile directors do not make use of the pipe, file, or autoreply - facilities, you can remove these new settings. - -(3) If you are using +allow_unknown in a host list which also has an exception - list, you may need to move +allow_unknown in the new configuration. For - example, if the old configuration contains - - sender_host_reject = +allow_unknown : *.b.c - sender_host_reject_except = *.a.b.c - - then the rewritten configuration will be - - host_reject = ! *.a.b.c : +allow_unknown : *.b.c - - Because the negated item contains a wild card, the reverse lookup for the - host name will occur before +allow_unknown is encountered, and therefore - +allow_unknown will have no effect. It should be moved to the start of the - list. - -One way of upgrading Exim from a pre-3.00 release to a post-3.00 release is as -follows: - -1. Suppose your configuration file is called /opt/exim/configure, and you want - to continue with this name after upgrading. The first thing to do is to make - another copy of this file called, say, /opt/exim/configure.pre-3.00. - -2. Rebuild your existing Exim to use the copy of the configuration file instead - of the standard file. Install this version of Exim under a special name such - as exim-2.12, and point a symbolic link called "exim" at it. Then HUP your - daemon. You can check on the name of the configuration file by running - - exim -bP configure_file - - Ensure that everything is running smoothly. - -3. Build the new release, configured to use the standard configuration file. - -4. Use the convert4r3 utility to upgrade your configuration file for the new - release. After running it, check the file by hand. - -5. If any of the options that convert4r3 rewrote contained regular expressions - that had backslashes in them, and were not previously in quotes, they will - need modification if convert4r3 has put them into quotes. Either re-arrange - the option to remove the quoting, or escape each backslash. For example, if - you had - - sender_reject_recipients = ^\d{8}@ - sender_reject_except = ^\d{8}@x.y.z - - convert4r3 will have combined the two settings into - - sender_reject_recipients = "! ^\d{8}@x.y.z : \ - ^\d{8}@" - - This must be changed to - - sender_reject_recipients = ! ^\d{8}@x.y.z : ^\d{8}@ - or - sender_reject_recipients = "! ^\\d{8}@x.y.z : ^\\d{8}@" - - In the second case, the quoted string could of course still be split - over several lines. - -6. If your configuration refers to any external lists of networks, check them - to ensure that all the masks are in the single-number form, because Exim no - longer recognizes the dotted quad form of mask. For example, if an item in - a netlist file is - - 131.111.8.0/255.255.255.0 - - you must change it to - - 131.111.8.0/24 - - Otherwise Exim will not recognize it as a masked IP address, and will treat - it as a host name. The convert4r3 utility makes this conversion for networks - that are mentioned inline in the configuration, but it does not handle - referenced files. - -7. Check the newly-built Exim as much as possible without installing; you can, - for example, use a command such as - - ./exim -bV - - in the build directory to test that it successfully reads the new - configuration file. You can also do tests using -bt and -bh. - -8. Install the new release under a special name such as exim-3.00. - -9. You can then easily change between the new and old releases simply by moving - the symbolic link and HUPping your daemon. - - -Details of syntax changes at 3.00 -================================= - -1. A bare file name without a preceding search type may appear in a domain -list; this causes each line of the file to be read and processed as if it were -an item in the list, except that it cannot itself be a bare file name (that is, -this facility cannot be used recursively). Wild cards and regular expressions -may be used in the lines of the file just as in the main list. -For example, if - - local_domains = /etc/local-domains - -then the file could contain lines like - - *.mydomain.com - -This is different to an lsearch file, which operates like any other lookup type -and does an exact search for the key. If a # character appears anywhere in a -line of the file, it and all following characters are ignored. Blank lines are -also ignored. - -2. Any item in a domain list (including a bare file name) can be preceded by an -exclamation mark character, to indicate negation. White space after the ! is -ignored. If the domain matches the rest of the item, it is *not* in the set of -domains that the option is defining. If the end of the list is reached, the -domain is accepted if the last item was a negative one, but not if it was a -positive one. If ! precedes a bare file name, then all items in the file are -negated, unless they are preceded by another exclamation mark. For example: - - relay_domains = !a.b.c : *.b.c - -sets up a.b.c as an exception to the more general item *.b.c, because lists are -processed from left to right. If the domain that is being checked matches -neither a.b.c nor *.b.c, then it is not accepted as a relay domain, because the -last item in the list is a positive item. However, if the option were just - - relay_domains = !a.b.c - -then all domains other than a.b.c would be relay domains, because the last item -in the list is a negative item. In effect, a list that ends with a negative -item has ": *" appended to it. - -3. Negation and bare file names are available as above in lists of local parts -(e.g. in local_parts options) and complete addresses (address lists). For the -special "@@" lookup form in address lists, negation also can be used in the -list of local parts that is looked up for the domain. For example, with - - sender_reject_recipients = @@dbm;/etc/reject-by-domain - -the file could contain lines like this: - - baddomain.com: !postmaster : !hostmaster : * - -If a local part that actually begins with ! is required, it has to be specified -using a regular expression. Because local parts may legitimately contain # -characters, a comment in the file is recognized only if # is followed by white -space or the end of the line. - -4. Host lists may now contain network items, as in the former net list options, -which have all been abolished. The only form of network masking is the /n -variety. Negation and bare file names can appear in host lists, and there is a -new type of item which allows masked network numbers to be used as keys in -lookups, thus making it possible to used DBM files for faster checking when the -list of networks is large. - -The complete list of types of item which can now appear in a host list is: - -. An item may be a bare file name; each line of the file may take the form of - any of the items below, but it may not itself be another bare file name. If - the file name is preceded by ! then all items in the file are negated, unless - they are preceded by another exclamation mark. Comments in the file are - introduced by # and blank lines are ignored. - -. If the entire item is "*" it matches any host. - -. If the item is in the form of an IP address, it is matched against the IP - address of the incoming call. - -. If the item is in the form of an IP address followed by a slash and a mask - length (e.g. 131.111.0.0/16) then it is matched against the IP address of the - incoming call, subject to the mask. - -. If the item is of the form "net-;", for - example: - - net24-dbm;/networks.db - - then the IP address of the incoming call is masked using as the mask - length; a textual string is then constructed from the masked value, followed - by the mask, and this is then used as the key for the lookup. For example, if - the incoming IP address is 192.152.34.6 then the key that is looked up for - the above example is "192.152.34.0/24". - -. If the entire item is "@" the primary host name is used as the the match - item, and the following applies: - -. If the item is a plain domain name, then a forward DNS lookup is done on that - name to find its IP address(es), and the result is compared with the IP - address of the incoming call. - -The remaining items require the host name to be obtained by a reverse DNS -lookup. If the lookup fails, Exim takes a hard line by default and access is -not permitted. If the list is an "accept" list, Exim behaves as if the current -host is not in the set defined by the list, whereas if it is a "reject" list, -it behaves as if it is. - -To change this behaviour, the special item "+allow_unknown" may appear in the -list (at top level - it is not recognized in an indirected file); if any -subsequent items require a host name, and the reverse DNS lookup fails, Exim -permits the access, that is, its behaviour is the opposite to the default. - -. If the item starts with "*" then the remainder of the item must match the end - of the host name. For example, *.b.c matches all hosts whose names end in - .b.c. This special simple form is provided because this is a very common - requirement. Other kinds of wildcarding require the use of a regular - expression. - -. If the item starts with "^" then it is taken to be a regular expression which - is matched against the host name. For example, ^(a|b)\.c\.d$ matches either - of the two hosts a.c.d or b.c.d. If the option string in which this occurs is - given in quotes, then the backslash characters must be doubled, because they - are significant in quoted strings. The following two settings are exactly - equivalent: - - host_accept = ^(a|b)\.c\.d$ - host_accept = "^(a|b)\\.c\\.d$" - -. If the item is of the form ;, for example - - dbm;/host/accept/list - - then the host name is looked up using the search type and file name or query - (as appropriate). The actual data that is looked up is not used. - -5. Early versions of Exim required commas and semicolons to terminate option -settings in drivers. This hasn't been the case for quite some time. The code to -handle them has now been removed. - - -Details of option changes at 3.00 -================================= - -Main options ------------- - - * address_directory_transport, address_directory2_transport, - address_file_transport, address_pipe_transport, and address_reply_transport - have been abolished as obsolete. The aliasfile and forwardfile directors - have been able for some time to set the transports they want to use for - these special kinds of delivery; there seems little need for global - defaults. The default configuration has been altered to add settings for - file_transport and pipe_transport to the aliasfile and forwardfile - directors, and to add reply_transport to forwardfile. - - * check_dns_names, a deprecated synonym for dns_check_names, has been - abolished. - - * helo_accept_junk_nets is abolished; nets can now appear in - helo_accept_junk_hosts. - - * helo_verify_except_hosts and helo_verify_except_nets have been abolished, - and helo_verify has been changed from a boolean to a host list, listing - those hosts for which HELO verification is required. - - * the obsolete option helo_verify_nets (a synonym for host_lookup_nets) has - been abolished. Note that host_lookup_nets itself has been replaced by - host_lookup. - - * hold_domains_except has been abolished. Use negated items in hold_domains. - - * host_lookup_nets has been replaced by host_lookup, which can contain hosts - and nets. - - * ignore_fromline_nets has been replaced by ignore_fromline_hosts. - - * If message_filter is set and the filter generates any deliveries to files, - pipes, or any autoreplies, then the appropriate message_filter_*_transport - options must be set to define the transports, following the abolition of - the global defaults (see above). - - * queue_remote and queue_remote_except have been abolished and replaced by - queue_remote_domains, which lists those domains that should be queued. The - effect of queue_remote=true is now obtained by queue_remote_domains=*. - - * queue_smtp and queue_smtp_except have been abolished and replaced by - queue_smtp_domains, which lists those domains that should be queued after - routing. The effect of queue_smtp=true is now obtained by - queue_smtp_domains=*. - - * rbl_except_nets has been abolished and replaced by rbl_hosts, which can - contain hosts and nets. This defaults to "*" and defines the set of hosts - for which RBL checking is done. - - * receiver_unqualified_nets is abolished; nets can now appear in - receiver_unqualified_hosts. - - * receiver_verify_except_hosts and receiver_verify_except_nets have been - abolished and replaced by receiver_verify_hosts, which defaults to "*". - This is used, however, only when receiver_verify is set - together with the - other conditions (receiver_verify_addresses, receiver_verify_senders). - - * receiver_verify_senders_except has been abolished; the functionality is now - available by using negation in receiver_verify_senders. - - * rfc1413_except_hosts and rfc1413_except_nets have been abolished, and - replaced by rfc1413_hosts, which defaults to "*". - - * sender_accept, sender_accept_recipients and sender_reject_except have - been abolished; the functionality is now available via sender_reject and - sender_reject_recipients. - - * sender_host_accept, sender_net_accept, sender_host_reject, - sender_net_reject, sender_host_reject_except, sender_net_reject_except, - sender_host_reject_recipients and sender_net_reject_recipients - have all been abolished, and replaced by the options host_reject and - host_reject_recipients. - - * sender_host_accept_relay, sender_net_accept_relay, - sender_host_reject_relay, sender_host_reject_relay_except, - sender_net_reject_relay, and sender_net_reject_relay_except are abolished, - and replaced by host_accept_relay. This defaults unset, and this means that - all relaying is now by default locked out in the Exim binary. Previously, - if no relaying options were set, relaying was permitted. - - * sender_unqualified_nets has been abolished; nets can now appear in - sender_unqualified_hosts. - - * sender_verify_except_hosts and sender_verify_except_nets have been - abolished and replaced by sender_verify_hosts, which defaults to "*". This - is used, however, only when sender_verify is set (to make it similar to - receiver_verify, even though there aren't at present any other conditions.) - - * sender_verify_log_details has been abolished. This was a little-used - debugging option. - - * smtp_etrn_nets has been abolished; nets can now appear in smtp_etrn_hosts. - - * smtp_expn_nets has been abolished; nets can now appear in smtp_expn_hosts. - - * smtp_log_connections, a deprecated synonym for log_smtp_connections, has - been abolished. - - * smtp_reserve_nets is abolished; nets can now appear in smtp_reserve_hosts. - -Generic director and router options ------------------------------------ - - * except_domains, except_local_parts, and except_senders have been abolished. - Use negated items in domains, local_parts, and senders instead, for - example, replace - - except_domains = a.b.c - - with - - domains = !a.b.c - - If you already have a domains setting, add any negative items to the front - of it. - -The aliasfile director ----------------------- - - * The option "directory", an obsolete synonym for home_directory, has been - abolished. - -The forwardfile director ------------------------- - - * The option "directory", an obsolete synonym for file_directory, has been - abolished. - - * The option forbid_filter_log, an obsolete synonym for - forbid_filter_logwrite, has been abolished. - -The localuser director ----------------------- - - * The option "directory", an obsolete synonym for match_directory, has been - abolished. - -The lookuphost router ---------------------- - - * mx_domains_except and its obsolete old name non_mx_domains have been - abolished. Use negated items in mx_domains. - -The pipe transport ------------------- - - * The option "directory", an obsolete synonym for home_directory, has been - abolished. - -The smtp transport ------------------- - - * mx_domains_except and its obsolete old name non_mx_domains have been - abolished. Use negated items in mx_domains. - - * serialize_nets has been abolished; nets may now appear in serialize_hosts. - - -Other items relevant to upgrading from Exim 2.12 -================================================ - -1. RFC 2505 (Anti-Spam Recommendations for SMTP MTAs) recommends that the -checking of addresses for spam blocks should be done entirely caselessly. -Previously, although Exim retained the case of the local part, in accordance -with the RFC 821 rule that local parts are case sensitive, some of the string -comparisons were nevertheless done caselessly, but file lookups used the -unmodified address. - -The way addresses are compared with options whose values are address lists has -been changed. At the start of the comparison, both the local part and the -domain are now forced to lower case, and any comparisons that are done with -in-line strings are done caselessly. For example, - - sender_reject = A@b.c - -rejects both A@b.c and a@b.c. Any lookups that occur use lowercased strings as -their keys. If the @@ lookup facility is used, the lookup is done on the lower -cased domain name, but any subsequent string comparisons on local parts are -done caselessly. - -To retain possibility of caseful matching, the pseudo-item "+caseful" can -appear in an address list. It causes any subsequent items to do caseful matches -on local parts. The domain, however, remains lower cased. - -2. The handling of incoming batched SMTP has been re-worked so as to behave in -a more useful way in cases of error: - - (i) The option sender_verify_batch now defaults false. - (ii) EOF is no longer interpreted as end-of-message; the "." line must be - present. - (iii) Exim stops immediately in cases of error, writing information to stdout - and stderr, and setting the return code to 1 if some messages have been - accepted, and 2 otherwise. - -3. The first message delivered by -R, and all messages delivered by -Rf and -qf -are "forced" in the sense that retry information is over-ridden. Previously, -Exim also forcibly thawed any of these messages that was frozen. This no longer -happens. Additional options -Rff and -qff have been implemented to force -thawing as well as delivery. - -4. When recipients are being rejected because the sending host is in an RBL -list, Exim used just to show the RBL text, if any, as part of the rejection -response. Now, if prohibition_message is set, it expands that string instead, -with the RBL message available in $rbl_text, and $prohibition_reason set to -"rbl_reject". - -5. When a trusted caller passed a message to Exim, it used to check the From: -header against the caller's login (even though the caller was trusted) unless -the -f option had been used to supply a different sender. This has been changed -so that From: is never checked if the caller is trusted. - -Philip Hazel -May 1999 - diff --git a/doc/doc-txt/Exim4.upgrade b/doc/doc-txt/Exim4.upgrade deleted file mode 100644 index 86d4a4dda..000000000 --- a/doc/doc-txt/Exim4.upgrade +++ /dev/null @@ -1,1734 +0,0 @@ -Upgrading Exim from Release 3.33 to 4.xx ----------------------------------------- - -Exim 4.00 represents the largest upheaval in Exim's history. There are a lot of -changes to the way some parts of Exim work, and a lot of incompatible changes -to the run time configuration file. - -This document is in two parts. The first part contains instructions and -suggestions for how you might go about performing the upgrade. The second part -is a brief list of all the changes that have taken place. For full details of -all the new features, please consult the current version of the reference -manual. - - -HOW TO UPGRADE YOUR EXIM ------------------------- - -When you compile Exim 4, a Perl script called convert4r4 is built in the build -directory. It is not installed by the install script, because it is likely that -you will run it only once. - -This script is provided to assist in updating Exim configuration files. It -reads an Exim 3 configuration file on the standard input, and writes a modified -file on the standard output. It also writes comments about what it has done to -the standard error file. It assumes that the input is a valid Exim 3 -configuration file. A typical call to the conversion script might be - - ./convert4r4 /etc/exim/configure.new - -The output file MUST be checked and tested before trying to use it on a live -system. The conversion script is just an aid which does a lot of the "grunt -work". It does not guarantee to produce an Exim 4 configuration that behaves -exactly the same as the Exim 3 configuration it reads. - -Each option change in the new file is preceded by an identifying comment. In -fact, the conversion script tends to make quite a mess of your configuration, -and you should expect to go through it afterwards and tidy it up by hand. - -Unless you are running a very straightforward configuration, the automatic -conversion is likely to generate a non-optimal configuration. You should not -only check it thoroughly, but also run as many tests as you can, to ensure that -it is working as you expect. In particular, you should test address routing, -using -bt and -bv, and the policy controls, using -bh. If possible, you should -also do some live tests (i.e. send and receive some messages) before putting -Exim 4 into service. - -If you have a very complicated configuration, it is possible that convert4r4 -will break it in some situations, which is why thorough testing is strongly -recommended. - - ********************************* - ***** You Have Been Warned ****** - ********************************* - - -HOW TO MOVE FROM AN EXIM 3 RELEASE TO AN EXIM 4 RELEASE -------------------------------------------------------- - -One way of upgrading to Exim 4 from a version 3 release is as follows: - -1. Suppose your run time configuration file is called /usr/exim/configure, and - you want to continue with this name after upgrading. The first thing to do - is to make another copy of this file called, say, /usr/exim/configure.r3. - -2. Rebuild your existing Exim to use the copy of the run time configuration - file instead of the standard file. Install this version of Exim and HUP your - daemon. You can check on the name of the configuration file by running - - exim -bP configure_file - - Ensure that everything is running smoothly. You now have something you can - fall back to. IMPORTANT: when you do this re-install, you should also - re-install the utilities because four of them (exicyclog, eximon, exinext, - and exiwhat) also refer to the configuration file. - -3. Build the new release, configured to use the standard configuration file. - -4. Use the convert4r4 utility to upgrade your configuration file for the new - release. After running the conversion utility, check the file by hand, and - tidy it up. - -5. Test, test, test! And test some more! - -6. You can run complete tests, including actual deliveries, from an uninstalled - binary, but you have to tell it where it is, so that any re-executions can - be done. You can do this by temporarily inserting a setting such as - - exim_path = /source/exim/exim-4.00/build-SunOS5-5.8-sparc/exim - - into the run time configuration. If you want to, you can also insert - settings for spool_directory and log_file_path to divert those away from - their normal places. Remember to remove these temporary settings when you - eventually install the binary for real. - -7. The new installation script installs the new release as exim-4.00-1, and - set a symbolic link called "exim" to point to it. The old version of Exim - will be renamed to something like exim-3.33-1. - -8. You can now easily change between the new and old releases simply by moving - the symbolic link and HUPping your daemon. The format of message files on - Exim's spool has _not_ changed, so there should be no problem in changing - between releases while there are messages on the queue. - -9. HOWEVER: If you do change back and forth between releases, you must also - change the utilities exicyclog, eximon, exinext, and exiwhat if you are - going to use them. Installing Exim 4 will have left the old versions with a - .O suffix. It might be helpful to rename these so that you don't lose them. - - -WHAT HAS NOT CHANGED IN EXIM 4.00 ---------------------------------- - -The basic overall philosophy, design, and process structure has not changed. -The format of spool files is the same. The transports have had only minor -modifications. The command line options remain the same, with a couple of -additions. - -The general run time configuration approach has not changed, but the actual -details of the configuration file are different. - -The Exim monitor has not changed, and there have been only very minor changes -to other Exim utilities. - - -WHAT HAS CHANGED IN EXIM 4.00 ------------------------------ - -The rest of this document lists the very many changes that have taken place. -I'm going to give only brief details here, because this part of the document is -intended as a way of alerting you to areas of difference. The reference manual -describes how the new features work in detail. - - -Named domain, host, address, and local part lists -------------------------------------------------- - -A new feature makes it possible to give names to lists of domains, hosts, -addresses, and local parts. The syntax used is - - domainlist = - hostlist = - addresslist = - localpartlist = - -For example: - - domainlist local_domains = *.my.domain - addresslist bad_senders = cdb;/etc/badsenders - -These lists are referenced in options by giving the name preceded by a + sign. -For example, in a router you might have - - domains = +local_domains - -At first sight, these lists might seem to be the same as macros, but they are -not. Macros are just textual substitutions. If you write - - ALIST = host1 : host2 - auth_advertise_hosts = !ALIST - -it probably won't do what you want, because that is exactly the same as - - auth_advertise_hosts = !host1 : host2 - -Notice that the second host name is not negated. However, if you use a host -list, and write - - hostlist alist = host1 : host2 - auth_advertise_hosts = ! +alist - -the negation applies to the whole list, and so that is equivalent to - - auth_advertise_hosts = !host1 : !host2 - -These named lists also have a performance advantage. When Exim is routing an -address or checking an incoming message, it caches the result of tests on the -lists. So, if you have a setting such as - - domains = +local_domains - -on several of your routers, the actual test is done only for the first one. -However, this caching works only if there are no expansions within the list -itself or any sublists that it references. In other words, caching happens only -if the list is known to be the same each time it is referenced. - -By default, there may be up to 16 named lists of each type. This limit can be -extended by changing a compile-time variable. - -The use of domain and host lists is recommended for concepts such as local -domains, relay domains, and relay hosts. The default configuration is set up -like this. - - -Processing of domain, host, local part, and address lists ---------------------------------------------------------- - -The handling of these lists is now more uniform. Every list is expanded as a -single string before it is used. (In Exim 3, some options were expanded and -some weren't, and query-style lookup items were then re-expanded.) - -If an expansion is forced to fail, Exim behaves as if the item has not been -found in the list. - -The confusing $key variable has been abolished. When processing a domain list, -$domain contains the relevant domain and can be used in generating database -queries. Other appropriate variables are set when processing other kinds of -list; $sender_host and $sender_host_address for checking incoming hosts and -$host and $host_address for checking outgoing hosts. - -Note that this means that any \ and $ characters in regular expressions must be -escaped if they appear in one of these lists. The new expansion feature to turn -off expansion (\N ... \N) which is described below can be helpful here. - -IMPORTANT: The details of the processing of address lists has been revised. In -particular, the handling of the case of an item that is a single-key lookup has -changed. It no longer looks up the domain on its own before looking up the -complete address. You need to supply an explicit "*@" before the lookup if you -want just the domain to be looked up. Please check the manual for full details. - -If an item in a host list is the empty string, it matches only when no host is -defined. If used when checking an incoming message, it matches only when the -message is arriving by SMTP on the standard input from a local process (using --bs). This provides a way of distinguishing between SMTP mail from local -processes and from remote hosts. - -The +allow_unknown and +warn_unknown settings for host lists have been replaced -by a single item, +include_unknown. By default, failure to find a host name -when needed causes Exim to behave as if the host does not match the list, but -if +include_unknown is set, the opposite behaviour happens. Whenever -+include_unknown is invoked, the incident is logged. - - -Merge of Directors and Routers ------------------------------- - -There are no longer any directors in Exim 4. There are just routers. All -addresses are passed to a single list of routers which typically makes use of -the "domains" option to choose which way to handle specific groups of domains. - -A consequence of this is that the code no longer contains any concept of "local -domains". However, a typical configuration will probably define a named domain -list (see above) called local_domains, and use it to control routing something -like this: - - route_remote: - driver = dnslookup - domains = ! +local_domains - transport = remote_smtp - no_more - - system_aliases: - .... - -The first router does DNS routing for all domains that are not in the named -list of local domains, and no_more ensures that it is the last router for those -domains. All other domains fall through to the system_aliases and subsequent -routers. For a complete configuration example, look at the default -configuration file in src/configure.default. - - -Router Actions --------------- - -The concept of how the routers work is as follows: - -A number of pre-conditions are tested (details below). If any of them fails, -control is passed to the next router. We say "the router is skipped". Otherwise -the router is run, and can yield one of several different results: - -. accept: The router accepts the address, and either queues it for a transport, -or generates one or more "child" addresses. Processing the original address -ceases, unless "unseen" is set on the router, in which case the address is -passed to the next router. Processing of any child addresses starts with the -first router by default, or at the router defined by redirect_router if it is -set. This may be any router in the list. - -. decline: The router declines to accept the address because it does not -recognize it at all. The address is passed to the next router, unless no_more -is set, in which case the address fails. - -. pass: The router recognizes the address, but cannot handle it itself. It -requests that the address be passed to another router. This overrides no_more. -By default the address is passed to the next router, but this can be changed by -setting pass_router. However, in this case (unlike redirect_router) the named -router must be below the current router (to avoid loops). - -. fail: The router determines that the address should fail, and queues it for -the generation of a bounce message. There is no further processing of the -original address, unless "unseen" is set. - -. defer: The router cannot handle the address at the present time. (For -example, a database may be offline.) No further processing of the address -happens in this delivery attempt. It is tried again next time. - -. error: There is some error in the router (for example, a syntax error in -its configuration). The action is as for defer. - - -Router pre-conditions ---------------------- - -In Exim 3 there are some strange interactions between the generic options that -test things before running a director or router and the no_more test that -happens afterwards. - -In Exim 4 it is all more straightforward. If any of the pre-condition tests -fail, the router is skipped and control passes to the next router. The no_more -option has an effect only if the router is actually run - that is, if all the -pre-condition tests succeed. The order in which these tests are run is: - - verify status, expn status, domains, local_parts, check_local_user - -If all those match, the debug_print string is output when debugging. Exim then -goes on to test - - senders, require_files, condition - -Note that require_files comes near the end of the list, so you cannot use it to -check for the existence of a file in which to lookup up a domain, local part, -or sender. However, as these options are all expanded, you can use the "exists" -expansion condition to make such tests. The require_files option is intended -for checking files that the router may be going to use internally, or which are -needed by a specific transport (e.g. .procmailrc). - -In Exim 4, local part prefixes and suffixes are recognized and removed before -any of the other pre-condition tests are done (in Exim 3 they were removed -afterwards). Note that this means that the local_parts option now tests the -local part without its prefix or suffix. - -If you want to use local parts that include any affixes in a pre-condition -test, you can do so by using a "condition" option that uses the variables -$local_part, $local_part_prefix, and $local_part_suffix as necessary. - - -A New Set of Routers --------------------- - -The two sets of routers and directors of Exim 3 have been replaced by a single -set of routers for Exim 4. These are as follows: - -. accept Always accepts an address. It has no private options. - -. dnslookup Routes by DNS lookup (descended from lookuphost). - -. ipliteral Routes IP literal addresses (unchanged). - -. iplookup Special-purpose lookup router (unchanged). - -. manualroute Routes domains from explicit data (descended from domainlist). - -. queryprogram Routes addresses by running a program (detail changed). - -. redirect Redirects addresses; handles all the functions previously - supported by aliasfile, forwardfile, and smartuser without - a transport. - - -Saving duplication of effort while routing ------------------------------------------- - -Early versions of Exim used to copy the routing of one address for all other -addresses in the same domain, thereby possibly saving some repeated DNS -lookups. This feature was removed for release 2.12, after the possibility of -varying the router actions according to the local part (the local_parts option) -was added. (In fact, the use of $local_part could have broken it earlier.) - -For Exim 4, I have added an option called same_domain_copy_routing to the -dnslookup and manualroute routers. When one of these routers routes an address -to a remote transport and this option is set, any other addresses in the -message that have the same domain are automatically given the same routing, but -only if the router does not set headers_add or headers_remove, and does not -`widen' the domain during the routing. - - -Generic Router Options ----------------------- - -. The global locally_caseless option is replaced by a generic router option - called caseful_local_part. By default, routers handle local parts caselessly. - -. check_local_user is now a generic option that is needed to check for a local - account. Typically used on redirect (for user's forward files) and on accept - (for local deliveries). - -. The setting self=local has been removed (since there's no concept of local - domains in the code). The same kind of effect can be achieved by using - self=reroute or self=pass. - -. expn is now a generic router option. - -. local_part_prefix and local_part_suffix are now generic router options, - replacing prefix and suffix on directors. - -. Exim 3 has two logging styles for delivery, depending on whether the domain - is a local domain or not. For local domains, the address is given just as the - local part - this makes these deliveries easier to spot in the log. In Exim 4 - there's no concept of local domains, so this functionality cannot be - automatic. Instead, there's a generic router option called log_as_local which - requests "local-style" logging. This option defaults on for the "accept" - router, and off for all the others. - -. There's an option called retry_use_local_part which is the default for any - router that has check_local_user set, and it applies to routing delays. (The - same option for transports applies to transport delays.) - -. transport_home_directory and transport_current_directory are new generic - options on all routers. They set up default values for home_directory and - current_directory on the transport to which they route an address. Any - settings in the transport override. - -. If transport_home_directory is not set, but check_local_user is set, the - user's home directory is used as a default value. - -. The special fudge that exists in Exim 3 for handling home_directory settings - in forwardfile directors is not needed in Exim 4. It has therefore been - removed. - -. The new_director option in Exim 3 allows the direction of redirected - addresses to start at a given director, instead of the first one. In Exim 4, - this option is now called redirect_router. The option is used when a redirect - router succeeds, and when a queryprogram router returns a "redirect" - response. - -. There is a new option called pass_router, which specifies the router to go to - when a router "passes" on an address. The named router must follow the - current router (to avoid routing loops). Note: if a router declines, control - always passes to the next router, unless no_more is set. - -. There is a new router option called address_data. This is set to a string - which is expanded just before the router is run, that is, after all the - pre-tests have succeeded. If the expansion is forced to fail, the router - declines. Other expansion failures cause delivery of the address to be - deferred. - - When the expansion succeeds, the value is retained with the address, and can - be accessed using the variable $address_data. Even if the router declines or - passes, the value remains with the address, though it can be changed by - another address_data setting on a subsequent router. If a router generates - child addresses, the value of $address_data propagates to them. - - The idea of address_data is that you can use it to look up a lot of data for - the address once, then then pick out parts of the data later. For example, - you could use an LDAP lookup to return a string of the form - - uid=1234 gid=5678 mailbox=/mail/xyz forward=/home/xyz/.forward - - In the transport you could then pick out the mailbox by a setting such as - - file = ${extract{mailbox}{$address_data}} - - This makes the configuration file less messy, and also reduces the number of - lookups. (Exim does cache the most recent lookup, but there may be several - addresses with different lookups.) - -. When a transport is run for several addresses simultaneously, the values of - $address_data, $local_part_data, and $domain_data are taken from the first - address that the transport handles. However, the order in which multiple - addresses are processed is not defined. You therefore need to be careful if - you want to use these variables with multiple addresses. The smtp transport - is the only one which by default handles multiple addresses. - -. When an address is routed by a router with the "unseen" option set, a "clone" - address is created, and it starts being routed at the next router. (This is - what people expect. In Exim 3 it starts at the top - in simple cases that has - the same effect because of the anti-looping rule, but if aliases are involved - it sometimes doesn't do what you want.) - -. The way that require_files works has been changed. Each item in the list is - now separately expanded as the test proceeds. The use of leading ! and + - characters is unchanged. However, user and group checking is done differently. - Previously, seteuid() was used, but seteuid() is no longer used (see - "Security" below) for checking the files required by this option. Instead, - Exim now scans along the components of the file path and checks the access - for the given uid and gid. It expects "x" access on directories and "r" on - the final file. This means that file access control lists (on those - operating systems that have them) are ignored. - - -Other Consequences of the Director/Router Merge ------------------------------------------------ - -. The -odqr option is abolished, as there is no inbuilt concept of remote - domains. - -. The -odqs option is equivalent to queue_smtp_domains = *. - -. queue_remote_domains is renamed queue_domains, and applies to any domain. - -. The -ql option now suppresses remote delivery; routing always happens. - -. The "remote" facility of queue_only_file has been removed. - -. The match_directory option for forwardfile and localuser has been entirely - abolished. Its function can be achieved using the "condition" option in - conjunction with check_local_user. - -. When an address is being verified, if it is redirected to a single new - address, verification continues with that address. If it is redirected to - more than one address, verification ceases with a success result. (In Exim 3, - this applied only to aliasing, not to forwarding.) - - -The dnslookup router --------------------- - -This router replaces the lookuphost router of Exim 3. It is much the same, -except that the "gethostbyname" option has been removed. It now does only DNS -routing - hence the change of name. Routing using gethostbyname() can be done -by the manualroute router. - - -The manualroute router ----------------------- - -This is the new name for the domainlist router, supposedly to make its function -clearer and to avoid confusion with the "domainlist" that is used to set up -named domain lists. Several things have been removed and reorganized. - -. The old search mechanism (route_file, route_query, route_queries, - search_type) have been removed. Instead there is a new option called - route_data, which is an expanded string. It should expand to a single routing - entry. If the expansion ends up empty (or is forced to fail), the router - declines. The route_list option still exists, for convenient listing of a few - inline routes. - -. There is no longer any MX processing function in this router. The keywords - bydns_mx and bydns_a have been removed, leaving just - - bydns => find IP addresses from address records in the DNS - byname => find IP addresses by calling gethostbyname() - - The default lookup type is "byname", and this can be omitted from a route - data line. If an IP address is given, both "byname" and "bydns" are ignored - (so typically you omit this field). - -. The qualify_single and search_parents options have also been removed. - -. A transport is always required to be set, unless verify_only is set. - -. The host_find_failed option can be set to "decline", to cause the router to - decline if it can't find an IP address for a listed host. - -. If manualroute routes to a local transport, there is no need to specify - byname or bydns in the routing data. Any supplied host list is passed as a - string in $host, but $host_address is unset. - - -The queryprogram router ------------------------ - -This router has been re-designed: - -. You must now specify a user and group for the program to be run using - command_user and (if necessary) command_group. It no longer defaults to - "nobody". These options are expanded. - -. The command is now split up and each argument expanded separately, as happens - for the pipe transport. The command name is also expanded. - -. The return value "forcefail" has been renamed "fail", and it causes delivery - to fail. (The original usage of "fail" meaning "decline" has finally been - removed.) - -. The $route_option variable, which queryprogram used to be able to set has - been abolished. A facility to set the new $address_data variable replaces it. - -. The string returned from queryprogram must now be one of: - - DECLINE - FAIL text - DEFER text - PASS - FREEZE text - REDIRECT text - ACCEPT TRANSPORT=transport HOSTS=host list LOOKUP=byname|bydns DATA=text - -The text returned for "redirect" is a list of new addresses. The text for FAIL -is returned in the SMTP dialogue when the router is run as part of address -verification. It is also logged. The text for DEFER and FREEZE is just logged. - -The data items in the "accept" return can be given in any order, and all are -optional. If no transport is included in the "accept" return, the router's -default transport is used. The host list and lookup type are needed only if the -transport is an smtp transport that does not itself have a host list. The -default lookup type is "byname". If the "data" field is set, its value is -placed in the $address_data variable. - - -The redirect router -------------------- - -This router replaces forwardfile, appendfile, and the use of smartuser without -a transport. It has two mutually exclusive options for specifying the data that -it uses. If "file" is set, the data is taken from a file. Otherwise "data" must -be set, and the data is the expanded value of that option. - -The data may be an alias list, possibly including special entries such as -:fail:, or it may be a list of filtering instructions. - -If "file" is set, but the file does not exist or is empty, or its contents have -no effect (entirely comments, or a filter that does nothing), the router -declines. This also happens if the expansion of "file" is forced to fail. Any -other expansion failure causes the router to defer. - -Ownership of the file is checked if check_local_user is set or if owners is -set, unless check_owner is explicitly set false. - -Likewise, the group is checked if owngroups is set, or if check_local_user is -set and a modemask not containing 020 is set, unless check_group is explicitly -set false. - -If "data" is set, a forced expansion causes the router to decline. This also -happens if "data" is an empty string or a string that causes nothing to be -generated and no action to be taken. - -Because "data" is now used for traditional /etc/aliases lookups, an empty alias -no longer gives an error. It behaves in the same way as :unknown: (which is -still recognized, but ignored). - -. If no_repeat_use is set, the router is skipped if _any_ ancestor of the - current address was routed by this router. This pre-test happens before any - of the others. (Contrast the default loop avoidance logic, which skips a - router if an ancestor with the same local part was routed by the router.) - -. If include_directory is set, :include: files are constrained to this - directory. - -. When an address is redirected to a file or a pipe, $address_file or - $address_pipe (as appropriate) is set when expanding the value of - file_transport or directory_transport. - -. There are new options forbid_filter_readfile and forbid_filter_run to lock - out the use of the new ${readfile and ${run expansion items in filters. - -. If one_time is set, forbid_pipe, forbid_file, and forbid_filter_reply are - forced to be true, and headers_add and headers_remove are forbidden. - - -Generic transport options -------------------------- - -. All remote deliveries are now done in subprocesses running with specified - UIDs and GIDs. (Formerly, only remote parallel deliveries were done in - subprocesses.) As a result, user and group are now generic options that can - be used on all transports. The default for both local and remote transports - is to run as the Exim user and group. For remote transports, this should not - normally be changed, but if it is, the user or group should be able to access - the hints databases, though failure to open a hints database is always - ignored. - - If it turns out that a transport user is in the never_users list, Exim now - defers delivery and writes to the panic log. (Previously it just ran the - delivery as "nobody".) Because subprocesses (usually running as "exim") - are now always used for remote deliveries, you should *not* include "exim" in - the never_users list. - -. initgroups is now also a generic transport option. - -. home_directory and current_directory are generic options on all transports, - though some transports (e.g. smtp) make no use of them. If they are unset, - values supplied by the router are used. - -. The message_size_limit option is now expanded, which makes it possible to - have different limits for different hosts, for example. - - -Multiple (batch) deliveries in the appendfile, lmtp, and pipe transports ------------------------------------------------------------------------- - -The options controlling batch deliveries, including BSMTP, were a mess, and -have been reworked. - -. The batch option has been removed from all three transports, and the bsmtp - and bsmtp_helo options have been removed from appendfile and pipe. - -. The batch_max option defaults to 1 in all three transports. - -. A new option called use_bsmtp has been added to appendfile and pipe. When - set, the message is delivered in BSMTP format. If you want to have a HELO - line at the start of the message, you can configure this by making use of the - message_prefix option. You must include the terminating newline. - -. A new option called batch_id has been added to all three transports. - -Batching is now achieved by setting batch_max to a value greater than 1. This -is recommended for lmtp. When multiple addresses are routed to the same -transport that has a batch_max value greater than one, the addresses are -delivered in a batch, subject to certain conditions: - -. If any of the transport's options contain a reference to "$local_part", no - batching is possible. - -. If any of the transport's options contain a reference to "$domain", only - addresses with the same domain are batched. - -. If batch_id is set, it is expanded for each address, and only those addresses - with the same expanded value are batched. - -. Batched addresses must also have the same errors address (where to send - delivery errors), the same header additions and removals, the same user and - group for the transport, and if a host list is present, the first host must - be the same. - - -The appendfile transport ------------------------- - -. The prefix and suffix options have been renamed message_prefix and - message_suffix to avoid confusion with address affixes. The default values, - which are suitable for mbox deliveries, now apply only if "file" is set and - use_bsmtp is not set. Otherwise, the default values for these options are - unset. They can, of course, always be overridden. - -. If "directory" is set (which means that "file" is not set), the check_string - and escape_string options now default unset. - -. The require_lockfile options has been abolished. If use_lockfile is set, a - lock file is always required. - -. The quota_filecount option is now expanded. - -. The create_file option now also applies when delivering into an individual - file in a given directory, as well as when appending to a single file. In the - case of maildir delivery, the restriction applies to the top directory of the - maildir folder. - -. There's a new option called directory_file which is expanded to form the - final leaf name of files when "directory" is set, but neither maildir nor - mailstore is set. The default is "q${base62:$tod_epoch}-$inode", which - reproduces the old fixed value. The variable $inode is available only when - expanding this new option. - - -The pipe transport ------------------- - -. The prefix and suffix options have been renamed message_prefix and - message_suffix to avoid confusion with address affixes. The default values - that are suitable for vacation deliveries now apply only if use_bsmtp is not - set. Otherwise the default values for these options are unset. They can, of - course, always be overridden. - - -The smtp transport ------------------- - -. The badly-named batch_max option is now called connection_max_messages. - -. If hosts_randomize is set, it now affects host lists that come from a router - as well as the contents of the "hosts" option, but only if the hosts were not - obtained from MX records. Typically, such lists come from the manualroute - router. This change means that the router can provide the same host list for - multiple addresses - causing them all to be sent to the transport at once. - Randomizing is then done each time the transport is called. (If you set - hosts_randomize on the router, the randomizing happens for each address.) - -. The way that smtp operates when there are multiple addresses to be sent to - the same host is now different. Previously, the transport was called many - times, with a maximum of max_rcpt addresses per call. Each call made a new - connection to the host. When remote_max_parallel = 1, all the addresses are - now passed to the transport at once. It makes a single TCP/IP call, but may - send multiple copies of the message, each with no more than max_rcpt - recipients. - - When remote_max_parallel is greater than 1, a heuristic is used. The number - of addresses passed to a single call of the transport is limited to - - (the total number of recipients) / (the value of remote_max_parallel) - - so, for example, if there are 100 recipients and remote_max_parallel is 2, no - more than 50 are passed in one call, even if max_rcpt is 100. (The idea is - that the other 50 will be passed to another call running in parallel.) - - There is an option of the smtp transport called connection_max_messages - which limits the number of messages, or copies of a message, that Exim sends - down a single TCP/IP connection. This applies both to this mechanism for - multiple copies of a single message, and the re-use of a TCP/IP connection - for sending other messages destined for the same host, after a delivery - delay. The default value is 500. - -. The "interface" option is now expanded. If the result is a forced failure or - an empty string, it is ignored. Otherwise, the result must be a list of IP - addresses. The first one of the correct type (IPv4 or IPv6) for the outgoing - connection is used. If there isn't one of the correct type, the option is - ignored. - -. At the start of running the transport, the value of $host is taken from the - first host in a multi-host list. However, just before the transport connects - to a host, the value is changed to refer to that particular host. (This - applies to $host_address as well.) This means that options such as helo_data - and the tls_options can be made host-specific. - -. The tls_verify_ciphers option has been renamed tls_require_ciphers, in order - to leave the word "verify" as something that refers to the verification of - certificates. - -. The resolution of hosts and fallback_hosts used to look up MX records. This - was some kind of ancient silliness that I recently noticed. These are - definitely hosts, not mail domains. Exim 4 just looks up address records. - As a consequence of this, the mx_domains option of the smtp transport is - removed. - -. The authenticate_hosts option has been renamed as hosts_try_auth. A new - option called hosts_require_auth has been added; if authentication fails for - one of these hosts, Exim does _not_ try to send unauthenticated. It defers - instead. The deferral error is detectable in the retry rules, so this can be - turned into a hard failure if required. - - -The System Filter ------------------ - -. The system filter options that were called message_filter_xxx have all been - renamed as system_filter_xxx. - -. The value of system_filter is expanded. - -. message_filter_directory_transport and message_filter_file_transport are now - both expanded before use. If the filter set up any file or pipe deliveries, - $address_file and $address_pipe are set as appropriate while doing the - expansions. - -. message_filter_directory2_transport has been removed. The effect of using - different directory-style transports can be achieved by specifying a suitable - expansion string to system_filter_directory_transport. - -. When a system filter added recipients to a message, Exim 3 added an - X-Envelope-To: header, listing the real recipients (up to 100). This has been - abolished because you can do this kind of thing using "headers_add" nowadays. - -. The "fail" command has been extended to allow for two different messages, one - for Exim's log and the other to be returned to the sender. The syntax is - - fail "<>user message" - - That is, if the first two characters of the message are "<<" the following - text, up to ">>", is written to the log, and the remainder is returned to the - user. If there is no log message, the user message is logged. The motivation - for this feature was to reduce the amount of text logged, while being able to - send quite long (maybe even multi-line) messages back to the sender. - - -Changes to Lookups ------------------- - -. Oracle support is available. It works like the mysql and pgsql support, - except that there is no "database name" involved, and the "host name" field - is used for what is called "service name" in Oracle. This often looks like a - host name. Also, semicolons are not used at the end of an SQL query for - Oracle. - -. There's a new single-key lookup type called dsearch. It searches a directory - for a file whose name matches the key. The result of a successful search is - the key. One possible use of this could be for recognizing virtual domains. - If each domain is represented by a file whose name is the domain name, you - needn't make a separate list of the domains. You could test for them in an - ACL (see below), for example, by a line like this - - accept domains = dsearch;/etc/virtual/domains - -. The format of LDAP output has been changed for cases where multiple - attributes are requested. The data for each attribute is now always quoted. - Within the quotes, the quote character, backslash, and newline are escaped - with backslashes and commas are used to separate multiple values for the - attribute. Thus, the string in quotes takes the same form as the output when - a single attribute is requested. If multiple entries are found, their data is - still separated by a newline. - -. There's a new expansion condition called ldapauth which exists so that the - LDAP authentication mechanism can be used for user authentication. It is - described under "string expansion" below. - -. Exim now supports ldaps:// URLs as well as ldap:// URLs. The former do LDAP - over TLS (i.e. encrypted) connections. - -. There is now support for the "whoson" mechanism for doing "POP-before-SMTP" - authentication. This is provided by new query-style lookup type called - "whoson", with queries that consist of IP addresses. For example, in an ACL - you can write - - require condition = ${lookup whoson {$sender_host_address}{yes}{no}} - - -Special items in domain and host lists --------------------------------------- - -. In a domain list, the special item @ matches the primary host name, and the - special item @[] matches any local interface address enclosed in square - brackets (as in domain literal email addresses). The special item @mx_any - matches any domain that has an MX record pointing to the local host. The - special items @mx_primary and @mx_secondary are similar, except that the - first matches only when the primary MX is to the local host, and the second - only when the primary MX is not the local host, but a secondary MX is. - -. In a host list, the special item @ matches the primary host name, and the - special item @[] matches any local interface address (not in brackets). - - -Access Control Lists (ACLs) ---------------------------- - -All the policy control options for incoming messages have been replaced by -Access Control Lists (ACLs). These give more flexibility to the sysadmin, and -allow the order of testing to be specified. For example, using an ACL, it is -possible to specify "accept if authenticated, even if from an RBL host, but -otherwise deny if from an RBL host", which is not possible in Exim 3. - -ACLs are defined in a new part of the configuration file, and given names. -Which ones to run are controlled by a new set of options that are placed in the -main part of the configuration. - - acl_smtp_auth specifies the ACL to run when AUTH is received - acl_smtp_data specifies the ACL to run after a message has been received - acl_smtp_etrn specifies the ACL to run when ETRN is received - acl_smtp_expn specifies the ACL to run when EXPN is received - acl_smtp_rcpt specifies the ACL to run when RCPT is received - acl_smtp_vrfy specifies the ACL to run when VRFY is received - -The default actions vary. If acl_smtp_auth is not defined, AUTH is always -accepted (and an attempt is made to authenticate the session). If acl_smtp_data -is not defined, no checks are done after a message has been received, and it is -always accepted at that point. - -However, if any of the others are not defined, the relevant SMTP command is -rejected. In particular, this means that acl_smtp_rcpt must be defined in order -to receive any messages over an SMTP connection. The default configuration file -contains a suitable default for this. - -ACLs can be provided in line, or in files, or looked up from databases. One ACL -can call another in a subroutine-like manner. String expansion is used, and -which ACL to run can be varied according to sender host or any other criterion -that a string expansion can test. - -This is not the place to give a full specification of ACLs, but here is a -typical example for checking RCPT commands, taken from the default -configuration. The tests are performed in order. - -acl_check_rcpt: - # Accept if source is local SMTP (i.e. not over TCP/IP - undefined host) - accept hosts = : - - # Deny if the local part contains @ or % or / - deny local_parts = ^.*[@%/] - - # Accept mail to postmaster in any local domain, regardless of the source, - # and without verifying the sender. - accept domains = +local_domains - local_parts = postmaster - - # Deny unless the sender address can be verified. - require verify = sender - - # Accept if the address is in a local domain, but only if the recipient can - # be verified. Otherwise deny. The "endpass" line is the border between - # passing on to the next ACL statement (if tests above it fail) or denying - # access (if tests below it fail). - accept domains = +local_domains - endpass - message = unknown user - verify = recipient - - # We get here only for non-local domains. Accept if the message arrived over - # an authenticated connection, from any host. These messages are usually from - # MUAs, so recipient verification is omitted. - accept authenticated = * - - # Reaching the end of the ACL causes a "deny", but we might as well give - # an explicit message. - deny message = relay not permitted - -The following options have been abolished as a consequence of the introduction -of ACLs: - -auth_hosts, auth_over_tls_hosts, headers_checks_fail, headers_check_syntax, -headers_sender_verify, headers_sender_verify_errmsg, host_accept_relay, -host_auth_accept_relay, host_reject_recipients, prohibition_message, -rbl_domains, rbl_hosts, rbl_log_headers, rbl_log_rcpt_count, -rbl_reject_recipients, rbl_warn_header, receiver_try_verify, receiver_verify, -receiver_verify_addresses, receiver_verify_hosts, receiver_verify_senders, -recipients_reject_except, recipients_reject_except_senders, relay_domains, -relay_domains_include_local_mx, relay_match_host_or_sender, -sender_address_relay, sender_address_relay_hosts, sender_reject, -sender_reject_recipients, sender_try_verify, sender_verify, -sender_verify_batch, sender_verify_hosts, sender_verify_fixup, -sender_verify_hosts_callback, sender_verify_callback_domains, -sender_verify_callback_timeout, sender_verify_max_retry_rate, -sender_verify_reject, smtp_etrn_hosts, smtp_expn_hosts. smtp_verify, tls_hosts. - -The variable $prohibition_reason has been abolished. - -The host_reject option has been retained, but with its name changed to -host_reject_connection, to emphasize that it causes a rejection at connection -time. I've left it available just in case it is needed - but its use is not -recommended in normal circumstances. - - -Other Incoming SMTP Session Controls ------------------------------------- - -. The option smtp_accept_max_per_connection (default 1000) limits the number of - messages accepted over a single SMTP connection. This is a safety catch in - case some sender goes mad (incidents of this kind have been seen). After the - limit is reached, a 421 response is given to MAIL commands. - -. Some sites find it helpful to be able to limit the rate at which certain - hosts can send them messages, and the rate at which an individual message can - specify recipients. There are now options for controlling these two different - rates. - - Rate limiting applies only to those hosts that match smtp_ratelimit_hosts, - whose value is a host list. When a host matches, one or both of the options - smtp_ratelimit_mail and smtp_ratelimit_rcpt may be set. They apply to the - rate of acceptance of MAIL and RCPT commands in a single SMTP session, - respectively. - - The value of each option is a set of four comma-separated values: - - 1. A threshold, before which there is no rate limiting. - 2. An initial time delay. Unlike other times in Exim, fractions are allowed - here. - 3. A factor by which to increase the delay each time. - 4. A maximum value for the delay. - - For example, these settings have been used successfully at the site which - first suggested this feature, for controlling mail from their customers: - - smtp_ratelimit_mail = 2, 0.5s, 1.05, 4m - smtp_ratelimit_rcpt = 4, 0.25s, 1.015, 4m - -. The default value for smtp_connect_backlog has been increased to 20. - -. The SMTP protocol specification requires the client to wait for a response - from the server at certain points in the dialogue. (Without PIPELINING these - are after every command; with PIPELINING they are fewer, but still exist.) - Some spamming sites send out a complete set of SMTP commands without waiting - for any response. Exim 4 protects against this by rejecting messages if the - client has sent further input when it should not have. The error response - "554 SMTP synchronization error" is sent, and the connection is dropped. - - This check is controlled by smtp_enforce_sync, which is true by default. - -. helo_strict_syntax has been abolished. The default is now to enforce strict - domain syntax for HELO/EHLO arguments. You can use helo_accept_junk_hosts if - you want to avoid this. - -. There's a new option called helo_lookup_domains. If the domain given in a - HELO or EHLO command matches this list, a reverse lookup is done in order to - establish the host's true name. The default setting is - - helo_lookup_domains = @ : @[] - - That is, a lookup is forced if the client host gives the server's name or - [one of its IP addresses] in HELO or EHLO. (In Exim 3 this happened - automatically and was not configurable.) - -. The value of the global message_size_limit option is now expanded. For - locally submitted messages this happens at the start of message reception. - For messages from remote hosts, the expansion is done just after the host - connects, so that the value can depend on the host. - - -Handling of Resent- Fields --------------------------- - -RFC 2822 makes it clear that Resent- fields are purely informational. Exim used -to make use of Resent-Reply-To: which does not actually exist, and it also used -to use the last set of resent- fields for all the address fields it recognized. - -In Exim 4, resent- headers are dealt with as follows: - -. A Resent-From: header that just contains the login id as the address is - automatically rewritten in the same way as From: is (using qualify domain, - and user name from the passwd data). - -. If there's a rewrite rule for a header, it is also applied to resent- headers - of the same type. For example, a rule that rewrites From: headers also - rewrites Resent-From: headers. - -. For local messages, if Sender: is being removed on input, Resent-Sender: is - also removed. - -. If there are any resent- headers but no Resent-Date: or Resent-From: they are - added. - -. The logic for adding Sender: is now duplicated for Resent-Sender. - -. If there's no Resent-Message-Id: one is created, and it is the - Resent-Message-Id: which is included in the log line. - - -Authentication --------------- - -. The auth_hosts option has been abolished; this functionality is now - controlled by ACLs. - -. The auth_always_advertise option has been abolished because it depended on - auth_hosts and host_auth_accept_relay, both of which are no more. In its - place there is a new option called auth_advertise_hosts, whose default value - is *, meaning "advertise AUTH to all". - -. The value of server_setid is now used when logging failed authentication - attempts. - -. The -oMaa option allows trusted users to set the value of - $sender_host_authenticated (the authenticator name). This is normally used in - conjunction with -oMa. - - -Encryption ----------- - -. Because tls_hosts is no more, tls_advertise_hosts is now the only means of - controlling the advertisement of STARTTLS (previously, tls_hosts overrode). - -. The global option tls_verify_ciphers has been abolished. There are now - facilities for checking which cipher is in use in ACLs. - -. There's a new option called tls_try_verify_hosts. Like tls_verify_hosts, this - causes the server to request a certificate from a client, and it verifies the - certificate that it receives. However, unlike tls_verify_hosts, Exim - continues with the SMTP connection (encrypted) if a client certificate is not - received, or if the certificate does not verify. This state can be detected - in an ACL, which makes it possible to implement policies such as "accept for - relay only if a verified certificate has been received but accept for local - delivery if encrypted, even without a verified certificate". - - A match in tls_verify_hosts overrides tls_try_verify_hosts. - - -The Daemon ----------- - -. local_interfaces can now specify a port number with each address, thus - allowing a single Exim daemon to listen on multiple ports. The format of each - address is either [aaaa]:ppp or aaaa.ppp where aaaa is an IP address and ppp - is a port number. For example: - - local_interfaces = 192.168.3.4.25 : 192.168.3.4.26 - - If an address is listed without a port, the setting of daemon_smtp_port, or - the value of the -oX option, is the default. - -. The -oX option can now override local_interfaces. That is, it can supply IP - addresses as well as just a port. It is interpreted in this way if its value - contains any of the characters . : or []. For example: - - exim -bd -oX 10.9.8.7:10.11.12.13.2525 - - The format of the string is identical to the format recognized by the - local_interfaces option. - -. The way the daemon wrote PID files was overly complicated and messy. It no - longer tries to be clever. A PID file is written if, and only if, -bd is used - and -oX is _not_ used. In other words, only if the daemon is started with its - standard options. There is only one PID file. If pid_file_path is unset, it - is exim-daemon.pid in Exim's spool directory. Otherwise the value of - pid_file_path is used. For backwards compatibility, "%s" in this value is - replaced by an empty string. - - -Logging -------- - -The log_level option and all the various independent logging control options -have been abolished. In their place there is a single option called -log_selector. It takes a string argument composed of names preceded by + or - -characters. These turn on or off the logging of different things. For example: - - log_selector = +arguments -retry_defer - -The optional logging items (defaults marked *) are: - - address_rewrite address rewriting - all_parents all parents in => lines - arguments exim arguments - *connection_reject connection rejections - *delay_delivery immediate delivery delayed (message queued) - delivery_size add S=nnn to delivery lines - *dnslist_defer defers of DNS list (aka RBL) lookups - incoming_interface incoming interface on <= lines - incoming_port incoming port on <= lines - *lost_incoming_connection as it says (includes timeouts) - *queue_run start and end queue runs - received_sender sender on <= lines - received_recipients recipients on <= lines - *retry_defer "retry time not reached" - sender_on_delivery add sender to => lines - *size_reject rejection because too big - *skip_delivery "message is frozen" - smtp_confirmation SMTP confirmation on <= lines - smtp_connection SMTP connections - smtp_protocol_error SMTP protocol errors - smtp_syntax_error SMTP syntax errors - subject contents of Subject: on <= lines - *tls_cipher TLS cipher on <= lines - tls_peerdn TLS peer DN on <= lines - - all all of the above - -"retry time not reached" is always omitted from individual message logs after -the first delivery attempt. - -The log line "error message sent to" has been abolished, because the R= item on -the incoming message line gives the relationship between the original message -and the bounce. - -The logging options that have been abolished are: log_all_parents, -log_arguments, log_incoming_port, log_interface, log_ip_options, -log_level, log_queue_run_level, log_received_sender, log_received_recipients, -log_rewrites, log_sender_on_delivery, log_smtp_confirmation, -log_smtp_connections, log_smtp_syntax_errors, log_subject, tls_log_cipher, -tls_log_peerdn. - - -Debugging ---------- - -The debug_level option has been removed. The -dm option has been removed. The --df option has also be removed, along with its related build-time option -STDERR_FILE. (To debug inetd usage, an auxiliary script should be used.) - -The -d option has been reworked. It no longer takes a debug level number -argument, but instead takes a list of debugging names, each preceded by + or - -to turn on or off individual sets of debugging messages. - -. The -v option now shows just the SMTP dialog and any log lines. - -. -d with no argument gives a lot of standard debugging data. This is in effect - the equivalent of the old -d9, the thing you ask people to set for an initial - debugging test. - -. -d+x adds debugging option x to the default set - -d-x removes debugging option x from the default set - -d-all+x leaves only debugging option x - -The available debugging names are: - - acl ACL interpretation - auth authenticators - deliver general delivery logic - dns DNS lookups (see also resolver) - dnsbl DNS black list (aka RBL) code - exec arguments for execv() calls - filter filter handling - hints_lookup hints data lookups - host_lookup all types of name->IP address handling - ident ident lookup - interface lists of local interfaces - lists matching things in lists - load system load checks - lookup general lookup code and all lookups - memory memory handling (replaces the old -dm) - process_info setting info for the process log - queue_run queue runs - receive general message reception logic - resolver turn on the DNS resolver's debugging output; goes to stdout - retry retry handling - rewrite rewriting - route address routing - tls TLS logic - transport transports - uid changes of uid/gid and looking up uid/gid - verify address verification logic - - all all of the above, and also -v - -The default (-d with no argument) includes all of the above, plus -v, with the -exception of filter, interface, load, memory, and resolver. Some debugging -output always happens unconditionally whenever any debugging is selected. This -includes some initial output and every log line. - --d without any value was previously allowed for non-admin users because it used -to be synonymous with -v. In Exim 4, non-admin users may use -v, but not -d. - -If the debug_print option is set in any driver, it produces output whenever any -debugging is selected, or if -v is used. - - -Local Scan Function -------------------- - -For customized message scanning, you can now supply a C function that is linked -into the Exim binary. The function is called local_scan(), and it is called -when Exim has received a message, but has not yet sent a final -acknowledgement to the sender. This applies to all messages, whether local or -remote, SMTP or not. - -From within your function you can inspect the message, change the recipients, -add or remove headers, and tell Exim whether to accept or reject the message. - -The manual contains the specification of the API for this function. - - -String Expansion ----------------- - -. The lookup feature that allowed for subkeys using the syntax - - ${lookup {key:subkey} type {data... - - has been abolished (a) because the effect can be achieved using ${extract, - and (b) because in non-lsearch lookups, a colon can be a valid character in a - key. - -. When a string key is used in a ${extract expansion item, it is now handled - case-insensitively. - -. A new expansion variable called $tod_epoch gives the time as a single decimal - number representing the number of seconds from the start of the Unix epoch. - -. There's a new expansion operator that can turn numbers into base 62, for - example, ${base62:$tod_epoch}. - -. ${extract{number} now recognizes a negative number as a request to count - fields from the right. - -. There's a new expansion feature for reading files: - - ${readfile{/some/file}{eolstring}} - - The contents of the file replace the item. If {eolstring} is present (it's - optional) any newlines in the file are replaced by that string. - -. There's a new expansion feature for running commands: - - ${run{command args}{yes}{no}} - - Like all the other conditional items, the {yes} and {no} strings are - optional. Omitting both is equivalent to {$value}. The standard output of the - command is put into $value if the command succeeds (returns a zero code). The - value of the code itself is put into $runrc, and this remains set afterwards, - so in a filter file you can do things like - - if "${run{x y z}{}}$runrc" is 1 then ... - elsif $runrc is 2 then ... - - As in other command executions from Exim, a shell is not used by default. - If you want a shell, you must explicitly code it. - -. The redirect router has options for forbidding ${readfile and ${run in - filters. - -. A feature is provided to suppress expansion of part of a string. Any - characters between two occurrences of \N are copied to the output string - verbatim. This is particularly useful for protecting regular expressions from - unwanted expansion effects. For example: - - queue_smtp_domains = ! \N^ten-\d+\.testing\.com$\N - - Without \N the \ and $ characters in the regex would have to be escaped. - -. Radius authentication is supported in a similar way to PAM. You must set - RADIUS_CONFIG_FILE in Local/Makefile to specify the location of the Radius - client configuration file. Then you can use expansions such as - - server_condition = ${if radius{arguments}{yes}{no}} - -. User authentication can now also be done by attempting to bind to an LDAP - server. The syntax is again similar to PAM and Radius. - - server_condition = ${if ldapauth{ldap query}{yes}{no}} - - A user and password are required to be supplied with the query. No actual - data is looked up; Exim just does a bind to the LDAP server and sets the - condition according to the result. Here's an example of an SMTP - authenticator: - - login: - driver = plaintext - public_name = LOGIN - server_prompts = "Username:: : Password::" - server_condition = ${if ldapauth \ - {user="uid=${quote_ldap:$1},ou=people,o=example.org" pass="$2" \ - ldap://ldap.example.org/}{yes}{no}} - server_set_id = uid=$1,ou=people,o=example.org - - - -Security --------- - -Exim 3 could be run in a variety of ways as far as security was concerned. This -has all been simplified in Exim 4. Exim dropped the use of seteuid() in -most places. But recent (2020-10/2021-04) vulnerabilities forced us to -re-introduce seteuid() for opening the database files (hint files) as secure as -possible. For future (>= 4.95) versions we work on a solution that -does not need the seteuid call. - -. A UID and GID are required to be specified when Exim is compiled. They can be - now specified by name as well as by number, so the relevant options are now - called EXIM_USER and EXIM_GROUP. If you really feel you have to run Exim as - root, you can specify root here, but it is not recommended. - -. The "security" option has been abolished. Exim always releases its root - privilege when it can. In a conventional configuration, that means when it is - receiving a message, when it is delivering a message, when it is running a - queryprogram router, and when it is obeying users' filter files (and system - filters if it has been given a user for that purpose). - -. One important change is that Exim 4 runs as root while routing addresses for - delivery. Exim 3 used seteuid() to give up privilege temporarily while - routing. Apart from the unliked use of seteuid(), this sometimes gave rise to - permissions problems on configuration files. - -. However, Exim still runs as the Exim user while receiving messages, and - therefore while using the routing logic for verifying at SMTP time. - -. There is a new option called deliver_drop_privilege. If this is set, Exim - gives up its privilege right at the start of a delivery process, and runs the - entire delivery as the Exim user. This is the same action that used to be - requested by setting security=unprivileged. - - -Hints Databases ---------------- - -. A single "misc" hints database is now used for ETRN and host serialization. - There have been appropriate consequential changes to the utilities for - managing the hints. - -. The exim_tidydb -f option has been abolished. A full tidy is now always done - (it hasn't proved to be very expensive). - - -The run time Configuration File ------------------------------- - -. The format of the configuration file has changed. Instead of using "end" to - terminate sections, it now uses "begin " to start sections. This means - that the sections, apart from the first, may appear in any order. - -. You can now include other files inside Exim run time configuration files, by - using this syntax: - - .include - -. Quotes round the file name are optional. Includes may be nested to any depth, - but remember that Exim reads its configuration file often. The processing of - .include happens early, at a physical line level, so, like comment lines, it - can be used in the middle of an options setting, for example: - - hosts_lookup = a.b.c \ - .include /some/file - - Include processing happens _before_ macro processing. Its effect is simply to - process the lines of the file as if they occurred inline where the .include - appears. - -. A macro at the start of a configuration line can now turn the line into an - empty line or a comment line. This applies to _logical_ input lines, that is, - after any concatenations have been done. - - -Format of spool files ---------------------- - -. -local_scan is used in spool files to record the value of $local_scan_data, - the string returned from the locally-provided local_scan() function. - - -Renamed Options ---------------- - -Some options have been renamed, to make their function clearer, or for -consistency. - -. receiver_unqualified_hosts has been renamed as recipient_unqualified_hosts. - I'm going to use "recipient" everywhere in future. - -. helo_verify has become helo_verify_hosts. - -. remote_sort has become remote_sort_domains. - -. In the appendfile and pipe transports, "prefix" and "suffix" have become - "message_prefix" and "message_suffix". In the generic router options, - "prefix" and "suffix" have become "local_part_prefix" and "local_part_suffix". - - -Miscellaneous -------------- - -. ETRN serialization now uses a double fork, so that an Exim process (detached - from the original input process) can wait for the command to finish. This - means that it works whatever command ETRN causes to run. (Previously it - worked only if ETRN ran "exim -Rxxx".) - -. For incoming messages, the server's port number is preserved, and is - available in $interface_port. The privileged option -oMi can be used to - set this value. - -. The -Mmd option (to mark addresses delivered) now operates in a - case-sensitive manner. - -. Checks for duplicate deliveries are now case-sensitive in the local part. - -. The number of situations where Exim panics has been reduced. For example, - expansion failures for the "domains" or "local_parts" options in a router now - cause deferral instead of a panic. - -. EXPN no longer attempts to distinguish local and remote addresses (but you - can cause it to be rejected for certain arguments in the ACL). - -. accept_timeout has been renamed as receive_timeout, to match - smtp_receive_timeout. - -. The ability to check an ident value as part of an item in a host list has - been removed. - -. The reject log shows a message's headers only if the rejection happens after - the SMTP DATA command (because they aren't available for earlier checks). The - sender, and up to five recipients are listed in Envelope-from: and - Envelope-to: header lines. After the headers, a line of separator characters - is output. Separators are no longer used for other reject log entries. - -. Because header checks are now done as part of ACLs, they now apply only to - SMTP input. - -. The port number on SMTP connections is now logged in the format [aaaa]:ppp - where aaaa is an IP address and ppp is a port, instead of in the format - [aaaa.ppp] because the former format causes some software to complain about - bad IP addresses. - -. The -oMa and -oMi options can now use the [aaaa]:ppp notation to set a port - number, but they still also recognize the aaaa.ppp notation. - -. The build-time option HAVE_AUTH is abolished. Exim automatically includes - authentication code if any authenticators are configured. - -. The nobody_user and nobody_group options have been abolished. - -. The $message_precedence variable has been abolished. The value is now - available as $h_precedence:. - -. There's a new utility script called exim_checkaccess which packages up a call - to Exim with the -bh option, for access control checking. The syntax is - - exim_checkaccess [exim options] - - It runs "exim -bh ", does the SMTP dialogue, tests the result and - outputs either "accepted" or "Rejected" and the SMTP response to the RCPT TO - command. The sender is <> by default, but can be changed by the use of the - -f option. - -. The default state of Exim is now to forbid domain literals. For this reason, - the option that changes this has been renamed as allow_domain_literals. - -. The dns_check_names boolean option has been abolished. Checking is now turned - off by unsetting dns_check_names_pattern. - -. The errors_address and freeze_tell_mailmaster options have been abolished. In - their place there is a new option called freeze_tell, which can be set to a - list of addresses. A message is sent to these addresses whenever a message is - frozen - with the exception of failed bounce messages (this is not changed). - -. The message_size_limit_count_recipients option has been abolished on the - grounds that it was a failed experiment. - -. The very-special-purpose X rewrite flag has been abolished. The facility it - provided can now be done using the features of ACLs. - -. The timestamps_utc option has been abolished. The facility is now provided by - setting timezone = utc. - -. The value of remote_max_parallel now defaults to 2. - -. ignore_errmsg_errors has been abolished. The effect can be achieved by - setting ignore_bounce_errors_after = 0s. This option has been renamed from - ignore_errmsg_errors_after to make its function clearer. The default value - for ignore_bounce_errors_after is now 10w (10 weeks - i.e. likely to be - longer than any other timeouts, thereby disabling the facility). - -. The default for message_size_limit is now 50M as a guard against DoS attacks. - -. The -qi option does only initial (first time) deliveries. This can be helpful - if you are injecting message onto the queue using -odq and want a queue - runner just to process new messages. You can also use -qqi if you want. - -. Rewriting and retry patterns are now anything that can be single address list - items. They are processed by the same code, and are therefore expanded before - the matching takes place. Regular expressions must be suitably quoted. These - patterns may now be enclosed in double quotes so that white space may be - included. Normal quote processing applies. - -. Some scripts were built in the util directory, which was a mistake, because - they might be different for different platforms. Everything that is built is - now built in the build directory. The util directory just contains a couple - of scripts that are not modified at build time. - -. The installation script now installs the Exim binary as exim-v.vv-bb (where - v.vv is the version number and bb is the build number), and points a symbolic - link called "exim" to this binary. It does this in an atomic way so that - there is no time when "exim" is non-existent. The script is clever enough to - cope with an existing non-symbolic-link binary, converting it to the new - scheme automatically (and atomically). - -. When installing utilities, Exim now uses cp instead of mv to add .O to the - old ones, in order to preserve the permissions. - -. If the installation script is installing the default configuration, and - /etc/aliases does not exist, the script installs a default version. This does - not actually contain any aliases, but it does contain comments about ones - that should be created. A warning is output to the user. - -. A delay warning message is not sent if all the addresses in a message get a - "retry time not reached" error. Exim waits until a delivery is actually - attempted, so as to be able to give a more informative message. - -. The existence of the three options deliver_load_max, queue_only_load, and - deliver_queue_load_max was confusing, because their function overlapped. The - first of them has been abolished. We are left with - - queue_only_load no immediate delivery if load is high when - message arrives - deliver_queue_load_max no queued delivery if load is too high - -. The ability to edit message bodies (-Meb and the Eximon menu item) has been - removed, on the grounds that it is bad practice to do this. - -. Eximstats is now Steve Campbell's patched version, which displays sizes in K - and M and G, and can optionally generate HTML. - -. If bounce_sender_authentication is set to an email address, this address is - used in an AUTH option of the MAIL command when sending bounce messages, if - authentication is being used. For example, if you set - - bounce_sender_authentication = mailer-daemon@your.domain - - a bounce message will be sent over an authenticated connection using - - MAIL FROM:<> AUTH=mailer-daemon@your.domain - -. untrusted_set_sender has changed from a boolean to an address pattern. It - permits untrusted users to set sender addresses that match the pattern. Like - all address patterns, it is expanded. The identity of the user is in - $sender_ident, so you can, for example, restrict users to setting senders - that start with their login ids by setting - - untrusted_set_sender = ^$sender_ident- - - The effect of the previous boolean can be achieved by setting the value to *. - This option applies to all forms of local input. - -. The always_bcc option has been abolished. If an incoming message has no To: - or Cc: headers, Exim now always adds an empty Bcc: line. This makes the - message valid for RFC 822 (sic). In time, this can be removed, because RFC - 2822 does not require there to be a recipient header. - -. ACTION_OUTPUT=no is now the default in the Exim monitor. - -. dns_ipv4_lookup has changed from a boolean into a domain list, and it now - applies only to those domains. Setting this option does not stop Exim from - making IPv6 calls: if an MX lookup returns AAAA records, Exim will use them. - What it does is to stop Exim looking for AAAA records explicitly. - -. The -G option is ignored (another Sendmail thing). - -. If no_bounce_return_message is set, the original message is not included in - bounce messages. If you want to include additional information in the bounce - message itself, you can use the existing errmsg_file and errmsg_text - facilities. - -. -bdf runs the daemon in the foreground (i.e. not detached from the terminal), - even when no debugging is requested. - -. Options for changing Exim's behaviour on receiving IPv4 options have been - abolished. Exim now always refuses calls that set these options, and logs the - incident. The abolished options are kill_ip_options, log_ip_options, and - refuse_ip_options. - -. The pattern for each errors_copy entry is now matched as an item in an - address list. - -. A number of options and variables that used the word "errmsg" have been - changed to use "bounce" instead, because it seems that "bounce message" is - now a reasonably well-understood term. I used it in the book and am now using - it in the manual; it's a lot less cumbersome than "delivery error - notification message". The changes are: - - $errmsg_recipient => $bounce_recipient - errmsg_file => bounce_message_file - errmsg_text => bounce_message_text - ignore_errmsg_errors_after => ignore_bounce_errors_after - - For consistency, warnmsg_file has been changed to warn_message_file. However, - the two variables $warnmsg_delay and $warnmsg_recipients are unchanged. - - The hide_child_in_errmsg option has not changed, because it applies to both - bounce and delay warning messages. - -. smtp_accept_max_per_host is now an expanded string, so it can be varied on - a per-host basis. However, because this test happens in the daemon before it - forks, the expansion should be kept as simple as possible (e.g. just inline - tests of $sender_host_address). - -. The retry rules can now recognize the error "auth_failed", which happens when - authentication is required, but cannot be done. - -. There's a new option called local_sender_retain which can be set if - no_local_from_check is set. It causes Sender: headers to be retained in - locally-submitted messages. - -. The -dropcr command line option now turns CRLF into LF, and leaves isolated - CRs alone. Previously it simply dropped _all_ CR characters. There is now - also a drop_cr main option which, if turned on, assumes -dropcr for all - non-SMTP input. - - -Removal of Obsolete Things --------------------------- - -. The obsolete values "fail_soft" and "fail_hard" for the "self" option have - been removed. - -. The obsolete "log" command has been removed from the filter language. - -. "service" was an obsolete synonym for "port" when specifying IP port numbers. - It has been removed. - -. The obsolete option collapse_source_routes has been removed. It has done - nothing since release 3.10. - -. The obsolete from_hack option in appendfile and pipe transports has been - removed. - -. The obsolete ipv4_address_lookup has been abolished (dns_ipv4_lookup has been - a synonym for some time, but it's changed - see above). - -. The obsolete generic transport options add_headers and remove_headers have - been abolished. The new names, headers_add and headers_remove, have been - available for some time. - -Philip Hazel -February 2002 diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index a6354a4c9..1daded431 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -250,8 +250,7 @@ macro.c: macro_predef utils: $(EXIM_MONITOR) exicyclog exinext exiwhat \ exigrep eximstats exipick exiqgrep exiqsumm \ - transport-filter.pl convert4r3 convert4r4 \ - exim_checkaccess \ + transport-filter.pl exim_checkaccess \ exim_dbmbuild exim_dumpdb exim_fixdb exim_tidydb \ exim_lock exim_msgdate exim_id_update @@ -490,30 +489,6 @@ transport-filter.pl: config ../src/transport-filter.src @chmod a+x transport-filter.pl @echo ">>> transport-filter.pl script built" -convert4r3: config ../src/convert4r3.src - @rm -f convert4r3 - @. ./version.sh && sed \ - -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \ - -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \ - -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \ - ../src/convert4r3.src > convert4r3-t - @mv convert4r3-t convert4r3 - @chmod a+x convert4r3 - @./convert4r3 -v 2>&1 >/dev/null - @echo ">>> convert4r3 script built" - -convert4r4: config ../src/convert4r4.src - @rm -f convert4r4 - @. ./version.sh && sed \ - -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \ - -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \ - -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \ - ../src/convert4r4.src > convert4r4-t - @mv convert4r4-t convert4r4 - @chmod a+x convert4r4 - @./convert4r4 -v 2>&1 >/dev/null - @echo ">>> convert4r4 script built" - # These are objects of optional features. They are always compiled, but # if the corresponding #defines are not set, they wind up empty and diff --git a/src/README b/src/README index e335cc22e..768eabbe8 100644 --- a/src/README +++ b/src/README @@ -10,7 +10,7 @@ published by UIT Cambridge in May 2003. This is the official guide for Exim 4. The current edition covers release 4.10 and a few later extensions. The O'Reilly book about Exim ("Exim The Mail Transfer Agent" by Philip Hazel) -covers Exim 3, which is now deprecated. Exim 4 has a large number of changes +covers Exim 3, which is now obsolete. Exim 4 has a large number of changes from Exim 3, though the basic structure and philosophy remains the same. The older book may be helpful for the background, but a lot of the detail has changed, so it is likely to be confusing to newcomers. diff --git a/src/src/convert4r3.src b/src/src/convert4r3.src deleted file mode 100755 index d0b94d15e..000000000 --- a/src/src/convert4r3.src +++ /dev/null @@ -1,1382 +0,0 @@ -#! PERL_COMMAND - -# This is a Perl script that reads an Exim run-time configuration file and -# checks for settings that were valid prior to release 3.00 but which were -# obsoleted by that release. It writes a new file with suggested changes to -# the standard output, and commentary about what it has done to stderr. - -# It is assumed that the input is a valid Exim configuration file. - -use warnings; -BEGIN { pop @INC if $INC[-1] eq '.' }; - -use Getopt::Long; -use File::Basename; - -GetOptions( - 'version' => sub { - print basename($0) . ": $0\n", - "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n", - "perl(runtime): $^V\n"; - exit 0; - }, -); - -################################################## -# Analyse one line # -################################################## - -# This is called for the main and the driver sections, not for retry -# or rewrite sections (which are unmodified). - -sub checkline{ -my($line) = $_[0]; - -return "comment" if $line =~ /^\s*(#|$)/; -return "end" if $line =~ /^\s*end\s*$/; - -# Macros are recognized only in the first section of the file. - -return "macro" if $prefix eq "" && $line =~ /^\s*[A-Z]/; - -# Pick out the name at the start and the rest of the line (into global -# variables) and return whether the start of a driver or not. - -($i1,$name,$i2,$rest) = $line =~ /^(\s*)([a-z0-9_]+)(\s*)(.*?)\s*$/; -return ($rest =~ /^:/)? "driver" : "option"; -} - - - - -################################################## -# Add transport setting to a director # -################################################## - -# This function adds a transport setting to an aliasfile or forwardfile -# director if a global setting exists and a local one does not. If neither -# exist, it adds file/pipe/reply, but not the directory ones. - -sub add_transport{ -my($option) = @_; - -my($key) = "$prefix$driver.${option}_transport"; -if (!exists $o{$key}) - { - if (exists $o{"address_${option}_transport"}) - { - print STDOUT "# >> Option added by convert4r3\n"; - printf STDOUT "${i1}${option}_transport = %s\n", - $o{"address_${option}_transport"}; - printf STDERR - "\n%03d ${option}_transport added to $driver director.\n", - ++$count; - } - else - { - if ($option eq "pipe" || $option eq "file" || $option eq "reply") - { - print STDOUT "# >> Option added by convert4r3\n"; - printf STDOUT "${i1}${option}_transport = address_${option}\n"; - printf STDERR - "\n%03d ${option}_transport added to $driver director.\n", - ++$count; - } - } - } -} - - - - -################################################## -# Negate a list of things # -################################################## - -sub negate { -my($list) = $_[0]; - -return $list if ! defined $list; - -($list) = $list =~ /^"?(.*?)"?\s*$/s; - -# Under Perl 5.005 we can split very nicely at colons, ignoring double -# colons, like this: -# -# @split = split /\s*(?%%%%%%%%> Option rewritten by convert4r3\n"; -print STDOUT "${i1}$name = \""; - -if (defined $reject_except) - { - print STDOUT "$reject_except"; - $join = " : \\\n "; - $last_was_negated = ($_[4] ne "+"); - } -if (defined $reject) - { - print STDOUT "$join$reject"; - $join = " : \\\n "; - $last_was_negated = ($_[4] eq "+"); - } -if (defined $accept) - { - print STDOUT "$join$accept"; - $last_was_negated = ($_[4] ne "+"); - $join = " : \\\n "; - } - -print STDOUT "$join*" if $last_was_negated; - -print STDOUT "\"\n"; - -my($driver_name); -my($driver_type) = ""; - -if ($_[0] =~ /^(d|r|t)\.([^.]+)\./ || - $_[1] =~ /^(d|r|t)\.([^.]+)\./ || - $_[2] =~ /^(d|r|t)\.([^.]+)\./) - { - $driver_type = ($1 eq 'd')? "director" : ($1 eq 'r')? "router" : "transport"; - $driver_name = $2; - } - -my($x) = ($driver_type ne "")? " in \"$driver_name\" $driver_type" : ""; - -my($l0) = &base($_[0]); -my($l1) = &base($_[1]); -my($l2) = &base($_[2]); - - -if ($l2 eq "") - { - if ($l0 eq "") - { - printf STDERR "\n%03d $l1 converted to $name$x.\n", ++$count; - } - else - { - printf STDERR "\n%03d $l0 and $l1\n amalgamated into $name$x.\n", - ++$count; - } - } -else - { - if ($l1 eq "") - { - printf STDERR "\n%03d $l0 and $l2\n amalgamated into $name$x.\n", - ++$count; - } - else - { - printf STDERR "\n%03d $l0, $l1 and $l2\n amalgamated into " . - "$name$x.\n", ++$count; - } - } -} - - - - -################################################## -# Join two lists, if they exist # -################################################## - -sub pair{ -my($l1) = $o{"$_[0]"}; -my($l2) = $o{"$_[1]"}; - -return $l2 if (!defined $l1); -return $l1 if (!defined $l2); - -($l1) = $l1 =~ /^"?(.*?)"?\s*$/s; -($l2) = $l2 =~ /^"?(.*?)"?\s*$/s; - -return "$l1 : $l2"; -} - - - - -################################################## -# Amalgamate accept/reject/reject_except pairs # -################################################## - -# This is like amalgamate, but it combines pairs of arguments, and -# doesn't output commentary (easier to write a generic one for the few -# cases). - -sub amalgamatepairs { -my($accept) = &pair($_[0], $_[1]); -my($reject) = &pair($_[2], $_[3]); -my($reject_except) = &pair($_[4], $_[5]); -my($last_was_negated) = 0; -my($join) = ""; - -if ($_[7] eq "+") - { - ($accept) = $accept =~ /^"?(.*?)"?\s*$/s if defined $accept; - $reject = &negate($reject) if defined $reject; - ($reject_except) = $reject_except =~ /^"?(.*?)"?\s*$/s if defined $reject_except; - } -else - { - $accept = &negate($accept) if defined $accept; - ($reject) = $reject =~ /^"?(.*?)"?$/s if defined $reject; - $reject_except = &negate($reject_except) if defined $reject_except; - } - -print STDOUT "# >> Option rewritten by convert4r3\n"; -print STDOUT "${i1}$_[6] = \""; - -if (defined $reject_except) - { - print STDOUT "$reject_except"; - $join = " : \\\n "; - $last_was_negated = ($_[7] ne "+"); - } -if (defined $reject) - { - print STDOUT "$join$reject"; - $join = " : \\\n "; - $last_was_negated = ($_[7] eq "+"); - } -if (defined $accept) - { - print STDOUT "$join$accept"; - $last_was_negated = ($_[7] ne "+"); - $join = " : \\\n "; - } - -print STDOUT "$join*" if $last_was_negated; -print STDOUT "\"\n"; -} - - - -################################################## -# Amalgamate boolean and exception list(s) # -################################################## - -sub amalgboolandlist { -my($name,$bool,$e1,$e2) = @_; - -print STDOUT "# >> Option rewritten by convert4r3\n"; -if ($bool eq "false") - { - printf STDOUT "$i1$name =\n"; - } -else - { - printf STDOUT "$i1$name = "; - my($n1) = &negate($o{$e1}); - my($n2) = &negate($o{$e2}); - if (!defined $n1 && !defined $n2) - { - print STDOUT "*\n"; - } - elsif (!defined $n1) - { - print STDOUT "\"$n2 : \\\n *\"\n"; - } - elsif (!defined $n2) - { - print STDOUT "\"$n1 : \\\n *\"\n"; - } - else - { - print STDOUT "\"$n1 : \\\n $n2 : \\\n *\"\n"; - } - } -} - - - -################################################## -# Convert mask format # -################################################## - -# This function converts an address and mask in old-fashioned dotted-quad -# format into an address plus a new format mask. - -@byte_list = (0, 128, 192, 224, 240, 248, 252, 254, 255); - -sub mask { -my($address,$mask) = @_; -my($length) = 0; -my($i, $j); - -my(@bytes) = split /\./, $mask; - -for ($i = 0; $i < 4; $i++) - { - for ($j = 0; $j <= 8; $j++) - { - if ($bytes[$i] == $byte_list[$j]) - { - $length += $j; - if ($j != 8) - { - for ($i++; $i < 4; $i++) - { - $j = 9 if ($bytes[$i] != 0); - } - } - last; - } - } - - if ($j > 8) - { - print STDERR "*** IP mask $mask cannot be converted to /n format. ***\n"; - return "$address/$mask"; - } - } - -if (!defined $masks{$mask}) - { - printf STDERR "\n%03d IP address mask $mask converted to /$length\n", - ++$count, $mask, $length; - $masks{$mask} = 1; - } - -return sprintf "$address/%d", $length; -} - - - - - -################################################## -# Main program # -################################################## - -print STDERR "Exim pre-release 3.00 configuration file converter.\n"; - -$count = 0; -$seen_helo_accept_junk = 0; -$seen_hold_domains = 0; -$seen_receiver_unqualified = 0; -$seen_receiver_verify_except = 0; -$seen_receiver_verify_senders = 0; -$seen_rfc1413_except = 0; -$seen_sender_accept = 0; -$seen_sender_accept_recipients = 0; -$seen_sender_host_accept = 0; -$seen_sender_host_accept_recipients = 0; -$seen_sender_host_accept_relay = 0; -$seen_sender_unqualified = 0; -$seen_sender_verify_except_hosts = 0; -$seen_smtp_etrn = 0; -$seen_smtp_expn = 0; -$seen_smtp_reserve = 0; -$semicomma = 0; - -# Read the entire file into an array - -chomp(@c = ); - -# First, go through the input and covert any net masks in the old dotted-quad -# style into the new /n style. - -for ($i = 0; $i < scalar(@c); $i++) - { - $c[$i] =~ - s"((?:\d{1,3}\.){3}\d{1,3})/((?:\d{1,3}\.){3}\d{1,3})"&mask($1,$2)"eg; - } - -# We now make two more passes over the input. In the first pass, we place all -# the option values into an associative array. Main options are keyed by their -# names; options for drivers are keyed by a driver type letter, the driver -# name, and the option name, dot-separated. In the second pass we modify -# the options if necessary, and write the output file. - -for ($pass = 1; $pass < 3; $pass++) - { - $prefix = ""; - $driver = ""; - $last_was_blank = 0; - - for ($i = 0; $i < scalar(@c); $i++) - { - # Everything after the router section is just copied in pass 2 and - # ignored in pass 1. - - if ($prefix eq "end") - { - print STDOUT "$c[$i]\n" if $pass == 2; - next; - } - - # Analyze the line - - $type = &checkline($c[$i]); - - # Skip comments in pass 1; copy in pass 2 - - if ($type eq "comment") - { - $last_was_blank = ($c[$i] =~ /^\s*$/)? 1 : 0; - print STDOUT "$c[$i]\n" if $pass == 2; - next; - } - - # Skip/copy macro definitions, but must handle continuations - - if ($type eq "macro") - { - print STDOUT "$c[$i]\n" if $pass == 2; - while ($c[$i] =~ /\\\s*$/) - { - $i++; - print STDOUT "$c[$i]\n" if $pass == 2; - } - $last_was_blank = 0; - next; - } - - # Handle end of section - - if ($type eq "end") - { - $prefix = "end"if $prefix eq "r."; - $prefix = "r." if $prefix eq "d."; - $prefix = "d." if $prefix eq "t."; - $prefix = "t." if $prefix eq ""; - print STDOUT "$c[$i]\n" if $pass == 2; - $last_was_blank = 0; - next; - } - - # Handle start of a new driver - - if ($type eq "driver") - { - $driver = $name; - print STDOUT "$c[$i]\n" if $pass == 2; - $last_was_blank = 0; - $seen_domains = 0; - $seen_local_parts = 0; - $seen_senders = 0; - $seen_mx_domains = 0; - $seen_serialize = 0; - next; - } - - # Handle definition of an option - - if ($type eq "option") - { - # Handle continued strings - - if ($rest =~ /^=\s*".*\\$/) - { - for (;;) - { - $rest .= "\n$c[++$i]"; - last unless $c[$i] =~ /(\\\s*$|^\s*#)/; - } - } - - # Remove any terminating commas and semicolons in pass 2 - - if ($pass == 2 && $rest =~ /[;,]\s*$/) - { - $rest =~ s/\s*[;,]\s*$//; - if (!$semicomma) - { - printf STDERR - "\n%03d Terminating semicolons and commas removed from driver " . - "options.\n", ++$count; - $semicomma = 1; - } - } - - # Convert all booleans to "x = true/false" format, but save the - # original so that it can be reproduced unchanged for options that - # are not of interest. - - $origname = $name; - $origrest = $rest; - - if ($name =~ /^not?_(.*)/) - { - $name = $1; - $rest = "= false"; - } - elsif ($rest !~ /^=/) - { - $rest = "= true"; - } - - # Set up the associative array key, and get rid of the = on the data - - $key = ($prefix eq "")? "$name" : "$prefix$driver.$name"; - ($rest) = $rest =~ /^=\s*(.*)/s; - - # Create the associative array of values in pass 1 - - if ($pass == 1) - { - $o{$key} = $rest; - } - - # In pass 2, test for interesting options and do the necessary; copy - # all the rest. - - else - { - ########## Global configuration ########## - - # These global options are abolished - - if ($name eq "address_directory_transport" || - $name eq "address_directory2_transport" || - $name eq "address_file_transport" || - $name eq "address_pipe_transport" || - $name eq "address_reply_transport") - { - ($n2) = $name =~ /^address_(.*)/; - printf STDERR "\n%03d $name option deleted.\n", ++$count; - printf STDERR " $n2 will be added to appropriate directors.\n"; - $i = &skipblanks($i); - next; - } - - # This debugging option is abolished - - elsif ($name eq "sender_verify_log_details") - { - printf STDERR "\n%03d $name option deleted.\n", ++$count; - printf STDERR " (Little used facility abolished.)\n"; - } - - # This option has been renamed - - elsif ($name eq "check_dns_names") - { - $origname =~ s/check_dns/dns_check/; - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "$i1$origname$i2$origrest\n"; - printf STDERR "\n%03d check_dns_names renamed as dns_check_names.\n", - ++$count; - } - - # helo_accept_junk_nets is abolished - - elsif ($name eq "helo_accept_junk_nets" || - $name eq "helo_accept_junk_hosts") - { - if (!$seen_helo_accept_junk) - { - &amalgamate("helo_accept_junk_nets", "", - "helo_accept_junk_hosts", "helo_accept_junk_hosts", "+"); - $seen_helo_accept_junk = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # helo_verify_except_{hosts,nets} are abolished, and helo_verify - # is now a host list instead of a boolean. - - elsif ($name eq "helo_verify") - { - &amalgboolandlist("helo_verify", $rest, "helo_verify_except_hosts", - "helo_verify_except_nets"); - printf STDERR "\n%03d helo_verify converted to host list.\n", - ++$count; - } - elsif ($name eq "helo_verify_except_hosts" || - $name eq "helo_verify_except_nets") - { - $i = &skipblanks($i); - next; - } - - # helo_verify_nets was an old synonym for host_lookup_nets; only - # one of them will be encountered. Change to a new name. - - elsif ($name eq "helo_verify_nets" || - $name eq "host_lookup_nets") - { - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "${i1}host_lookup$i2$origrest\n"; - printf STDERR "\n%03d $name renamed as host_lookup.\n", ++$count; - } - - # hold_domains_except is abolished; add as negated items to - # hold_domains. - - elsif ($name eq "hold_domains_except" || - $name eq "hold_domains") - { - if ($seen_hold_domains) # If already done with these - { # omit, and following blanks. - $i = &skipblanks($i); - next; - } - $seen_hold_domains = 1; - - if (exists $o{"hold_domains_except"}) - { - &amalgamate("hold_domains", "hold_domains_except", "", - "hold_domains", "+"); - } - else - { - print STDOUT "$i1$origname$i2$origrest\n"; - } - } - - # ignore_fromline_nets is renamed as ignore_fromline_hosts - - elsif ($name eq "ignore_fromline_nets") - { - $origname =~ s/_nets/_hosts/; - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "$i1$origname$i2$origrest\n"; - printf STDERR - "\n%03d ignore_fromline_nets renamed as ignore_fromline_hosts.\n", - ++$count; - } - - # Output a warning for message filters with no transports set - - elsif ($name eq "message_filter") - { - print STDOUT "$i1$origname$i2$origrest\n"; - - if (!exists $o{"message_filter_directory_transport"} && - !exists $o{"message_filter_directory2_transport"} && - !exists $o{"message_filter_file_transport"} && - !exists $o{"message_filter_pipe_transport"} && - !exists $o{"message_filter_reply_transport"}) - { - printf STDERR - "\n%03d message_filter is set, but no message_filter transports " - . "are defined.\n" - . " If your filter generates file or pipe deliveries, or " - . "auto-replies,\n" - . " you will need to define " - . "message_filter_{file,pipe,reply}_transport\n" - . " options, as required.\n", ++$count; - } - } - - # queue_remote_except is abolished, and queue_remote is replaced by - # queue_remote_domains, which is a host list. - - elsif ($name eq "queue_remote") - { - &amalgboolandlist("queue_remote_domains", $rest, - "queue_remote_except", ""); - printf STDERR - "\n%03d queue_remote converted to domain list queue_remote_domains.\n", - ++$count; - } - elsif ($name eq "queue_remote_except") - { - $i = &skipblanks($i); - next; - } - - # queue_smtp_except is abolished, and queue_smtp is replaced by - # queue_smtp_domains, which is a host list. - - elsif ($name eq "queue_smtp") - { - &amalgboolandlist("queue_smtp_domains", $rest, - "queue_smtp_except", ""); - printf STDERR - "\n%03d queue_smtp converted to domain list queue_smtp_domains.\n", - ++$count; - } - elsif ($name eq "queue_smtp_except") - { - $i = &skipblanks($i); - next; - } - - # rbl_except_nets is replaced by rbl_hosts - - elsif ($name eq "rbl_except_nets") - { - &amalgamate("", "rbl_except_nets", "", "rbl_hosts", "+"); - } - - # receiver_unqualified_nets is abolished - - elsif ($name eq "receiver_unqualified_nets" || - $name eq "receiver_unqualified_hosts") - { - if (!$seen_receiver_unqualified) - { - &amalgamate("receiver_unqualified_nets", "", - "receiver_unqualified_hosts", "receiver_unqualified_hosts", "+"); - $seen_receiver_unqualified = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # receiver_verify_except_{hosts,nets} are replaced by - # receiver_verify_hosts. - - elsif ($name eq "receiver_verify_except_hosts" || - $name eq "receiver_verify_except_nets") - { - if (!$seen_receiver_verify_except) - { - &amalgboolandlist("receiver_verify_hosts", "true", - "receiver_verify_except_hosts", "receiver_verify_except_nets"); - printf STDERR - "\n%03d receiver_verify_except_{hosts,nets} converted to " . - "receiver_verify_hosts.\n", - ++$count; - $seen_receiver_verify_except = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # receiver_verify_senders_except is abolished - - elsif ($name eq "receiver_verify_senders" || - $name eq "receiver_verify_senders_except") - { - if (defined $o{"receiver_verify_senders_except"}) - { - if (!$seen_receiver_verify_senders) - { - &amalgamate("receiver_verify_senders", - "receiver_verify_senders_except", "", - "receiver_verify_senders", "+"); - $seen_receiver_verify_senders = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - else - { - print STDOUT "$i1$origname$i2$origrest\n"; - } - } - - # rfc1413_except_{hosts,nets} are replaced by rfc1413_hosts. - - elsif ($name eq "rfc1413_except_hosts" || - $name eq "rfc1413_except_nets") - { - if (!$seen_rfc1413_except) - { - &amalgboolandlist("rfc1413_hosts", "true", - "rfc1413_except_hosts", "rfc1413_except_nets"); - printf STDERR - "\n%03d rfc1413_except_{hosts,nets} converted to rfc1413_hosts.\n", - ++$count; - $seen_rfc1413_except = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # sender_accept and sender_reject_except are abolished - - elsif ($name eq "sender_accept" || - $name eq "sender_reject") - { - if (!$seen_sender_accept) - { - &amalgamate("sender_accept", "sender_reject", - "sender_reject_except", "sender_reject", "-"); - $seen_sender_accept = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # sender_accept_recipients is also abolished; sender_reject_except - # also used to apply to this, so we include it here as well. - - elsif ($name eq "sender_accept_recipients" || - $name eq "sender_reject_recipients") - { - if (!$seen_sender_accept_recipients) - { - &amalgamate("sender_accept_recipients", "sender_reject_recipients", - "sender_reject_except", "sender_reject_recipients", "-"); - $seen_sender_accept_recipients = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # sender_reject_except must be removed - - elsif ($name eq "sender_reject_except") - { - $i = &skipblanks($i); - next; - } - - # sender_{host,net}_{accept,reject}[_except] all collapse into - # host_reject. - - elsif ($name eq "sender_host_accept" || - $name eq "sender_net_accept" || - $name eq "sender_host_reject" || - $name eq "sender_net_reject") - { - if (!$seen_sender_host_accept) - { - &amalgamatepairs("sender_host_accept", "sender_net_accept", - "sender_host_reject", "sender_net_reject", - "sender_host_reject_except", "sender_net_reject_except", - "host_reject", "-"); - printf STDERR "\n%03d sender_{host,net}_{accept,reject} and " . - "sender_{host_net}_reject_except\n" . - " amalgamated into host_reject.\n", ++$count; - $seen_sender_host_accept = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # sender_{host,net}_{accept,reject}_recipients all collapse into - # host_reject_recipients. - - elsif ($name eq "sender_host_accept_recipients" || - $name eq "sender_net_accept_recipients" || - $name eq "sender_host_reject_recipients" || - $name eq "sender_net_reject_recipients") - { - if (!$seen_sender_host_accept_recipients) - { - &amalgamatepairs("sender_host_accept_recipients", - "sender_net_accept_recipients", - "sender_host_reject_recipients", - "sender_net_reject_recipients", - "sender_host_reject_except", "sender_net_reject_except", - "host_reject_recipients", "-"); - printf STDERR "\n%03d sender_{host,net}_{accept,reject}_recipients" - . "\n and sender_{host_net}_reject_except" - . "\n amalgamated into host_reject_recipients.\n", ++$count; - $seen_sender_host_accept_recipients = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # sender_{host,net}_reject_except must be removed - - elsif ($name eq "sender_host_reject_except" || - $name eq "sender_net_reject_except") - { - $i = &skipblanks($i); - next; - } - - # sender_{host,net}_{accept,reject}_relay all collapse into - # host_accept_relay. - - elsif ($name eq "sender_host_accept_relay" || - $name eq "sender_net_accept_relay" || - $name eq "sender_host_reject_relay" || - $name eq "sender_net_reject_relay") - { - if (!$seen_sender_host_accept_relay) - { - &amalgamatepairs("sender_host_accept_relay", - "sender_net_accept_relay", - "sender_host_reject_relay", - "sender_net_reject_relay", - "sender_host_reject_relay_except", - "sender_net_reject_relay_except", - "host_accept_relay", "+"); - printf STDERR "\n%03d sender_{host,net}_{accept,reject}_relay" - . "\n and sender_{host_net}_reject_relay_except" - . "\n amalgamated into host_accept_relay.\n", ++$count; - $seen_sender_host_accept_relay = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # sender_{host,net}_reject_relay_except must be removed - - elsif ($name eq "sender_host_reject_relay_except" || - $name eq "sender_net_reject_relay_except") - { - $i = &skipblanks($i); - next; - } - - - # sender_unqualified_nets is abolished - - elsif ($name eq "sender_unqualified_nets" || - $name eq "sender_unqualified_hosts") - { - if (!$seen_sender_unqualified) - { - &amalgamate("sender_unqualified_nets", "", - "sender_unqualified_hosts", "sender_unqualified_hosts", "+"); - $seen_sender_unqualified = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # sender_verify_except_{hosts,nets} are replaced by sender_verify_hosts. - - elsif ($name eq "sender_verify_except_hosts" || - $name eq "sender_verify_except_nets") - { - if (!$seen_sender_verify_except_hosts) - { - &amalgboolandlist("sender_verify_hosts", "true", - "sender_verify_except_hosts", "sender_verify_except_nets"); - printf STDERR - "\n%03d sender_verify_except_{hosts,nets} converted to " . - "sender_verify_hosts.\n", - ++$count; - $seen_sender_verify_except_hosts = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # smtp_etrn_nets is abolished - - elsif ($name eq "smtp_etrn_nets" || - $name eq "smtp_etrn_hosts") - { - if (!$seen_smtp_etrn) - { - &amalgamate("smtp_etrn_nets", "", - "smtp_etrn_hosts", "smtp_etrn_hosts", "+"); - $seen_smtp_etrn = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # smtp_expn_nets is abolished - - elsif ($name eq "smtp_expn_nets" || - $name eq "smtp_expn_hosts") - { - if (!$seen_smtp_expn) - { - &amalgamate("smtp_expn_nets", "", - "smtp_expn_hosts", "smtp_expn_hosts", "+"); - $seen_smtp_expn = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - # This option has been renamed - - elsif ($name eq "smtp_log_connections") - { - $origname =~ s/smtp_log/log_smtp/; - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "$i1$origname$i2$origrest\n"; - printf STDERR "\n%03d smtp_log_connections renamed as " . - "log_smtp_connections.\n", - ++$count; - } - - # smtp_reserve_nets is abolished - - elsif ($name eq "smtp_reserve_nets" || - $name eq "smtp_reserve_hosts") - { - if (!$seen_smtp_reserve) - { - &amalgamate("smtp_reserve_nets", "", - "smtp_reserve_hosts", "smtp_reserve_hosts", "+"); - $seen_smtp_reserve = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - ########### Driver configurations ########## - - # For aliasfile and forwardfile directors, add file, pipe, and - # reply transports - copying from the globals if they are set. - - elsif ($name eq "driver") - { - $driver_type = $rest; - print STDOUT "$i1$origname$i2$origrest\n"; - if ($rest eq "aliasfile" || $rest eq "forwardfile") - { - &add_transport("directory"); - &add_transport("directory2"); - &add_transport("file"); - &add_transport("pipe"); - &add_transport("reply") if $rest eq "forwardfile"; - } - } - - # except_domains is abolished; add as negated items to domains. - - elsif ($name eq "except_domains" || - $name eq "domains") - { - if ($seen_domains) # If already done with these - { # omit, and following blanks. - $i = &skipblanks($i); - next; - } - $seen_domains = 1; - - if (exists $o{"$prefix$driver.except_domains"}) - { - &amalgamate("$prefix$driver.domains", - "$prefix$driver.except_domains", "", - "domains", "+"); - } - else - { - print STDOUT "$i1$origname$i2$origrest\n"; - } - } - - # except_local_parts is abolished; add as negated items to - # local_parts. - - elsif ($name eq "except_local_parts" || - $name eq "local_parts") - { - if ($seen_local_parts) # If already done with these - { # omit, and following blanks. - $i = &skipblanks($i); - next; - } - $seen_local_parts = 1; - - if (exists $o{"$prefix$driver.except_local_parts"}) - { - &amalgamate("$prefix$driver.local_parts", - "$prefix$driver.except_local_parts", "", - "local_parts", "+"); - } - else - { - print STDOUT "$i1$origname$i2$origrest\n"; - } - } - - # except_senders is abolished; add as negated items to senders - - elsif ($name eq "except_senders" || - $name eq "senders") - { - if ($seen_senders) # If already done with these - { # omit, and following blanks. - $i = &skipblanks($i); - next; - } - $seen_senders = 1; - - if (exists $o{"$prefix$driver.except_senders"}) - { - &amalgamate("$prefix$driver.senders", - "$prefix$driver.except_senders", "", - "senders", "+"); - } - else - { - print STDOUT "$i1$origname$i2$origrest\n"; - } - } - - # This option has been renamed - - elsif ($name eq "directory" && $driver_type eq "aliasfile") - { - $origname =~ s/directory/home_directory/; - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "$i1$origname$i2$origrest\n"; - printf STDERR "\n%03d directory renamed as " . - "home_directory in \"$driver\" director.\n", - ++$count; - } - - # This option has been renamed - - elsif ($name eq "directory" && $driver_type eq "forwardfile") - { - $origname =~ s/directory/file_directory/; - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "$i1$origname$i2$origrest\n"; - printf STDERR "\n%03d directory renamed as " . - "file_directory in \"$driver\" director.\n", - ++$count; - } - - # This option has been renamed - - elsif ($name eq "forbid_filter_log" && $driver_type eq "forwardfile") - { - $origname =~ s/log/logwrite/; - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "$i1$origname$i2$origrest\n"; - printf STDERR "\n%03d forbid_filter_log renamed as " . - "forbid_filter_logwrite in \"$driver\" director.\n", - ++$count; - } - - # This option has been renamed - - elsif ($name eq "directory" && $driver_type eq "localuser") - { - $origname =~ s/directory/match_directory/; - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "$i1$origname$i2$origrest\n"; - printf STDERR "\n%03d directory renamed as " . - "match_directory in \"$driver\" director.\n", - ++$count; - } - - # mx_domains_except (and old synonym non_mx_domains) are abolished - # (both lookuphost router and smtp transport) - - elsif ($name eq "mx_domains" || - $name eq "mx_domains_except" || - $name eq "non_mx_domains") - { - if ($seen_mx_domains) # If already done with these - { # omit, and following blanks. - $i = &skipblanks($i); - next; - } - $seen_mx_domains = 1; - - if (exists $o{"$prefix$driver.mx_domains_except"} || - exists $o{"$prefix$driver.non_mx_domains"}) - { - $o{"$prefix$driver.mx_domains_except"} = - &pair("$prefix$driver.mx_domains_except", - "$prefix$driver.non_mx_domains"); - - &amalgamate("$prefix$driver.mx_domains", - "$prefix$driver.mx_domains_except", "", - "mx_domains", "+"); - } - else - { - print STDOUT "$i1$origname$i2$origrest\n"; - } - } - - # This option has been renamed - - elsif ($name eq "directory" && $driver_type eq "pipe") - { - $origname =~ s/directory/home_directory/; - print STDOUT "# >> Option rewritten by convert4r3\n"; - print STDOUT "$i1$origname$i2$origrest\n"; - printf STDERR "\n%03d directory renamed as " . - "home_directory in \"$driver\" director.\n", - ++$count; - } - - # serialize_nets is abolished - - elsif ($name eq "serialize_nets" || - $name eq "serialize_hosts") - { - if (!$seen_serialize) - { - &amalgamate("$prefix$driver.serialize_nets", "", - "$prefix$driver.serialize_hosts", "serialize_hosts", "+"); - $seen_serialize = 1; - } - else - { - $i = &skipblanks($i); - next; - } - } - - - # Option not of interest; reproduce verbatim - - else - { - print STDOUT "$i1$origname$i2$origrest\n"; - } - - - $last_was_blank = 0; - } - } - } - - } - -# Debugging: show the associative array -# foreach $key (sort keys %o) { print STDERR "$key = $o{$key}\n"; } - -print STDERR "\nEnd of configuration file conversion.\n"; -print STDERR "\n*******************************************************\n"; -print STDERR "***** Please review the generated file carefully. *****\n"; -print STDERR "*******************************************************\n\n"; - -print STDERR "In particular:\n\n"; - -print STDERR "(1) If you use regular expressions in any options that have\n"; -print STDERR " been rewritten by this script, they might have been put\n"; -print STDERR " inside quotes, when then were not previously quoted. This\n"; -print STDERR " means that any backslashes in them must now be escaped.\n\n"; - -print STDERR "(2) If your configuration refers to any external files that\n"; -print STDERR " contain lists of network addresses, check that the masks\n"; -print STDERR " are specified as single numbers, e.g. /24 and NOT as dotted\n"; -print STDERR " quads (e.g. 255.255.255.0) because Exim release 3.00 does\n"; -print STDERR " not recognize the dotted quad form.\n\n"; - -print STDERR "(3) If your configuration uses macros for lists of domains or\n"; -print STDERR " hosts or addresses, check to see if any of the references\n"; -print STDERR " have been negated. If so, you will have to rework things,\n"; -print STDERR " because the negation will apply only to the first item in\n"; -print STDERR " the macro-generated list.\n\n"; - -print STDERR "(4) If you do not generate deliveries to pipes, files, or\n"; -print STDERR " auto-replies in your aliasfile and forwardfile directors,\n"; -print STDERR " you can remove the added transport settings.\n\n"; - -# End of convert4r3 diff --git a/src/src/convert4r4.src b/src/src/convert4r4.src deleted file mode 100755 index 47987fc8f..000000000 --- a/src/src/convert4r4.src +++ /dev/null @@ -1,2527 +0,0 @@ -#! PERL_COMMAND - -# This is a Perl script that reads an Exim run-time configuration file for -# Exim 3. It makes what changes it can for Exim 4, and also output commentary -# on what it has done, and on things it cannot do. - -# It is assumed that the input is a valid Exim 3 configuration file. - -use warnings; -BEGIN { pop @INC if $INC[-1] eq '.' }; - -use Getopt::Long; -use File::Basename; - -GetOptions( - 'version' => sub { - print basename($0) . ": $0\n", - "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n", - "perl(runtime): $^V\n"; - exit 0; - }, -); - -# These are lists of main options which are abolished in Exim 4. -# The first contains options that are used to construct new options. - -@skipped_options = ( -"auth_hosts", -"auth_over_tls_hosts", -"errors_address", -"headers_check_syntax", -"headers_checks_fail", -"headers_sender_verify", -"headers_sender_verify_errmsg", -"host_accept_relay", -"host_auth_accept_relay", -"host_reject_recipients", -"local_domains", -"local_domains_include_host", -"local_domains_include_host_literals", -"log_all_parents", -"log_arguments", -"log_incoming_port", -"log_interface", -"log_level", -"log_received_sender", -"log_received_recipients", -"log_rewrites", -"log_sender_on_delivery", -"log_smtp_confirmation", -"log_smtp_connections", -"log_smtp_syntax_errors", -"log_subject", -"log_queue_run_level", -"rbl_domains", -"rbl_hosts", -"rbl_reject_recipients", -"receiver_verify", -"receiver_verify_addresses", -"receiver_verify_hosts", -"receiver_verify_senders", -"recipients_reject_except", -"recipients_reject_except_senders", -"relay_domains", -"relay_domains_include_local_mx", -"sender_address_relay", -"sender_address_relay_hosts", -"sender_reject_recipients", -"sender_verify", -"sender_verify_hosts_callback", -"sender_verify_callback_domains", -"sender_verify_callback_timeout", -"sender_verify_hosts", -"smtp_etrn_hosts", -"smtp_expn_hosts", -"smtp_verify", -"tls_host_accept_relay", -"tls_hosts", -"tls_log_cipher", -"tls_log_peerdn", -"tls_verify_ciphers" -); - -# The second contains options that are completely abolished and have -# no equivalent. - -@abolished_options = ( -"always_bcc", -"debug_level", -"helo_strict_syntax", -"kill_ip_options", -"log_ip_options", -"log_refused_recipients", -"message_size_limit_count_recipients", -"rbl_log_headers", -"rbl_log_rcpt_count", -"receiver_try_verify", -"refuse_ip_options", -"relay_match_host_or_sender", -"sender_try_verify", -"sender_verify_batch", -"sender_verify_fixup", -"sender_verify_reject", -"sender_verify_max_retry_rate", -); - -# This is a list of options that are not otherwise handled, but which -# contain domain or host lists that have to be processed so that any -# regular expressions are marked "not for expansion". - -@list_options = ( -"dns_again_means_nonexist", -"hold_domains", -"hosts_treat_as_local", -"percent_hack_domains", -"queue_smtp_domains", -"helo_accept_junk_hosts", -"host_lookup", -"ignore_fromline_hosts", -"rfc1413_hosts", -"sender_unqualified_hosts", -"smtp_reserve_hosts", -"tls_advertise_hosts", -"tls_verify_hosts", -); - - - -################################################## -# Output problem rubric once # -################################################## - -sub rubric { -return if $rubric_output; -$rubric_output = 1; -print STDERR "\n" . -"** The following comments describe problems that have been encountered\n" . -" while converting an Exim 3 runtime file for Exim 4. More detail can\n" . -" be found in the file doc/Exim4.upgrade.\n"; -} - - -################################################## -# Analyse one line # -################################################## - -sub checkline{ -my($line) = $_[0]; - -return "comment" if $line =~ /^\s*(#|$)/; -return "end" if $line =~ /^\s*end\s*$/i; - -# Macros are recognized only in the first section of the file. - -return "macro" if $prefix eq "" && $line =~ /^\s*[A-Z]/; - -# In retry and rewrite sections, the type is always "other" - -return "other" if $prefix eq "=retry" || $prefix eq "=rewrite"; - -# Pick out the name at the start and the rest of the line (into global -# variables) and return whether the start of a driver or not. - -($hide,$name,$rest) = $line =~ /^\s*(hide\s+|)([a-z0-9_]+)\s*(.*?)\s*$/; - -# If $rest begins with a colon, this is a driver name - -return "driver" if $rest =~ /^:/; - -# If $rest begins with an = the value of the option is given explicitly; -# remove the = from the start. Turn "yes"/"no" into "true"/"false". - -if ($rest =~ /^=/) - { - $rest =~ s/^=\s*//; - $rest = "true" if $rest eq "yes"; - $rest = "false" if $rest eq "no"; - } - -# Otherwise we have a boolean option. Set up a "true"/"false" value. - -else - { - if ($name =~ /^not?_/) # Recognize "no_" or "not_" - { - $rest = "false"; - $name =~ s/^not?_//; - } - else - { - $rest = "true"; - } - } - -return "option"; -} - - - -################################################## -# Negate a list of things # -################################################## - -# Can be tricky, because there may be comment lines in the list. -# Also, lists may have different delimiters. - -sub negate { -my($list) = $_[0]; -my($delim) = ":"; -my($leadin) = ""; - -return $list if ! defined $list; - -($list) = $list =~ /^"?(.*?)"?\s*$/s; # Remove surrounding quotes -$list =~ s/\\\s*\n\s*//g; # Remove continuation markers - -if ($list =~ /^(\s*<(\S)\s*)(.*)/s) - { - $leadin = $1; - $delim = $2; - $list = $3; - } - -$list =~ s/^\s+//; -$list =~ s/\Q$delim$delim/>%%%%%%%%%%%%%%%%%%%%%%%%); -$clen = scalar @c; - -# Remove the standard comment that appears at the end of the default - -if ($clen > 0 && $c[$clen-1] =~ /^#\s*End of Exim configuration file\s*/i) - { - pop @c; - $clen--; - } - -# The first pass over the input fishes out all the options settings in the -# main, transport, director, and router sections, and places their values in -# associative arrays. It also notes the starting position of all the sections. - -$prefix = ""; -%main = (); -$hash = \%main; - -for ($i = 0; $i < $clen; $i++) - { - # Change references to +allow_unknown and +warn_unknown into +include_unknown - - if ($c[$i] =~ /\+(?:allow|warn)_unknown/) - { - if (!$unk_output) - { - &rubric(); - print STDERR "\n" . -"** You have used '+allow_unknown' or '+warn_unknown' in a configuration\n" . -" option. This has been converted to '+include_unknown', but the action\n" . -" is different in Exim 4, so you should review all the relevant options.\n"; - $unk_output = 1; - } - $c[$i] =~ s/\+(?:allow|warn)_unknown/+include_unknown/g; - } - - # Any reference to $errmsg_recipient is changed to $bounce_recipient - - if ($c[$i] =~ /\$errmsg_recipient/) - { - if (!$errmsg_output) - { - &rubric(); - print STDERR "\n" . -"** References to \$errmsg_recipient have been changed to \$bounce_recipient\n"; - $errmsg_output = 1; - } - $c[$i] =~ s/\$errmsg_recipient/\$bounce_recipient/g; - } - - - # Analyse the type of line - - $type = &checkline($c[$i]); - next if $type eq "comment"; - - # Output a warning if $key is used - - if ($c[$i] =~ /\$key/ && !$key_output) - { - &rubric(); - print STDERR "\n" . -"** You have used '\$key' in a configuration option. This variable does not\n" . -" exist in Exim 4. Instead, the value you need for your lookup will be\n" . -" in one of the other variables such as '\$domain' or '\$host'. You will\n" . -" need to edit the new configuration to sort this out.\n"; - $key_output = 1; - } - - # Save macro definitions so we can output them first; must handle - # continuations. - - if ($type eq "macro") - { - $macro_output .= "$c[$i++]\n" while $c[$i] =~ /\\\s*$|^\s*#/; - $macro_output .= "$c[$i]\n"; - } - - # Handle end of section - - elsif ($type eq "end") - { - if ($prefix eq "=rewrite") - { - $prefix = "a."; - $auth_start = $i + 1; - last; - } - elsif ($prefix eq "=retry") - { - $prefix = "=rewrite"; - $rewrite_start = $i + 1; - } - elsif ($prefix eq "r.") - { - $prefix = "=retry"; - $retry_start = $i + 1; - } - elsif ($prefix eq "d.") - { - $prefix = "r."; - $router_start = $i + 1; - } - elsif ($prefix eq "t.") - { - $prefix = "d."; - $director_start = $i + 1; - } - elsif ($prefix eq "") - { - $prefix = "t."; - $transport_start = $i + 1; - } - } - - # Handle start of a new director, router or transport driver - - elsif ($type eq "driver" && $prefix !~ /^=/) - { - $hash = {}; - if (defined $driverlist{"$prefix$name"}) - { - die "*** There are two drivers with the name \"$name\"\n"; - } - $driverlist{"$prefix$name"} = $hash; - $first_director = $name if !defined $first_director && $prefix eq "d."; - } - - # Handle definition of an option; we must pull in any continuation - # strings, and save the value in the current hash. Note if the option - # is hidden. - - elsif ($type eq "option") - { - my($nextline) = ""; - - while ($i < $clen - 1 && ($rest =~ /\\\s*$/s || $nextline =~ /^\s*#/)) - { - $nextline = $c[++$i]; - $rest .= "\n$nextline"; - } - - $$hash{$name} = $rest; - $$hash{"$name-hide"} = 1 if $hide ne ""; - } - } - - -# Generate the new configuration. Start with a warning rubric. - -print STDOUT "#!!# This file is output from the convert4r4 script, which tries\n"; -print STDOUT "#!!# to convert Exim 3 configurations into Exim 4 configurations.\n"; -print STDOUT "#!!# However, it is not perfect, especially with non-simple\n"; -print STDOUT "#!!# configurations. You must check it before running it.\n"; -print STDOUT "\n\n"; - -# Output the macro definitions - -if ($macro_output ne "") - { - print STDOUT "#!!# All macro definitions have been gathered here to ensure\n"; - print STDOUT "#!!# they precede any references to them.\n\n"; - print STDOUT "$macro_output\n"; - } - -# Output some default pointers to ACLs for RCPT and DATA time. If no Exim 3 -# options that apply are set, non-restricting ACLs are generated. - -print STDOUT "#!!# These options specify the Access Control Lists (ACLs) that\n"; -print STDOUT "#!!# are used for incoming SMTP messages - after the RCPT and DATA\n"; -print STDOUT "#!!# commands, respectively.\n\n"; - -print STDOUT "acl_smtp_rcpt = check_recipient\n"; -print STDOUT "acl_smtp_data = check_message\n\n"; - -if (defined $main{"auth_over_tls_hosts"}) - { - print STDOUT "#!!# This option specifies the Access Control List (ACL) that\n"; - print STDOUT "#!!# is used after an AUTH command.\n\n"; - print STDOUT "acl_smtp_auth = check_auth\n\n"; - } - -if (&bool("smtp_verify") || - defined $main{"smtp_etrn_hosts"} || - defined $main{"smtp_expn_hosts"}) - { - print STDOUT "#!!# These options specify the Access Control Lists (ACLs) that\n"; - print STDOUT "#!!# are used to control the ETRN, EXPN, and VRFY commands.\n"; - print STDOUT "#!!# Where no ACL is defined, the command is locked out.\n\n"; - - print STDOUT "acl_smtp_etrn = check_etrn\n" if defined $main{"smtp_etrn_hosts"}; - print STDOUT "acl_smtp_expn = check_expn\n" if defined $main{"smtp_expn_hosts"}; - print STDOUT "acl_smtp_vrfy = check_vrfy\n" if &bool("smtp_verify"); - print STDOUT "\n"; - } - -# If local_domains was set, get its value; otherwise set to "@". Add into it -# appropriate magic for local_domains_include_host[_literals]. - -$local_domains = (defined $main{"local_domains"})? $main{"local_domains"} : "@"; - -$ldsep = ":"; -if ($local_domains =~ /^\s*<(.)\s*(.*)/s) - { - $ldsep = $1; - $local_domains = $2; - } - -$local_domains = "\@[] $ldsep " . $local_domains - if defined $main{"local_domains_include_host_literals"} && - $main{"local_domains_include_host_literals"} eq "true"; - -$local_domains = "\@ $ldsep " . $local_domains - if defined $main{"local_domains_include_host"} && - $main{"local_domains_include_host"} eq "true"; - -$local_domains = "<$ldsep " . $local_domains if $ldsep ne ":"; - -# Output a domain list setting for these domains, provided something is defined - -if ($local_domains !~ /^\s*$/) - { - print STDOUT "#!!# This setting defines a named domain list called\n"; - print STDOUT "#!!# local_domains, created from the old options that\n"; - print STDOUT "#!!# referred to local domains. It will be referenced\n"; - print STDOUT "#!!# later on by the syntax \"+local_domains\".\n"; - print STDOUT "#!!# Other domain and host lists may follow.\n\n"; - - printf STDOUT ("domainlist local_domains = %s\n\n", - &no_expand_regex($local_domains)); - } - -$relay_domains = (defined $main{"relay_domains"})? $main{"relay_domains"} : ""; - -$ldsep = ":"; -if ($relay_domains =~ /^\s*<(.)\s*(.*)/s) - { - $ldsep = $1; - } - -if (defined $main{"relay_domains_include_local_mx"}) - { - $relay_domains .= ($relay_domains =~ /^\s*$/)? "\@mx_any" : - " $ldsep \@mx_any"; - } - -printf STDOUT ("domainlist relay_domains = %s\n", - &no_expand_regex($relay_domains)) - if $relay_domains !~ /^\s*$/; - - -# If ignore_errmsg_errors is set, we are going to force 0s as the value -# for ignore_errmsg_errors_after, so arrange to skip any other value. - -push @skipped_options, "ignore_errmsg_errors_after" - if &bool("ignore_errmsg_errors"); - - -# If rbl_domains is set, split it up and generate six lists: -# rbl_warn_domains, rbl_warn_domains_skiprelay -# rbl_reject_domains, rbl_reject_domains_skiprelay -# rbl_accept_domains, rbl_accept_domains_skiprelay - -if (defined $main{"rbl_domains"}) - { - my($s) = &unquote($main{"rbl_domains"}); - $s =~ s/\s*\\\s*\n\s*/ /g; - my(@list) = split /\s*:\s*/, $s; - - foreach $d (@list) - { - my(@sublist) = split /\//, $d; - my($name) = shift @sublist; - my($warn) = 0; - if (defined $main{"rbl_reject_recipients"}) - { - $warn = $main{"rbl_reject_recipients"} ne "true"; - } - - foreach $o (@sublist) - { - $warn = 1 if $o eq "warn"; - $warn = 0 if $o eq "reject"; - $warn = 2 if $o eq "accept"; - $skiprelay = 1 if $o eq "skiprelay"; - } - - if ($skiprelay) - { - if ($warn == 0) - { - $rbl_reject_skiprelay .= ((defined $rbl_reject_skiprelay)? ":":"").$name; - } - elsif ($warn == 1) - { - $rbl_warn_skiprelay .= ((defined $rbl_warn_skiprelay)? ":":"").$name; - } - elsif ($warn == 2) - { - $rbl_accept_skiprelay .= ((defined $rbl_accept_skiprelay)? ":":"").$name; - } - } - else - { - if ($warn == 0) - { - $rbl_reject_domains .= ((defined $rbl_reject_domains)? ":":"").$name; - } - elsif ($warn == 1) - { - $rbl_warn_domains .= ((defined $rbl_warn_domains)? ":":"").$name; - } - elsif ($warn == 2) - { - $rbl_accept_domains .= ((defined $rbl_accept_domains)? ":":"").$name; - } - } - } - } - - -# Output host list settings - -printf STDOUT ("hostlist auth_hosts = %s\n", - &no_expand_regex($main{"auth_hosts"})) - if defined $main{"auth_hosts"}; -printf STDOUT ("hostlist rbl_hosts = %s\n", - &no_expand_regex($main{"rbl_hosts"})) - if defined $main{"rbl_hosts"}; -printf STDOUT ("hostlist relay_hosts = %s\n", - &no_expand_regex($main{"host_accept_relay"})) - if defined $main{"host_accept_relay"}; -printf STDOUT ("hostlist auth_relay_hosts = %s\n", - &no_expand_regex($main{"host_auth_accept_relay"})) - if defined $main{"host_auth_accept_relay"}; - -printf STDOUT ("hostlist auth_over_tls_hosts = %s\n", - &no_expand_regex($main{"auth_over_tls_hosts"})) - if defined $main{"auth_over_tls_hosts"}; -printf STDOUT ("hostlist tls_hosts = %s\n", - &no_expand_regex($main{"tls_hosts"})) - if defined $main{"tls_hosts"}; -printf STDOUT ("hostlist tls_relay_hosts = %s\n", - &no_expand_regex($main{"tls_host_accept_relay"})) - if defined $main{"tls_host_accept_relay"}; - -print STDOUT "\n"; - - -# Convert various logging options - -$log_selector = ""; -$sep = " \\\n "; - -if (defined $main{"log_level"}) - { - my($level) = $main{"log_level"}; - $log_selector .= "$sep -retry_defer$sep -skip_delivery" if $level < 5; - $log_selector .= "$sep -lost_incoming_connection$sep -smtp_syntax_error" . - "$sep -delay_delivery" if $level < 4; - $log_selector .= "$sep -size_reject" if $level < 2; - } - -$log_selector .= "$sep -queue_run" - if defined $main{"log_queue_run_level"} && - defined $main{"log_level"} && - $main{"log_queue_run_level"} > $main{"log_level"}; - -$log_selector .= "$sep +address_rewrite" if &bool("log_rewrites"); -$log_selector .= "$sep +all_parents" if &bool("log_all_parents"); -$log_selector .= "$sep +arguments" if &bool("log_arguments"); -$log_selector .= "$sep +incoming_port" if &bool("log_incoming_port"); -$log_selector .= "$sep +incoming_interface" if &bool("log_interface"); -$log_selector .= "$sep +received_sender" if &bool("log_received_sender"); -$log_selector .= "$sep +received_recipients" if &bool("log_received_recipients"); -$log_selector .= "$sep +sender_on_delivery" if &bool("log_sender_on_delivery"); -$log_selector .= "$sep +smtp_confirmation" if &bool("log_smtp_confirmation"); -$log_selector .= "$sep +smtp_connection" if &bool("log_smtp_connections"); -$log_selector .= "$sep +smtp_syntax_error" if &bool("log_smtp_syntax_errors"); -$log_selector .= "$sep +subject" if &bool("log_subject"); -$log_selector .= "$sep +tls_cipher" if &bool("tls_log_cipher"); -$log_selector .= "$sep +tls_peerdn" if &bool("tls_log_peerdn"); - - -if ($log_selector ne "") - { - print STDOUT "#!!# All previous logging options are combined into a single\n" - . "#!!# option in Exim 4. This setting is an approximation to\n" - . "#!!# the previous state - some logging has changed.\n\n"; - print STDOUT "log_selector = $log_selector\n\n"; - } - -# If deliver_load_max is set, replace it with queue_only_load (taking the -# lower value if both set) and also set deliver_queue_load_max if it is -# not already set. When scanning for output, deliver_load_max is skipped. - -if (defined $main{"deliver_load_max"}) - { - &rubric(); - print STDERR "\n" . -"** deliver_load_max is abolished in Exim 4.\n"; - - if (defined $main{"queue_only_load"}) - { - $queue_only_load_was_present = 1; - if ($main{"queue_only_load"} < $main{"deliver_load_max"}) - { - print STDERR -" As queue_only_load was set lower, deliver_load_max is just removed.\n"; - } - else - { - print STDERR -" As queue_only_load was set higher, it's value has been replaced by\n" . -" the value of deliver_load_max.\n"; - $main{"queue_only_load"} = $main{"deliver_load_max"}; - } - } - else - { - print STDERR -" queue_only_load has been set to the load value.\n"; - $main{"queue_only_load"} = $main{"deliver_load_max"}; - } - - if (!defined $main{"deliver_queue_load_max"}) - { - print STDERR -" deliver_queue_load_max has been set to the value of queue_only_load.\n"; - $main{"deliver_queue_load_max"} = $main{"queue_only_load"}; - } - else - { - $deliver_queue_load_max_was_present = 1; - } - } - - -# Now we scan through the various parts of the file again, making changes -# as necessary. - -# -------- The main configuration -------- - -$prefix = ""; -MainLine: for ($i = 0; $i < $clen; $i++) - { - my($nextline) = ""; - $type = &checkline($c[$i]); - last if $type eq "end"; - - if ($type eq "macro") - { - $i++ while $c[$i] =~ /\\\s*$|^\s*#/; - next; - } - - if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; } - - # Collect any continuation lines for an option setting - - while ($rest =~ /\\\s*$/s || $nextline =~ /^\s*#/) - { - $nextline = $c[++$i]; - $rest .= "\n$nextline"; - } - - $rest =~ s/^=\s*//; - - # Deal with main options that are skipped (they are used in other - # options in other places). - - for $skipped (@skipped_options) - { - next MainLine if $name eq $skipped; - } - - # Deal with main options that are totally abolished - - for $abolished (@abolished_options) - { - if ($name eq $abolished) - { - &rubric(); - print STDERR "\n" . -"** The $name option no longer exists, and has no equivalent\n" . -" in Exim 4.\n"; - next MainLine; - } - } - - # There is a special case for rbl_warn_header - - if ($name eq "rbl_warn_header") - { - &rubric(); - print STDERR "\n" . -"** The $name option no longer exists. In Exim 4 you can achieve the\n" . -" effect by adding a suitable \"message\" statement in the ACL.\n"; - } - - # There is a special case for sender_reject and host_reject - - elsif ($name eq "sender_reject" || $name eq "host_reject") - { - &rubric(); - print STDERR "\n" . -"** The $name option no longer exists. Its data has been used in\n" . -" an Access Control List as if it were in ${name}_recipients.\n"; - } - - # And a special message for prohibition_message - - elsif ($name eq "prohibition_message") - { - &rubric(); - print STDERR "\n" . -"** The prohibition_message option no longer exists. The facility is\n" . -" provided in a different way in Exim 4, via the \"message\" keyword\n" . -" in Access Control Lists. It isn't possible to do an automatic conversion,\n" . -" so the value of prohibition_message has been ignored. You will have to\n" . -" modify the ACLs if you want to reinstate the feature.\n"; - } - - # auth_always_advertise gets converted to auth_advertise_hosts - - elsif ($name eq "auth_always_advertise") - { - print STDOUT "#!!# auth_always_advertise converted to auth_advertise_hosts\n"; - if (&bool("auth_always_advertise")) - { - print STDOUT "auth_advertise_hosts = *\n"; - } - else - { - $sep = ""; - print STDOUT "auth_advertise_hosts ="; - if (defined $main{"auth_hosts"}) - { - print STDOUT "$sep +auth_hosts"; - $sep = " :"; - } - if (defined $main{"host_accept_relay"}) - { - print STDOUT "$sep !+relay_hosts"; - $sep = " :"; - } - if (defined $main{"host_auth_accept_relay"}) - { - print STDOUT "$sep +auth_relay_hosts"; - } - print STDOUT "\n"; - } - } - - # Deal with main options that have to be rewritten - - elsif ($name eq "accept_timeout") - { - print STDOUT "#!!# accept_timeout renamed receive_timeout\n"; - print STDOUT "receive_timeout = $rest\n"; - } - - elsif ($name eq "collapse_source_routes") - { - print STDOUT "#!!# collapse_source_routes removed\n"; - print STDOUT "#!!# It has been a no-op since 3.10.\n"; - } - - elsif ($name eq "daemon_smtp_service") - { - print STDOUT "#!!# daemon_smtp_service renamed daemon_smtp_port\n"; - print STDOUT "daemon_smtp_port = $rest\n"; - } - - elsif ($name eq "dns_check_names" || $name eq "dns_check_names_pattern") - { - if (!$done_dns_check_names) - { - if (&bool("dns_check_names")) - { - if (defined $main{"dns_check_names_pattern"}) - { - &outopt(\%main, "dns_check_names_pattern", 0); - } - } - - else - { - print STDOUT "#!!# dns_check_names has been abolished\n"; - print STDOUT "#!!# setting dns_check_pattern empty to turn off check\n"; - print STDOUT "dns_check_names_pattern =\n"; - } - - $done_dns_check_names = 1; - } - } - - elsif ($name eq "deliver_load_max") - { - print STDOUT "deliver_queue_load_max = $main{'deliver_queue_load_max'}\n" - if !$deliver_queue_load_max_was_present; - print STDOUT "queue_only_load = $main{'queue_only_load'}\n" - if !$queue_only_load_was_present; - } - - elsif ($name eq "errmsg_file") - { - print STDOUT "#!!# errmsg_file renamed bounce_message_file\n"; - print STDOUT "bounce_message_file = $rest\n"; - } - - elsif ($name eq "errmsg_text") - { - print STDOUT "#!!# errmsg_text renamed bounce_message_text\n"; - print STDOUT "bounce_message_text = $rest\n"; - } - - elsif ($name eq "forbid_domain_literals") - { - print STDOUT "#!!# forbid_domain_literals replaced by allow_domain_literals\n"; - print STDOUT "allow_domain_literals = ", - &bool("forbid_domain_literals")? "false" : "true", "\n"; - } - - elsif ($name eq "freeze_tell_mailmaster") - { - print STDOUT "#!!# freeze_tell_mailmaster replaced by freeze_tell\n"; - if (&bool("freeze_tell_mailmaster")) - { - print STDOUT "freeze_tell = ", - ((defined $main{"errors_address"})? - $main{"errors_address"} : "postmaster"), "\n"; - } - else - { - print STDOUT "#!!# freeze_tell is unset by default\n"; - } - } - - elsif ($name eq "helo_verify") - { - print STDOUT "#!!# helo_verify renamed helo_verify_hosts\n"; - printf STDOUT ("helo_verify_hosts = %s\n", &no_expand_regex($rest)); - } - - elsif ($name eq "ignore_errmsg_errors") - { - print STDOUT "ignore_bounce_errors_after = 0s\n"; - } - - elsif ($name eq "ignore_errmsg_errors_after") - { - print STDOUT "#!!# ignore_errmsg_errors_after renamed ignore_bounce_errors_after\n"; - print STDOUT "ignore_bounce_errors_after = $rest\n"; - } - - elsif ($name eq "ipv4_address_lookup" || $name eq "dns_ipv4_lookup") - { - print STDOUT "#!!# $name changed to dns_ipv4_lookup\n" - if $name eq "ipv4_address_lookup"; - print STDOUT "#!!# dns_ipv4_lookup is now a domain list\n"; - if (&bool($name)) - { - print STDOUT "dns_ipv4_lookup = *\n"; - } - else - { - print STDOUT "#!!# default for dns_ipv4_lookup is unset\n"; - } - } - - elsif ($name eq "locally_caseless") - { - print STDOUT "#!!# locally_caseless removed\n"; - print STDOUT "#!!# caseful_local_part will be added to ex-directors\n"; - $add_caseful_local_part = 1; - } - - elsif ($name eq "message_filter_directory2_transport") - { - print STDOUT "#!!# message_filter_directory2_transport removed\n"; - } - - elsif ($name =~ /^message_filter(.*)/) - { - print STDOUT "#!!# $name renamed system_filter$1\n"; - print STDOUT "system_filter$1 = $rest\n"; - } - - elsif ($name eq "queue_remote_domains") - { - print STDOUT "#!!# queue_remote_domains renamed queue_domains\n"; - printf STDOUT ("queue_domains = %s\n", &no_expand_regex($rest)); - } - - elsif ($name eq "receiver_unqualified_hosts") - { - print STDOUT "#!!# receiver_unqualified_hosts renamed recipient_unqualified_hosts\n"; - printf STDOUT ("recipient_unqualified_hosts = %s\n", - &no_expand_regex($rest)); - } - - elsif ($name eq "remote_sort") - { - print STDOUT "#!!# remote_sort renamed remote_sort_domains\n"; - printf STDOUT ("remote_sort_domains = %s\n", &no_expand_regex($rest)); - } - - elsif ($name eq "security") - { - if ($rest eq "unprivileged") - { - print STDOUT "#!!# security=unprivileged changed to deliver_drop_privilege\n"; - print STDOUT "deliver_drop_privilege\n"; - } - else - { - &rubric(); - print STDERR "\n" . -"** The 'security' option no longer exists.\n"; - } - } - - elsif ($name eq "timestamps_utc") - { - print STDOUT "#!!# timestamps_utc changed to use timezone\n"; - print STDOUT "timezone = utc\n"; - } - - elsif ($name eq "untrusted_set_sender") - { - print STDOUT "#!!# untrusted_set_sender is now a list of what can be set\n"; - print STDOUT "#!!# The default is an empty list.\n"; - if (&bool("untrusted_set_sender")) - { - print STDOUT "untrusted_set_sender = *\n"; - } - } - - elsif ($name eq "warnmsg_file") - { - print STDOUT "#!!# warnmsg_file renamed warn_message_file\n"; - print STDOUT "warn_message_file = $rest\n"; - } - - # Remaining options just get copied unless they are one of those that's - # a list where any regular expressions have to be escaped. - - else - { - my($no_expand) = 0; - foreach $o (@list_options) - { - if ($name eq $o) - { - $no_expand = 1; - last; - } - } - &outopt(\%main, $name, $no_expand); - } - } - - -# -------- The ACL configuration -------- - -print STDOUT "\n"; -print STDOUT "#!!#######################################################!!#\n"; -print STDOUT "#!!# This new section of the configuration contains ACLs #!!#\n"; -print STDOUT "#!!# (Access Control Lists) derived from the Exim 3 #!!#\n"; -print STDOUT "#!!# policy control options. #!!#\n"; -print STDOUT "#!!#######################################################!!#\n"; - -print STDOUT "\n"; -print STDOUT "#!!# These ACLs are crudely constructed from Exim 3 options.\n"; -print STDOUT "#!!# They are almost certainly not optimal. You should study\n"; -print STDOUT "#!!# them and rewrite as necessary.\n"; - -print STDOUT "\nbegin acl\n\n"; - - -# Output an ACL for use after the RCPT command. This combines all the previous -# policy checking options. - -print STDOUT "#!!# ACL that is used after the RCPT command\n"; -print STDOUT "check_recipient:\n"; - -print STDOUT " # Exim 3 had no checking on -bs messages, so for compatibility\n"; -print STDOUT " # we accept if the source is local SMTP (i.e. not over TCP/IP).\n"; -print STDOUT " # We do this by testing for an empty sending host field.\n"; -print STDOUT " accept hosts = :\n"; - -if (defined $main{"tls_verify_ciphers"}) - { - print STDOUT " deny "; - print STDOUT "hosts = $main{'tls_verify_hosts'}\n " - if defined $main{"tls_verify_hosts"}; - print STDOUT " encrypted = *\n "; - print STDOUT "!encrypted = $main{'tls_verify_ciphers'}\n"; - } - -print STDOUT " deny hosts = +auth_hosts\n" . - " message = authentication required\n" . - " !authenticated = *\n" - if defined $main{"auth_hosts"}; - -print STDOUT " deny hosts = +tls_hosts\n" . - " message = encryption required\n" . - " !encrypted = *\n" - if defined $main{"tls_hosts"}; - -printf STDOUT (" accept recipients = %s\n", - &acl_quote(&sort_address_list($main{"recipients_reject_except"}, - "recipients_reject_except"))) - if defined $main{"recipients_reject_except"}; - -printf STDOUT (" accept senders = %s\n", - &acl_quote(&sort_address_list($main{"recipients_reject_except_senders"}, - "recipients_reject_except_senders"))) - if defined $main{"recipients_reject_except_senders"}; - -printf STDOUT (" deny hosts = %s\n", &acl_quote($main{"host_reject"})) - if defined $main{"host_reject"}; - -printf STDOUT (" deny hosts = %s\n", - &acl_quote($main{"host_reject_recipients"})) - if defined $main{"host_reject_recipients"}; - -if (defined $main{"rbl_domains"}) - { - my($msg) = "message = host is listed in \$dnslist_domain\n "; - my($hlist) = (defined $main{"rbl_hosts"})? - "hosts = +rbl_hosts\n " : ""; - - print STDOUT " accept ${hlist}dnslists = $rbl_accept_domains\n" - if defined $rbl_accept_domains; - print STDOUT " deny ${hlist}${msg}dnslists = $rbl_reject_domains\n" - if defined $rbl_reject_domains; - print STDOUT " warn ${hlist}" . - "message = X-Warning: \$sender_host_address is listed at \$dnslist_domain\n" . - " dnslists = $rbl_warn_domains\n" - if defined $rbl_warn_domains; - - if (defined $main{"host_accept_relay"}) - { - $hlist .= "hosts = !+relay_hosts\n "; - print STDOUT " accept ${hlist}dnslists = $rbl_accept_skiprelay\n" - if defined $rbl_accept_skiprelay; - print STDOUT " deny ${hlist}${msg}dnslists = $rbl_reject_skiprelay\n" - if defined $rbl_reject_skiprelay; - print STDOUT " warn ${hlist}" . - "message = X-Warning: \$sender_host_address is listed at \$dnslist_domain\n" . - " dnslists = $rbl_warn_skiprelay\n" - if defined $rbl_warn_skiprelay; - } - } - -printf STDOUT (" deny senders = %s\n", - &acl_quote(&sort_address_list($main{"sender_reject"}, "sender_reject"))) - if defined $main{"sender_reject"}; - -printf STDOUT (" deny senders = %s\n", - &acl_quote(&sort_address_list($main{"sender_reject_recipients"}, - "sender_reject_recipients"))) - if defined $main{"sender_reject_recipients"}; - -if (&bool("sender_verify")) - { - if (defined $main{"sender_verify_hosts_callback"} && - defined $main{"sender_verify_callback_domains"}) - { - printf STDOUT (" deny hosts = %s\n", - &acl_quote($main{"sender_verify_hosts_callback"})); - printf STDOUT (" sender_domains = %s\n", - &acl_quote($main{"sender_verify_callback_domains"})); - print STDOUT " !verify = sender/callout"; - print STDOUT "=$main{\"sender_verify_callback_timeout\"}" - if defined $main{"sender_verify_callback_timeout"}; - print STDOUT "\n"; - } - - if (defined $main{"sender_verify_hosts"}) - { - printf STDOUT (" deny hosts = %s\n", - &acl_quote($main{"sender_verify_hosts"})); - print STDOUT " !verify = sender\n"; - } - else - { - print STDOUT " require verify = sender\n"; - } - } - -if (&bool("receiver_verify")) - { - print STDOUT " deny message = unrouteable address\n"; - printf STDOUT (" recipients = %s\n", - &acl_quote(&sort_address_list($main{"receiver_verify_addresses"}, - "receiver_verify_addresses"))) - if defined $main{"receiver_verify_addresses"}; - printf STDOUT (" hosts = %s\n", - &acl_quote($main{"receiver_verify_hosts"})) - if defined $main{"receiver_verify_hosts"}; - printf STDOUT (" senders = %s\n", - &acl_quote(&sort_address_list($main{"receiver_verify_senders"}, - "receiver_verify_senders"))) - if defined $main{"receiver_verify_senders"}; - print STDOUT " !verify = recipient\n"; - } - -print STDOUT " accept domains = +local_domains\n" - if $local_domains !~ /^\s*$/; - -print STDOUT " accept domains = +relay_domains\n" - if $relay_domains !~ /^\s*$/; - -if (defined $main{"host_accept_relay"}) - { - if (defined $main{"sender_address_relay"}) - { - if (defined $main{"sender_address_relay_hosts"}) - { - printf STDOUT (" accept hosts = %s\n", - &acl_quote($main{"sender_address_relay_hosts"})); - print STDOUT " endpass\n"; - print STDOUT " message = invalid sender\n"; - printf STDOUT (" senders = %s\n", - &acl_quote(&sort_address_list($main{"sender_address_relay"}, - "sender_address_relay"))); - print STDOUT " accept hosts = +relay_hosts\n"; - } - else - { - print STDOUT " accept hosts = +relay_hosts\n"; - print STDOUT " endpass\n"; - print STDOUT " message = invalid sender\n"; - printf STDOUT (" senders = %s\n", - &acl_quote(&sort_address_list($main{"sender_address_relay"}, - "sender_address_relay"))); - } - } - else - { - print STDOUT " accept hosts = +relay_hosts\n"; - } - } - -print STDOUT " accept hosts = +auth_relay_hosts\n" . - " endpass\n" . - " message = authentication required\n" . - " authenticated = *\n" - if defined $main{"host_auth_accept_relay"}; - -print STDOUT " accept hosts = +tls_relay_hosts\n" . - " endpass\n" . - " message = encryption required\n" . - " encrypted = *\n" - if defined $main{"tls_host_accept_relay"}; - -print STDOUT " deny message = relay not permitted\n\n"; - - -# Output an ACL for use after the DATA command. This is concerned with -# header checking. - -print STDOUT "#!!# ACL that is used after the DATA command\n"; -print STDOUT "check_message:\n"; - -# Default for headers_checks_fail is true - -if (!defined $main{"headers_checks_fail"} || - $main{"headers_checks_fail"} eq "true") - { - print STDOUT " require verify = header_syntax\n" - if &bool("headers_check_syntax"); - print STDOUT " require verify = header_sender\n" - if &bool("headers_sender_verify"); - print STDOUT " accept senders = !:\n require verify = header_sender\n" - if &bool("headers_sender_verify_errmsg"); - } -else - { - print STDOUT " warn !verify = header_syntax\n" - if &bool("headers_check_syntax"); - print STDOUT " warn !verify = header_sender\n" - if &bool("headers_sender_verify"); - print STDOUT " accept senders = !:\n warn !verify = header_sender\n" - if &bool("headers_sender_verify_errmsg"); - } - -print STDOUT " accept\n\n"; - - -# Output an ACL for AUTH if required - -if (defined $main{"auth_over_tls_hosts"}) - { - print STDOUT "#!!# ACL that is used after the AUTH command\n" . - "check_auth:\n" . - " accept hosts = +auth_over_tls_hosts\n" . - " endpass\n" . - " message = STARTTLS required before AUTH\n" . - " encrypted = *\n" . - " accept\n"; - } - - -# Output ACLs for ETRN, EXPN, and VRFY if required - -if (defined $main{"smtp_etrn_hosts"}) - { - print STDOUT "#!!# ACL that is used after the ETRN command\n" . - "check_etrn:\n"; - print STDOUT " deny hosts = +auth_hosts\n" . - " message = authentication required\n" . - " !authenticated = *\n" - if defined $main{"auth_hosts"}; - print STDOUT " accept hosts = $main{\"smtp_etrn_hosts\"}\n\n"; - } - -if (defined $main{"smtp_expn_hosts"}) - { - print STDOUT "#!!# ACL that is used after the EXPN command\n" . - "check_expn:\n"; - print STDOUT " deny hosts = +auth_hosts\n" . - " message = authentication required\n" . - " !authenticated = *\n" - if defined $main{"auth_hosts"}; - print STDOUT " accept hosts = $main{\"smtp_expn_hosts\"}\n\n"; - } - -if (&bool("smtp_verify")) - { - print STDOUT "#!!# ACL that is used after the VRFY command\n" . - "check_vrfy:\n"; - print STDOUT " deny hosts = +auth_hosts\n" . - " message = authentication required\n" . - " !authenticated = *\n" - if defined $main{"auth_hosts"}; - print STDOUT " accept\n\n"; - } - -# -------- The authenticators -------- - -$started = 0; -for ($i = $auth_start; $i < $clen; $i++) - { - if (!$started) - { - if ($c[$i] !~ /^\s*(#|$)/) - { - print STDOUT "\nbegin authenticators\n\n"; - $started = 1; - } - } - print STDOUT "$c[$i]\n"; - } - - -# -------- Rewrite section -------- - -$started = 0; -for ($i = $rewrite_start; $i < $clen && $i < $auth_start - 1; $i++) - { - if (!$started) - { - if ($c[$i] !~ /^\s*(#|$)/) - { - print STDOUT "\nbegin rewrite\n\n"; - $started = 1; - } - } - &print_no_expand($c[$i]); - } - - -# -------- The routers configuration -------- - -# The new routers configuration is created out of the old directors and routers -# configuration. We put the old routers first, adding a "domains" option to -# any that don't have one, to make them select the domains that do not match -# the original local_domains. The routers get modified as necessary, and the -# final one has "no_more" set, unless it has conditions. In that case we have -# to add an extra router to be sure of failing all non-local addresses that -# fall through. We do this also if there are no routers at all. The old -# directors follow, modified as required. - -$prefix = "r."; -undef @comments; - -print STDOUT "\n"; -print STDOUT "#!!#######################################################!!#\n"; -print STDOUT "#!!# Here follow routers created from the old routers, #!!#\n"; -print STDOUT "#!!# for handling non-local domains. #!!#\n"; -print STDOUT "#!!#######################################################!!#\n"; - -print STDOUT "\nbegin routers\n\n"; - -for ($i = $router_start; $i < $clen; $i++) - { - $type = &checkline($c[$i]); - last if $type eq "end"; - - if ($type eq "comment") { push(@comments, "$c[$i]\n"); next; } - - # When we hit the start of a driver, modify its options as necessary, - # and then output it from the stored option settings, having first output - # and previous comments. - - if ($type eq "driver") - { - print STDOUT shift @comments while scalar(@comments) > 0; - - $hash = $driverlist{"$prefix$name"}; - $driver = $$hash{"driver"}; - print STDOUT "$name:\n"; - - $add_no_more = - ! defined $$hash{"domains"} && - ! defined $$hash{"local_parts"} && - ! defined $$hash{"senders"} && - ! defined $$hash{"condition"} && - ! defined $$hash{"require_files"} && - (!defined $$hash{"verify_only"} || $$hash{"verify_only"} eq "false") && - (!defined $$hash{"verify"} || $$hash{"verify"} eq "true"); - - # Create a "domains" setting if there isn't one, unless local domains - # was explicitly empty. - - $$hash{"domains"} = "! +local_domains" - if !defined $$hash{"domains"} && $local_domains !~ /^\s*$/; - - # If the router had a local_parts setting, add caseful_local_part - - $$hash{"caseful_local_part"} = "true" if defined $$hash{"local_parts"}; - - # If the router has "self=local" set, change it to "self=pass", and - # set pass_router to the router that was the first director. Change the - # obsolete self settings of "fail_hard" and "fail_soft" to "fail" and - # "pass". - - if (defined $$hash{"self"}) - { - if ($$hash{"self"} eq "local") - { - $$hash{"self"} = "pass"; - $$hash{"pass_router"} = $first_director; - } - elsif ($$hash{"self"} eq "fail_hard") - { - $$hash{"self"} = "fail"; - } - elsif ($$hash{"self"} eq "fail_soft") - { - $$hash{"self"} = "pass"; - } - } - - # If the router had a require_files setting, check it for user names - # and colons that are part of expansion items - - if (defined $$hash{"require_files"}) - { - &check_require($$hash{"require_files"}, "'$name' router"); - if (($$hash{"require_files"} =~ s/(\$\{\w+):/$1::/g) > 0 || - ($$hash{"require_files"} =~ s/ldap:/ldap::/g) > 0) - { - &rubric(); - print STDERR "\n" . -"*** A setting of require_files in the $name router contains\n" . -" a colon in what appears to be an expansion item. In Exim 3, the\n" . -" whole string was expanded before splitting the list, but in Exim 4\n" . -" each item is expanded separately, so colons that are not list\n" . -" item separators have to be doubled. One or more such colons in this\n" . -" list have been doubled as a precaution. Please check the result.\n"; - } - } - - # If the router had a "senders" setting, munge the address list - - $$hash{"senders"} = &sort_address_list($$hash{"senders"}, "senders") - if defined $$hash{"senders"}; - - # ---- Changes to domainlist router ---- - - if ($driver eq "domainlist") - { - &abolished($hash, "A domainlist router", - "modemask", "owners", "owngroups", - "qualify_single", "search_parents"); - - # The name has changed - - $$hash{"driver"} = "manualroute"; - - # Turn "route_file", "route_query" and "route_queries" into lookups for - # route_data. - - if (defined $$hash{"route_file"}) - { - $$hash{"route_data"} = "\${lookup\{\$domain\}$$hash{'search_type'}" . - "\{$$hash{'route_file'}\}\}"; - } - elsif (defined $$hash{"route_query"}) - { - $$hash{"route_data"} = "\${lookup $$hash{'search_type'}" . - "\{" . &unquote($$hash{'route_query'}) . "\}\}"; - } - elsif (defined $$hash{"route_queries"}) - { - $endkets = 0; - $$hash{"route_data"} = ""; - $route_queries = $$hash{'route_queries'}; - $route_queries =~ s/^"(.*)"$/$1/s; - $route_queries =~ s/::/++colons++/g; - @qq = split(/:/, $route_queries); - - foreach $q (@qq) - { - $q =~ s/\+\+colons\+\+/:/g; - $q =~ s/^\s+//; - $q =~ s/\s+$//; - if ($endkets > 0) - { - $$hash{"route_data"} .= "\\\n {"; - $endkets++; - } - $$hash{"route_data"} .= "\${lookup $$hash{'search_type'} \{$q\}\{\$value\}"; - $endkets++; - } - - $$hash{"route_data"} .= "}" x $endkets; - } - - delete $$hash{"route_file"}; - delete $$hash{"route_query"}; - delete $$hash{"route_queries"}; - delete $$hash{"search_type"}; - - # But we can't allow both route_data and route_list - - if (defined $$hash{"route_data"} && defined $$hash{"route_list"}) - { - &rubric(); - print STDERR "\n" . -"** An Exim 3 'domainlist' router called '$name' contained a 'route_list'\n" . -" option as well as a setting of 'route_file', 'route_query', or\n" . -" 'route_queries'. The latter has been turned into a 'route_data' setting,\n". -" but in Exim 4 you can't have both 'route_data' and 'route_list'. You'll\n" . -" have to rewrite this router; in the meantime, 'route_list' has been\n" . -" omitted.\n"; - print STDOUT "#!!# route_list option removed\n"; - delete $$hash{"route_list"}; - } - - # Change bydns_a into bydns in a route_list; also bydns_mx, but that - # works differently. - - if (defined $$hash{"route_list"}) - { - $$hash{"route_list"} =~ s/bydns_a/bydns/g; - if ($$hash{"route_list"} =~ /bydns_mx/) - { - $$hash{"route_list"} =~ s/bydns_mx/bydns/g; - &rubric(); - print STDERR "\n" . -"*** An Exim 3 'domainlist' router called '$name' contained a 'route_list'\n" . -" option which used 'bydns_mx'. This feature no longer exists in Exim 4.\n" . -" It has been changed to 'bydns', but it won't have the same effect,\n" . -" because it will look for A rather than MX records. Use the 'dnslookup'\n" . -" router to do MX lookups - if you want to override the hosts found from\n" . -" MX records, you should route to a special 'smtp' transport which has\n" . -" both 'hosts' and 'hosts_override' set.\n"; - } - } - - # Arrange to not expand regex - - $$hash{"route_list"} = &no_expand_regex($$hash{"route_list"}, ";") - if (defined $$hash{"route_list"}) - } - - - # ---- Changes to iplookup router ---- - - elsif ($driver eq "iplookup") - { - &renamed($hash, "service", "port"); - } - - - # ---- Changes to lookuphost router ---- - - elsif ($driver eq "lookuphost") - { - $$hash{"driver"} = "dnslookup"; - - if (defined $$hash{"gethostbyname"}) - { - &rubric(); - print STDERR "\n" . -"** An Exim 3 'lookuphost' router called '$name' used the 'gethostbyname'\n" . -" option, which no longer exists. You will have to rewrite it.\n"; - print STDOUT "#!!# gethostbyname option removed\n"; - delete $$hash{"gethostbyname"}; - } - - $$hash{"mx_domains"} = &no_expand_regex($$hash{"mx_domains"}) - if defined $$hash{"mx_domains"}; - } - - - # ---- Changes to the queryprogram router ---- - - elsif ($driver eq "queryprogram") - { - &rubric(); - print STDERR "\n" . -"** The configuration contains a 'queryprogram' router. Please note that\n" . -" the specification for the text that is returned by the program run\n" . -" by this router has changed in Exim 4. You will need to modify your\n" . -" program.\n"; - - if (!defined $$hash{'command_user'}) - { - &rubric(); - print STDERR "\n" . -"** The 'queryprogram' router called '$name' does not have a setting for\n" . -" the 'command_user' option. This is mandatory in Exim 4. A setting of\n" . -" 'nobody' has been created.\n"; - $$hash{"command_user"} = "nobody"; - } - } - - - # ------------------------------------- - - # Output the router's option settings - - &outdriver($hash); - next; - } - - # Skip past any continuation lines for an option setting - while ($c[$i] =~ /\\\s*$/s && $i < $clen - 1) - { - $i++; - $i++ while ($c[$i] =~ /^\s*#/); - } - } - -# Add "no_more" to the final driver from the old routers, provided it had no -# conditions. Otherwise, or if there were no routers, make up one to fail all -# non-local domains. - -if ($add_no_more) - { - print STDOUT " no_more\n"; - print STDOUT shift @comments while scalar(@comments) > 0; - } -else - { - print STDOUT shift @comments while scalar(@comments) > 0; - print STDOUT "\n#!!# This new router is put here to fail all domains that\n"; - print STDOUT "#!!# were not in local_domains in the Exim 3 configuration.\n\n"; - print STDOUT "fail_remote_domains:\n"; - print STDOUT " driver = redirect\n"; - print STDOUT " domains = ! +local_domains\n"; - print STDOUT " allow_fail\n"; - print STDOUT " data = :fail: unrouteable mail domain \"\$domain\"\n\n"; - } - -# Now copy the directors, making appropriate changes - -print STDOUT "\n"; -print STDOUT "#!!#######################################################!!#\n"; -print STDOUT "#!!# Here follow routers created from the old directors, #!!#\n"; -print STDOUT "#!!# for handling local domains. #!!#\n"; -print STDOUT "#!!#######################################################!!#\n"; - -$prefix = "d."; -for ($i = $director_start; $i < $clen; $i++) - { - $type = &checkline($c[$i]); - last if $type eq "end"; - - if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; } - - undef $second_router; - - if ($type eq "driver") - { - $hash = $driverlist{"$prefix$name"}; - $driver = $$hash{"driver"}; - print STDOUT "$name:\n"; - - $$hash{"caseful_local_part"} = "true" if $add_caseful_local_part; - - if (defined $$hash{"local_parts"} && - (defined $$hash{"prefix"} || defined $hash{"suffix"})) - { - &rubric(); - print STDERR "\n" . -"** The Exim 3 configuration contains a director called '$name' which has\n" . -" 'local_parts' set, together with either or both of 'prefix' and 'suffix'\n". -" This combination has a different effect in Exim 4, where the affix\n" . -" is removed *before* 'local_parts' is tested. You will probably need\n" . -" to make changes to this driver.\n"; - } - - &renamed($hash, "prefix", "local_part_prefix"); - &renamed($hash, "prefix_optional", "local_part_prefix_optional"); - &renamed($hash, "suffix", "local_part_suffix"); - &renamed($hash, "suffix_optional", "local_part_suffix_optional"); - &renamed($hash, "new_director", "redirect_router"); - - &handle_current_and_home_directory($hash, $driver, $name); - - # If the director had a require_files setting, check it for user names - # and colons that are part of expansion items - - if (defined $$hash{"require_files"}) - { - &check_require($$hash{"require_files"}, "'$name' director"); - if (($$hash{"require_files"} =~ s/(\$\{\w+):/$1::/g) > 0 || - ($$hash{"require_files"} =~ s/ldap:/ldap::/g) > 0) - { - &rubric(); - print STDERR "\n" . -"*** A setting of require_files in the $name director contains\n" . -" a colon in what appears to be an expansion item. In Exim 3, the\n" . -" whole string was expanded before splitting the list, but in Exim 4\n" . -" each item is expanded separately, so colons that are not list\n" . -" item separators have to be doubled. One or more such colons in this\n" . -" list have been doubled as a precaution. Please check the result.\n"; - } - } - - # If the director had a "senders" setting, munge the address list - - $$hash{"senders"} = &sort_address_list($$hash{"senders"}, "senders") - if defined $$hash{"senders"}; - - # ---- Changes to aliasfile director ---- - - if ($driver eq "aliasfile") - { - &abolished($hash, "An aliasfile director", - "directory2_transport", "freeze_missing_include", - "modemask", "owners", "owngroups"); - - $$hash{"driver"} = "redirect"; - - $key = "\$local_part"; - $key = "\$local_part\@\$domain" - if defined $$hash{"include_domain"} && - $$hash{"include_domain"} eq "true"; - delete $$hash{"include_domain"}; - - if (defined $$hash{"forbid_special"} && $$hash{"forbid_special"} eq "true") - { - $$hash{"forbid_blackhole"} = "true"; - } - else - { - $$hash{"allow_defer"} = "true"; - $$hash{"allow_fail"} = "true"; - } - delete $$hash{"forbid_special"}; - - # Deal with "file", "query", or "queries" - - if (defined $$hash{"file"}) - { - $$hash{"data"} = - "\$\{lookup\{$key\}$$hash{'search_type'}\{$$hash{'file'}\}\}"; - if (defined $$hash{"optional"} && $$hash{"optional"} eq "true") - { - $$hash{"data"} = - "\$\{if exists\{$$hash{'file'}\}\{$$hash{'data'}\}\}"; - } - delete $$hash{"optional"}; - } - elsif (defined $$hash{"query"}) - { - &abolished($hash, "An aliasfile director", "optional"); - $$hash{"data"} = "\${lookup $$hash{'search_type'} " . - "\{" . &unquote($$hash{'query'}) . "\}\}"; - } - else # Must be queries - { - &abolished($hash, "An aliasfile director", "optional"); - $endkets = 0; - $$hash{"data"} = ""; - $queries = $$hash{'queries'}; - $queries =~ s/^"(.*)"$/$1/s; - $queries =~ s/::/++colons++/g; - @qq = split(/:/, $queries); - - foreach $q (@qq) - { - $q =~ s/\+\+colons\+\+/:/g; - $q =~ s/^\s+//; - $q =~ s/\s+$//; - if ($endkets > 0) - { - $$hash{"data"} .= "\\\n {"; - $endkets++; - } - $$hash{"data"} .= "\${lookup $$hash{'search_type'} \{$q\}\{\$value\}"; - $endkets++; - } - - $$hash{"data"} .= "}" x $endkets; - } - - $$hash{"data"} = "\${expand:$$hash{'data'}\}" - if (defined $$hash{"expand"} && $$hash{"expand"} eq "true"); - - delete $$hash{"expand"}; - delete $$hash{"file"}; - delete $$hash{"query"}; - delete $$hash{"queries"}; - delete $$hash{"search_type"}; - - # Turn aliasfile + transport into accept + condition - - if (defined $$hash{'transport'}) - { - &rubric(); - if (!defined $$hash{'condition'}) - { - print STDERR "\n" . -"** The Exim 3 configuration contains an aliasfile director called '$name',\n". -" which has 'transport' set. This has been turned into an 'accept' router\n". -" with a 'condition' setting, but should be carefully checked.\n"; - $$hash{'driver'} = "accept"; - $$hash{'condition'} = - "\$\{if eq \{\}\{$$hash{'data'}\}\{no\}\{yes\}\}"; - delete $$hash{'data'}; - delete $$hash{'allow_defer'}; - delete $$hash{'allow_fail'}; - } - else - { - print STDERR "\n" . -"** The Exim 3 configuration contains an aliasfile director called '$name',\n". -" which has 'transport' set. This cannot be turned into an 'accept' router\n". -" with a 'condition' setting, because there is already a 'condition'\n" . -" setting. It has been left as 'redirect' with a transport, which is\n" . -" invalid - you must sort this one out.\n"; - } - } - } - - - # ---- Changes to forwardfile director ---- - - elsif ($driver eq "forwardfile") - { - &abolished($hash, "A forwardfile director", - "check_group", "directory2_transport", - "freeze_missing_include", "match_directory", - "seteuid"); - - &renamed($hash, "filter", "allow_filter"); - - $$hash{"driver"} = "redirect"; - $$hash{"check_local_user"} = "true" - if !defined $$hash{"check_local_user"}; - - if (defined $$hash{"forbid_pipe"} && $$hash{"forbid_pipe"} eq "true") - { - print STDOUT "#!!# forbid_filter_run added because forbid_pipe is set\n"; - $$hash{"forbid_filter_run"} = "true"; - } - - if (defined $$hash{'allow_system_actions'} && - $$hash{'allow_system_actions'} eq 'true') - { - $$hash{'allow_freeze'} = "true"; - } - delete $$hash{'allow_system_actions'}; - - # If file_directory is defined, use it to qualify relative paths; if not, - # and check_local_user is defined, use $home. Remove file_directory from - # the output. - - $dir = ""; - if (defined $$hash{"file_directory"}) - { - $dir = $$hash{"file_directory"} . "/"; - delete $$hash{"file_directory"}; - } - elsif ($$hash{"check_local_user"} eq "true") - { - $dir = "\$home/"; - } - - # If it begins with an upper case letter, guess that this is really - # a macro. - - if (defined $$hash{"file"} && $$hash{"file"} !~ /^[\/A-Z]/) - { - $$hash{"file"} = $dir . $$hash{"file"}; - } - } - - - # ---- Changes to localuser director ---- - - elsif ($driver eq "localuser") - { - &abolished($hash, "A localuser director", "match_directory"); - $$hash{"driver"} = "accept"; - $$hash{"check_local_user"} = "true"; - } - - - # ---- Changes to smartuser director ---- - - elsif ($driver eq "smartuser") - { - &abolished($hash, "A smartuser director", "panic_expansion_fail"); - - $transport = $$hash{"transport"}; - $new_address = $$hash{"new_address"}; - - if (defined $transport && defined $new_address) - { - &rubric(); - print STDERR "\n" . -"** The Exim 3 configuration contains a smartuser director called '$name',\n". -" which has both 'transport' and 'new_address' set. This has been turned\n". -" into two routers for Exim 4. However, if the new address contains a\n" . -" reference to \$local_part, this won't work correctly. In any case, you\n". -" may be able to make it tidier by rewriting.\n"; - $$hash{"driver"} = "redirect"; - $$hash{"data"} = $new_address; - $$hash{"redirect_router"} = "${name}_part2"; - - $second_router = "\n". - "#!!# This router is invented to go with the previous one because\n". - "#!!# in Exim 4 you can't have a change of address and a transport\n". - "#!!# setting in the same router as you could in Exim 3.\n\n" . - "${name}_part2:\n". - " driver = accept\n". - " condition = \$\{if eq\{\$local_part@\$domain\}" . - "\{$new_address\}\{yes\}\{no\}\}\n". - " transport = $$hash{'transport'}\n"; - - delete $$hash{"new_address"}; - delete $$hash{"transport"}; - } - elsif (defined $new_address) - { - $$hash{"driver"} = "redirect"; - $$hash{"data"} = $new_address; - $$hash{"allow_defer"} = "true"; - $$hash{"allow_fail"} = "true"; - delete $$hash{"new_address"}; - } - else # Includes the case of neither set (verify_only) - { - $$hash{"driver"} = "accept"; - if (defined $$hash{"rewrite"}) - { - &rubric(); - print STDERR "\n" . -"** The Exim 3 configuration contains a setting of the 'rewrite' option on\n". -" a smartuser director called '$name', but this director does not have\n". -" a setting of 'new_address', so 'rewrite' has no effect. The director\n". -" has been turned into an 'accept' router, and 'rewrite' has been discarded."; - delete $$hash{"rewrite"}; - } - } - } - - - # ------------------------------------- - - # For ex-directors that don't have check_local_user set, add - # retry_use_local_part to imitate what Exim 3 would have done. - - $$hash{"retry_use_local_part"} = "true" - if (!defined $$hash{"check_local_user"} || - $$hash{"check_local_user"} eq "false") ; - - # Output the router's option settings - - &outdriver($hash); - - # Output an auxiliary router if one is needed - - print STDOUT $second_router if defined $second_router; - - next; - } - - # Skip past any continuation lines for an option setting - while ($c[$i] =~ /\\\s*$/s) - { - $i++; - $i++ while ($c[$i] =~ /^\s*#/); - } - } - - - -# -------- The transports configuration -------- - -$started = 0; -$prefix = "t."; -for ($i = $transport_start; $i < $clen; $i++) - { - $type = &checkline($c[$i]); - last if $type eq "end"; - - if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; } - - if (!$started) - { - print STDOUT "begin transports\n\n"; - $started = 1; - } - - if ($type eq "driver") - { - $hash = $driverlist{"$prefix$name"}; - $driver = $$hash{"driver"}; - print STDOUT "$name:\n"; - - # ---- Changes to the appendfile transport ---- - - if ($driver eq "appendfile") - { - &renamed($hash, "prefix", "message_prefix"); - &renamed($hash, "suffix", "message_suffix"); - &abolished($hash, "An appendfile transport", - "require_lockfile"); - &handle_batch_and_bsmtp($hash); - if (defined $$hash{"from_hack"} && $$hash{"from_hack"} eq "false") - { - print STDOUT "#!!# no_from_hack replaced by check_string\n"; - $$hash{"check_string"} = ""; - } - delete $$hash{"from_hack"}; - } - - # ---- Changes to the lmtp transport ---- - - elsif ($driver eq "lmtp") - { - if (defined $$hash{"batch"} && $$hash{"batch"} ne "none") - { - $$hash{"batch_max"} = "100" if !defined $$hash{"batch_max"}; - $$hash{"batch_id"} = "\$domain" if $$hash{"batch"} eq "domain"; - } - else - { - $$hash{"batch_max"} = "1" if defined $$hash{"batch_max"}; - } - delete $$hash{"batch"}; - } - - # ---- Changes to the pipe transport ---- - - elsif ($driver eq "pipe") - { - &renamed($hash, "prefix", "message_prefix"); - &renamed($hash, "suffix", "message_suffix"); - &handle_batch_and_bsmtp($hash); - if (defined $$hash{"from_hack"} && $$hash{"from_hack"} eq "false") - { - print STDOUT "#!!# no_from_hack replaced by check_string\n"; - $$hash{"check_string"} = ""; - } - delete $$hash{"from_hack"}; - } - - # ---- Changes to the smtp transport ---- - - elsif ($driver eq "smtp") - { - &abolished($hash, "An smtp transport", "mx_domains"); - &renamed($hash, "service", "port"); - &renamed($hash, "tls_verify_ciphers", "tls_require_ciphers"); - &renamed($hash, "authenticate_hosts", "hosts_try_auth"); - - if (defined $$hash{"batch_max"}) - { - print STDOUT "#!!# batch_max renamed connection_max_messages\n"; - $$hash{"connection_max_messages"} = $$hash{"batch_max"}; - delete $$hash{"batch_max"}; - } - - foreach $o ("hosts_try_auth", "hosts_avoid_tls", "hosts_require_tls", - "mx_domains", "serialize_hosts") - { - $$hash{$o} = &no_expand_regex($$hash{$o}) if defined $$hash{$o}; - } - } - - &outdriver($driverlist{"$prefix$name"}); - next; - } - - # Skip past any continuation lines for an option setting - while ($c[$i] =~ /\\\s*$/s) - { - $i++; - $i++ while ($c[$i] =~ /^\s*#/); - } - } - - -# -------- The retry configuration -------- - -$started = 0; -for ($i = $retry_start; $i < $clen && $i < $rewrite_start - 1; $i++) - { - if (!$started) - { - if ($c[$i] !~ /^\s*(#|$)/) - { - print STDOUT "\nbegin retry\n\n"; - $started = 1; - } - } - &print_no_expand($c[$i]); - } - -print STDOUT "\n# End of Exim 4 configuration\n"; - -print STDERR "\n*******************************************************\n"; -print STDERR "***** Please review the generated file carefully. *****\n"; -print STDERR "*******************************************************\n\n"; - -# End of convert4r4 -