Commit | Line | Data |
---|---|---|
8c4f17b3 | 1 | #! PERL_COMMAND |
059ec3d9 PH |
2 | |
3 | # This is a Perl script that reads an Exim run-time configuration file for | |
4 | # Exim 3. It makes what changes it can for Exim 4, and also output commentary | |
5 | # on what it has done, and on things it cannot do. | |
6 | ||
7 | # It is assumed that the input is a valid Exim 3 configuration file. | |
8 | ||
8c4f17b3 | 9 | use warnings; |
4d3d955f | 10 | BEGIN { pop @INC if $INC[-1] eq '.' }; |
059ec3d9 | 11 | |
983da878 HSHR |
12 | use Getopt::Long; |
13 | use File::Basename; | |
14 | ||
15 | GetOptions( | |
16 | 'version' => sub { | |
17 | print basename($0) . ": $0\n", | |
18 | "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n", | |
19 | "perl(runtime): $^V\n"; | |
20 | exit 0; | |
21 | }, | |
22 | ); | |
23 | ||
059ec3d9 PH |
24 | # These are lists of main options which are abolished in Exim 4. |
25 | # The first contains options that are used to construct new options. | |
26 | ||
27 | @skipped_options = ( | |
28 | "auth_hosts", | |
29 | "auth_over_tls_hosts", | |
30 | "errors_address", | |
31 | "headers_check_syntax", | |
32 | "headers_checks_fail", | |
33 | "headers_sender_verify", | |
34 | "headers_sender_verify_errmsg", | |
35 | "host_accept_relay", | |
36 | "host_auth_accept_relay", | |
37 | "host_reject_recipients", | |
38 | "local_domains", | |
39 | "local_domains_include_host", | |
40 | "local_domains_include_host_literals", | |
41 | "log_all_parents", | |
42 | "log_arguments", | |
43 | "log_incoming_port", | |
44 | "log_interface", | |
45 | "log_level", | |
46 | "log_received_sender", | |
47 | "log_received_recipients", | |
48 | "log_rewrites", | |
49 | "log_sender_on_delivery", | |
50 | "log_smtp_confirmation", | |
51 | "log_smtp_connections", | |
52 | "log_smtp_syntax_errors", | |
53 | "log_subject", | |
54 | "log_queue_run_level", | |
55 | "rbl_domains", | |
56 | "rbl_hosts", | |
57 | "rbl_reject_recipients", | |
58 | "receiver_verify", | |
59 | "receiver_verify_addresses", | |
60 | "receiver_verify_hosts", | |
61 | "receiver_verify_senders", | |
62 | "recipients_reject_except", | |
63 | "recipients_reject_except_senders", | |
64 | "relay_domains", | |
65 | "relay_domains_include_local_mx", | |
66 | "sender_address_relay", | |
67 | "sender_address_relay_hosts", | |
68 | "sender_reject_recipients", | |
69 | "sender_verify", | |
70 | "sender_verify_hosts_callback", | |
71 | "sender_verify_callback_domains", | |
72 | "sender_verify_callback_timeout", | |
73 | "sender_verify_hosts", | |
74 | "smtp_etrn_hosts", | |
75 | "smtp_expn_hosts", | |
76 | "smtp_verify", | |
77 | "tls_host_accept_relay", | |
78 | "tls_hosts", | |
79 | "tls_log_cipher", | |
80 | "tls_log_peerdn", | |
81 | "tls_verify_ciphers" | |
82 | ); | |
83 | ||
84 | # The second contains options that are completely abolished and have | |
85 | # no equivalent. | |
86 | ||
87 | @abolished_options = ( | |
88 | "always_bcc", | |
89 | "debug_level", | |
90 | "helo_strict_syntax", | |
91 | "kill_ip_options", | |
92 | "log_ip_options", | |
93 | "log_refused_recipients", | |
94 | "message_size_limit_count_recipients", | |
95 | "rbl_log_headers", | |
96 | "rbl_log_rcpt_count", | |
97 | "receiver_try_verify", | |
98 | "refuse_ip_options", | |
99 | "relay_match_host_or_sender", | |
100 | "sender_try_verify", | |
101 | "sender_verify_batch", | |
102 | "sender_verify_fixup", | |
103 | "sender_verify_reject", | |
104 | "sender_verify_max_retry_rate", | |
105 | ); | |
106 | ||
107 | # This is a list of options that are not otherwise handled, but which | |
108 | # contain domain or host lists that have to be processed so that any | |
109 | # regular expressions are marked "not for expansion". | |
110 | ||
111 | @list_options = ( | |
112 | "dns_again_means_nonexist", | |
113 | "hold_domains", | |
114 | "hosts_treat_as_local", | |
115 | "percent_hack_domains", | |
116 | "queue_smtp_domains", | |
117 | "helo_accept_junk_hosts", | |
118 | "host_lookup", | |
119 | "ignore_fromline_hosts", | |
120 | "rfc1413_hosts", | |
121 | "sender_unqualified_hosts", | |
122 | "smtp_reserve_hosts", | |
123 | "tls_advertise_hosts", | |
124 | "tls_verify_hosts", | |
125 | ); | |
126 | ||
127 | ||
128 | ||
129 | ################################################## | |
130 | # Output problem rubric once # | |
131 | ################################################## | |
132 | ||
133 | sub rubric { | |
134 | return if $rubric_output; | |
135 | $rubric_output = 1; | |
136 | print STDERR "\n" . | |
137 | "** The following comments describe problems that have been encountered\n" . | |
138 | " while converting an Exim 3 runtime file for Exim 4. More detail can\n" . | |
139 | " be found in the file doc/Exim4.upgrade.\n"; | |
140 | } | |
141 | ||
142 | ||
143 | ################################################## | |
144 | # Analyse one line # | |
145 | ################################################## | |
146 | ||
147 | sub checkline{ | |
148 | my($line) = $_[0]; | |
149 | ||
150 | return "comment" if $line =~ /^\s*(#|$)/; | |
151 | return "end" if $line =~ /^\s*end\s*$/i; | |
152 | ||
153 | # Macros are recognized only in the first section of the file. | |
154 | ||
155 | return "macro" if $prefix eq "" && $line =~ /^\s*[A-Z]/; | |
156 | ||
157 | # In retry and rewrite sections, the type is always "other" | |
158 | ||
159 | return "other" if $prefix eq "=retry" || $prefix eq "=rewrite"; | |
160 | ||
161 | # Pick out the name at the start and the rest of the line (into global | |
162 | # variables) and return whether the start of a driver or not. | |
163 | ||
164 | ($hide,$name,$rest) = $line =~ /^\s*(hide\s+|)([a-z0-9_]+)\s*(.*?)\s*$/; | |
165 | ||
166 | # If $rest begins with a colon, this is a driver name | |
167 | ||
168 | return "driver" if $rest =~ /^:/; | |
169 | ||
170 | # If $rest begins with an = the value of the option is given explicitly; | |
171 | # remove the = from the start. Turn "yes"/"no" into "true"/"false". | |
172 | ||
173 | if ($rest =~ /^=/) | |
174 | { | |
175 | $rest =~ s/^=\s*//; | |
176 | $rest = "true" if $rest eq "yes"; | |
177 | $rest = "false" if $rest eq "no"; | |
178 | } | |
179 | ||
180 | # Otherwise we have a boolean option. Set up a "true"/"false" value. | |
181 | ||
182 | else | |
183 | { | |
184 | if ($name =~ /^not?_/) # Recognize "no_" or "not_" | |
185 | { | |
186 | $rest = "false"; | |
187 | $name =~ s/^not?_//; | |
188 | } | |
189 | else | |
190 | { | |
191 | $rest = "true"; | |
192 | } | |
193 | } | |
194 | ||
195 | return "option"; | |
196 | } | |
197 | ||
198 | ||
199 | ||
200 | ################################################## | |
201 | # Negate a list of things # | |
202 | ################################################## | |
203 | ||
204 | # Can be tricky, because there may be comment lines in the list. | |
205 | # Also, lists may have different delimiters. | |
206 | ||
207 | sub negate { | |
208 | my($list) = $_[0]; | |
209 | my($delim) = ":"; | |
210 | my($leadin) = ""; | |
211 | ||
212 | return $list if ! defined $list; | |
213 | ||
214 | ($list) = $list =~ /^"?(.*?)"?\s*$/s; # Remove surrounding quotes | |
215 | $list =~ s/\\\s*\n\s*//g; # Remove continuation markers | |
216 | ||
217 | if ($list =~ /^(\s*<(\S)\s*)(.*)/s) | |
218 | { | |
219 | $leadin = $1; | |
220 | $delim = $2; | |
221 | $list = $3; | |
222 | } | |
223 | ||
224 | $list =~ s/^\s+//; | |
225 | $list =~ s/\Q$delim$delim/>%%%%</g; | |
226 | @split = split /\s*\Q$delim\E\s*/s, $list; | |
227 | ||
228 | foreach $item (@split) | |
229 | { | |
230 | $item =~ s/>%%%%</$delim$delim/g; | |
231 | ||
232 | if ($item =~ /^\s*#/) | |
233 | { | |
234 | $item =~ s/((?:^\s*#[^\n]*\n)+\s*)/$1! /mg; | |
235 | $item =~ s/!\s*!//sg; | |
236 | } | |
237 | else | |
238 | { | |
239 | if ($item =~ /^\s*!(.*)/) | |
240 | { $item = $1; } | |
241 | else | |
242 | { $item = "! " . $item; } | |
243 | } | |
244 | } | |
245 | ||
246 | $" = " $delim \\\n "; | |
247 | $leadin .= " " if $leadin !~ /(^|\s)$/; | |
248 | return "$leadin@split"; | |
249 | } | |
250 | ||
251 | ||
252 | ||
253 | ################################################## | |
254 | # Prevent regex expansion in a list of things # | |
255 | ################################################## | |
256 | ||
257 | # Can be tricky, because there may be comment lines in the list. | |
258 | # Also, lists may have different delimiters. | |
259 | ||
260 | sub no_expand_regex { | |
261 | my($list) = $_[0]; | |
262 | my($delim) = ":"; | |
263 | my($leadin) = ""; | |
264 | ||
265 | return $list if ! defined $list; | |
266 | ||
267 | $delim = $_[1] if (defined $_[1]); | |
268 | ||
269 | my($is_route_list) = $delim eq ";"; | |
270 | ||
271 | ($list) = $list =~ /^"?(.*?)"?\s*$/s; # Remove surrounding quotes | |
272 | $list =~ s/\\\s*\n\s*//g; # Remove continuation markers | |
273 | ||
274 | if ($list =~ /^(\s*<(\S)\s*)(.*)/s) | |
275 | { | |
276 | $leadin = $1; | |
277 | $delim = $2; | |
278 | $list = $3; | |
279 | } | |
280 | ||
281 | $list =~ s/^\s+//; | |
282 | $list =~ s/\Q$delim$delim/>%%%%</g; | |
283 | @split = split /\s*\Q$delim\E\s*/s, $list; | |
284 | ||
285 | my($changed) = 0; | |
286 | foreach $item (@split) | |
287 | { | |
288 | $item =~ s/>%%%%</$delim$delim/g; | |
289 | if ($item =~ /^\^/) | |
290 | { | |
291 | # Fudge for route_list items | |
292 | ||
293 | if ($is_route_list) | |
294 | { | |
295 | $item = "\\N$item"; # Only one item ... | |
296 | } | |
297 | else | |
298 | { | |
299 | $item = "\\N$item\\N"; | |
300 | } | |
301 | $changed = 1; | |
302 | } | |
303 | } | |
304 | print STDOUT | |
305 | "#!!# Regular expressions enclosed in \\N...\\N to avoid expansion\n" | |
306 | if $changed; | |
307 | ||
308 | $" = " $delim \\\n "; | |
309 | $leadin .= " " if $leadin !~ /(^|\s)$/; | |
310 | return "$leadin@split"; | |
311 | } | |
312 | ||
313 | ||
314 | ||
315 | ################################################## | |
316 | # Sort out lookups in an address list # | |
317 | ################################################## | |
318 | ||
319 | # Can be tricky, because there may be comment lines in the list. | |
320 | # Also, lists may have different delimiters. | |
321 | ||
322 | sub sort_address_list { | |
323 | my($list) = $_[0]; | |
324 | my($name) = $_[1]; | |
325 | my($delim) = ":"; | |
326 | my($leadin) = ""; | |
327 | my($quoted) = 0; | |
328 | ||
329 | return $list if ! defined $list; | |
330 | ||
331 | if ($list =~ /^"(.*?)"\s*$/s) # Remove surrounding quotes | |
332 | { | |
333 | $list = $1; | |
334 | $quoted = 1; | |
335 | } | |
336 | ||
337 | $list =~ s/\\\s*\n\s*//g; # Remove continuation markers | |
338 | ||
339 | if ($list =~ /^(\s*<(\S)\s*)(.*)/s) | |
340 | { | |
341 | $leadin = $1; | |
342 | $delim = $2; | |
343 | $list = $3; | |
344 | } | |
345 | ||
346 | $list =~ s/^\s+//; | |
347 | $list =~ s/\Q$delim$delim/>%%%%</g; | |
348 | @split = split /\s*\Q$delim\E\s*/s, $list; | |
349 | ||
350 | foreach $item (@split) | |
351 | { | |
352 | $item =~ s/>%%%%</$delim$delim/g; | |
353 | if ($item =~ /^\s*(?:partial-)?(\w+;.*)$/) | |
354 | { | |
355 | my($lookup) = $1; | |
356 | if ($lookup =~ /^lsearch|^dbm|^cdb|^nis[^p]/) | |
357 | { | |
358 | &rubric(); | |
359 | print STDERR "\n" . | |
360 | "** The Exim 3 \"$name\" option specifies an address\n" . | |
361 | " list that includes the item\n\n" . | |
362 | " $item\n\n" . | |
363 | " In Exim 4 address lists, single-key lookups without a local part just\n" . | |
364 | " look up the complete address. They don't also try the domain, as\n" . | |
365 | " happened in Exim 3. The item has been rewritten as two items to make\n" . | |
366 | " it behave in the same way as Exim 3, but you should check to see if\n" . | |
367 | " this is actually what you want.\n"; | |
368 | ||
369 | $item = "*\@$item $delim $lookup"; | |
370 | } | |
371 | } | |
372 | } | |
373 | ||
374 | $" = " $delim \\\n "; | |
375 | $leadin .= " " if $leadin !~ /(^|\s)$/; | |
376 | ||
377 | return $quoted? "\"$leadin@split\"" : "$leadin@split"; | |
378 | } | |
379 | ||
380 | ||
381 | ||
382 | ################################################## | |
383 | # Quote a string against expansion # | |
384 | ################################################## | |
385 | ||
386 | # Used for setting up new "domains" options | |
387 | ||
388 | sub expquote { | |
389 | my($s) = $_[0]; | |
390 | $s =~ s/\$/\\\$/sg; | |
391 | $s =~ s/\\(?!\s*\n)/\\\\/sg; | |
392 | return $s; | |
393 | } | |
394 | ||
395 | ||
396 | ||
397 | ################################################## | |
398 | # Dequote an option string # | |
399 | ################################################## | |
400 | ||
401 | # If the original list is not quoted, do nothing. | |
402 | # If it is quoted, just get rid of the quotes. | |
403 | ||
404 | sub unquote { | |
405 | my($s) = $_[0]; | |
406 | $s =~ s/^"(.*)"$/$1/s; | |
407 | return $s; | |
408 | } | |
409 | ||
410 | ||
411 | ################################################## | |
412 | # Quote/dequote an option string # | |
413 | ################################################## | |
414 | ||
415 | # If the original list is not quoted, quote it against expansion. | |
416 | # If it is quoted, just get rid of the quotes. Also, indent any | |
417 | # continuations. | |
418 | ||
419 | sub acl_quote { | |
420 | my($s) = $_[0]; | |
421 | $s = ($s =~ /^"(.*)"$/s)? $1 : &expquote($s); | |
422 | $s =~ s/\n/\n /g; | |
423 | $s =~ s/\n\s{11,}/\n /g; | |
424 | return $s; | |
425 | } | |
426 | ||
427 | ||
428 | ################################################## | |
429 | # Handle abolished driver options # | |
430 | ################################################## | |
431 | ||
432 | sub abolished { | |
433 | my($hash) = shift @_; | |
434 | my($name) = shift @_; | |
435 | for $abolished (@_) | |
436 | { | |
437 | if (defined $$hash{$abolished}) | |
438 | { | |
439 | &rubric(); | |
440 | print STDERR "\n" . | |
441 | "** $name used the \"$abolished\" option, which no\n". | |
442 | " longer exists. The option has been removed.\n"; | |
443 | print STDOUT "#!!# $abolished option removed\n"; | |
444 | delete $$hash{$abolished}; | |
445 | } | |
446 | } | |
447 | } | |
448 | ||
449 | ||
450 | ||
451 | ################################################## | |
452 | # Handle renamed driver options # | |
453 | ################################################## | |
454 | ||
455 | sub renamed { | |
456 | my($hash,$old,$new) = @_; | |
457 | if (defined $$hash{$old}) | |
458 | { | |
459 | print STDOUT "#!!# $old renamed $new\n"; | |
460 | $$hash{$new} = $$hash{$old}; | |
461 | delete $$hash{$old}; | |
462 | } | |
463 | } | |
464 | ||
465 | ||
466 | ||
467 | ################################################## | |
468 | # Comment on user names in require_files # | |
469 | ################################################## | |
470 | ||
471 | sub check_require { | |
472 | my($string, $name) = @_; | |
473 | ||
474 | $string =~ s/::/[[[]]]/g; | |
475 | my(@list) = split /:/, $string; | |
476 | my($item); | |
477 | ||
478 | for $item (@list) | |
479 | { | |
480 | if ($item =~ /^\s*[\w,]+\s*$/) | |
481 | { | |
482 | &rubric(); | |
483 | $item =~ s/^\s*//; | |
484 | $item =~ s/\s*$//; | |
485 | print STDERR "\n" . | |
486 | "** A setting of require_files in the $name contains\n" . | |
487 | " what appears to be a user name ('$item'). The ability to check files\n" . | |
488 | " as a specific user is done differently in Exim 4. In fact, because the\n" . | |
489 | " routers run as root, you may not need this at all.\n" | |
490 | } | |
491 | } | |
492 | } | |
493 | ||
494 | ||
495 | ################################################## | |
496 | # Handle current and home directory # | |
497 | ################################################## | |
498 | ||
499 | sub handle_current_and_home_directory { | |
500 | my($hash,$driver,$name) = @_; | |
501 | ||
502 | for ("current_directory", "home_directory") | |
503 | { | |
504 | if (defined $$hash{$_} && $$hash{$_} eq "check_local_user") | |
505 | { | |
506 | my($article) = (substr($driver, 0, 1) eq "a")? "an" : "a"; | |
507 | &rubric(); | |
508 | print STDERR "\n" . | |
509 | "** The Exim 3 configuration contains $article '$driver' director called\n" . | |
510 | " '$name', which set '$_' to the special value\n" . | |
511 | " 'check_local_user'. This facility has been abolished in Exim 4 because\n" . | |
512 | " it is no longer necessary. The setting has therefore been omitted. See\n" . | |
513 | " note X.\n"; | |
514 | delete $$hash{$_}; | |
515 | } | |
516 | else | |
517 | { | |
518 | &renamed($hash, $_, "transport_$_"); | |
519 | } | |
520 | } | |
521 | } | |
522 | ||
523 | ||
524 | ||
525 | ################################################## | |
526 | # Handle batch/bsmtp for appendfile/pipe # | |
527 | ################################################## | |
528 | ||
529 | sub handle_batch_and_bsmtp{ | |
530 | my($hash) = @_; | |
531 | ||
532 | if (defined $$hash{"bsmtp"}) | |
533 | { | |
534 | if ($$hash{"bsmtp"} ne "none") | |
535 | { | |
536 | $$hash{"use_bsmtp"} = "true"; | |
537 | $$hash{"message_prefix"} = "\"HELO \$primary_host_name\\n\"" | |
538 | if defined $$hash{"bsmtp_helo"} && $$hash{"bsmtp_helo"} eq "true"; | |
539 | } | |
540 | ||
541 | if ($$hash{"bsmtp"} eq "one") | |
542 | { | |
543 | delete $$hash{"batch"}; | |
544 | } | |
545 | else | |
546 | { | |
547 | $$hash{"batch"} = $$hash{"bsmtp"}; | |
548 | } | |
549 | ||
550 | delete $$hash{"bsmtp"}; | |
551 | delete $$hash{"bsmtp_helo"}; | |
552 | } | |
553 | ||
554 | if (defined $$hash{"batch"} && $$hash{"batch"} ne "none") | |
555 | { | |
556 | $$hash{"batch_max"} = "100" if !defined $$hash{"batch_max"}; | |
557 | $$hash{"batch_id"} = "\$domain" if $$hash{"batch"} eq "domain"; | |
558 | } | |
559 | else | |
560 | { | |
561 | $$hash{"batch_max"} = "1" if defined $$hash{"batch_max"}; | |
562 | } | |
563 | delete $$hash{"batch"}; | |
564 | } | |
565 | ||
566 | ||
567 | ||
568 | ################################################## | |
569 | # Output one option # | |
570 | ################################################## | |
571 | ||
572 | sub outopt { | |
573 | my($hash, $key, $no_expand) = @_; | |
574 | my($data) = $$hash{$key}; | |
575 | ||
576 | print STDOUT "hide " if defined $$hash{"$key-hide"}; | |
577 | ||
578 | # Output booleans in the form that doesn't use "=" | |
579 | ||
580 | if ($data eq "true") | |
581 | { | |
582 | print STDOUT "$key\n"; | |
583 | } | |
584 | elsif ($data eq "false") | |
585 | { | |
586 | print STDOUT "no_$key\n"; | |
587 | } | |
588 | else | |
589 | { | |
590 | if ($no_expand) | |
591 | { | |
592 | printf STDOUT ("$key = %s\n", &no_expand_regex($data)); | |
593 | } | |
594 | else | |
595 | { | |
596 | print STDOUT "$key = $data\n"; | |
597 | } | |
598 | } | |
599 | } | |
600 | ||
601 | ||
602 | ||
603 | ################################################## | |
604 | # Output the options for one driver # | |
605 | ################################################## | |
606 | ||
607 | # Put the "driver" option first | |
608 | ||
609 | sub outdriver { | |
610 | my($hash) = $_[0]; | |
611 | print STDOUT " driver = $$hash{'driver'}\n"; | |
612 | foreach $key (sort keys %$hash) | |
613 | { | |
614 | next if $key eq "driver" || $key =~ /-hide$/; | |
615 | print STDOUT " "; | |
616 | &outopt($hash, $key, 0); | |
617 | } | |
618 | } | |
619 | ||
620 | ||
621 | ||
622 | ################################################## | |
623 | # Output a rewrite or a retry line # | |
624 | ################################################## | |
625 | ||
626 | # These lines start with patterns which are now always expanded. If the | |
627 | # pattern is a regex, arrange for it not to expand. | |
628 | ||
629 | sub print_no_expand { | |
630 | my($s) = $_[0]; | |
631 | if ($s =~ /^\^/) | |
632 | { | |
633 | if (!$escape_output) | |
634 | { | |
635 | &rubric(); | |
636 | print STDERR "\n" . | |
637 | "** You have a retry or rewrite pattern that is a regular expression. Because\n" . | |
638 | " these patterns are now always expanded, you need to be sure that the\n" . | |
639 | " special characters in the regex are not interpreted by the expander.\n" . | |
640 | " \\N has been inserted at the start of the regex to prevent the rest of\n" . | |
641 | " it from being expanded.\n"; | |
642 | $escape_output = 1; | |
643 | } | |
644 | print STDOUT "\\N"; | |
645 | } | |
646 | print STDOUT "$s\n"; | |
647 | } | |
648 | ||
649 | ||
650 | ||
651 | ################################################## | |
652 | # Test a boolean main option # | |
653 | ################################################## | |
654 | ||
655 | # This just saves a lot of typing | |
656 | ||
657 | sub bool { | |
658 | return defined $main{$_[0]} && $main{$_[0]} eq "true"; | |
659 | } | |
660 | ||
661 | ||
662 | ||
663 | ################################################## | |
664 | # Main program # | |
665 | ################################################## | |
666 | ||
667 | print STDERR "Runtime configuration file converter for Exim release 4.\n"; | |
668 | ||
669 | $transport_start = $director_start = $router_start = $retry_start | |
670 | = $rewrite_start = $auth_start = 999999; | |
671 | ||
672 | $macro_output = ""; | |
673 | $rubric_output = 0; | |
674 | $errmsg_output = 0; | |
675 | $key_output = 0; | |
676 | $unk_output = 0; | |
677 | $escape_output = 0; | |
678 | $add_no_more = 0; | |
679 | $add_caseful_local_part = 0; | |
680 | $done_dns_check_names = 0; | |
681 | ||
682 | $queue_only_load_was_present = 0; | |
683 | $deliver_queue_load_max_was_present = 0; | |
684 | ||
685 | # Read the entire file into an array | |
686 | ||
687 | chomp(@c = <STDIN>); | |
688 | $clen = scalar @c; | |
689 | ||
690 | # Remove the standard comment that appears at the end of the default | |
691 | ||
692 | if ($clen > 0 && $c[$clen-1] =~ /^#\s*End of Exim configuration file\s*/i) | |
693 | { | |
694 | pop @c; | |
695 | $clen--; | |
696 | } | |
697 | ||
698 | # The first pass over the input fishes out all the options settings in the | |
699 | # main, transport, director, and router sections, and places their values in | |
700 | # associative arrays. It also notes the starting position of all the sections. | |
701 | ||
702 | $prefix = ""; | |
703 | %main = (); | |
704 | $hash = \%main; | |
705 | ||
706 | for ($i = 0; $i < $clen; $i++) | |
707 | { | |
708 | # Change references to +allow_unknown and +warn_unknown into +include_unknown | |
709 | ||
710 | if ($c[$i] =~ /\+(?:allow|warn)_unknown/) | |
711 | { | |
712 | if (!$unk_output) | |
713 | { | |
714 | &rubric(); | |
715 | print STDERR "\n" . | |
716 | "** You have used '+allow_unknown' or '+warn_unknown' in a configuration\n" . | |
717 | " option. This has been converted to '+include_unknown', but the action\n" . | |
718 | " is different in Exim 4, so you should review all the relevant options.\n"; | |
719 | $unk_output = 1; | |
720 | } | |
721 | $c[$i] =~ s/\+(?:allow|warn)_unknown/+include_unknown/g; | |
722 | } | |
723 | ||
724 | # Any reference to $errmsg_recipient is changed to $bounce_recipient | |
725 | ||
726 | if ($c[$i] =~ /\$errmsg_recipient/) | |
727 | { | |
728 | if (!$errmsg_output) | |
729 | { | |
730 | &rubric(); | |
731 | print STDERR "\n" . | |
732 | "** References to \$errmsg_recipient have been changed to \$bounce_recipient\n"; | |
733 | $errmsg_output = 1; | |
734 | } | |
735 | $c[$i] =~ s/\$errmsg_recipient/\$bounce_recipient/g; | |
736 | } | |
737 | ||
738 | ||
739 | # Analyse the type of line | |
740 | ||
741 | $type = &checkline($c[$i]); | |
742 | next if $type eq "comment"; | |
743 | ||
744 | # Output a warning if $key is used | |
745 | ||
746 | if ($c[$i] =~ /\$key/ && !$key_output) | |
747 | { | |
748 | &rubric(); | |
749 | print STDERR "\n" . | |
750 | "** You have used '\$key' in a configuration option. This variable does not\n" . | |
751 | " exist in Exim 4. Instead, the value you need for your lookup will be\n" . | |
752 | " in one of the other variables such as '\$domain' or '\$host'. You will\n" . | |
753 | " need to edit the new configuration to sort this out.\n"; | |
754 | $key_output = 1; | |
755 | } | |
756 | ||
757 | # Save macro definitions so we can output them first; must handle | |
758 | # continuations. | |
759 | ||
760 | if ($type eq "macro") | |
761 | { | |
762 | $macro_output .= "$c[$i++]\n" while $c[$i] =~ /\\\s*$|^\s*#/; | |
763 | $macro_output .= "$c[$i]\n"; | |
764 | } | |
765 | ||
766 | # Handle end of section | |
767 | ||
768 | elsif ($type eq "end") | |
769 | { | |
770 | if ($prefix eq "=rewrite") | |
771 | { | |
772 | $prefix = "a."; | |
773 | $auth_start = $i + 1; | |
774 | last; | |
775 | } | |
776 | elsif ($prefix eq "=retry") | |
777 | { | |
778 | $prefix = "=rewrite"; | |
779 | $rewrite_start = $i + 1; | |
780 | } | |
781 | elsif ($prefix eq "r.") | |
782 | { | |
783 | $prefix = "=retry"; | |
784 | $retry_start = $i + 1; | |
785 | } | |
786 | elsif ($prefix eq "d.") | |
787 | { | |
788 | $prefix = "r."; | |
789 | $router_start = $i + 1; | |
790 | } | |
791 | elsif ($prefix eq "t.") | |
792 | { | |
793 | $prefix = "d."; | |
794 | $director_start = $i + 1; | |
795 | } | |
796 | elsif ($prefix eq "") | |
797 | { | |
798 | $prefix = "t."; | |
799 | $transport_start = $i + 1; | |
800 | } | |
801 | } | |
802 | ||
803 | # Handle start of a new director, router or transport driver | |
804 | ||
805 | elsif ($type eq "driver" && $prefix !~ /^=/) | |
806 | { | |
807 | $hash = {}; | |
808 | if (defined $driverlist{"$prefix$name"}) | |
809 | { | |
810 | die "*** There are two drivers with the name \"$name\"\n"; | |
811 | } | |
812 | $driverlist{"$prefix$name"} = $hash; | |
813 | $first_director = $name if !defined $first_director && $prefix eq "d."; | |
814 | } | |
815 | ||
816 | # Handle definition of an option; we must pull in any continuation | |
817 | # strings, and save the value in the current hash. Note if the option | |
818 | # is hidden. | |
819 | ||
820 | elsif ($type eq "option") | |
821 | { | |
822 | my($nextline) = ""; | |
823 | ||
824 | while ($i < $clen - 1 && ($rest =~ /\\\s*$/s || $nextline =~ /^\s*#/)) | |
825 | { | |
826 | $nextline = $c[++$i]; | |
827 | $rest .= "\n$nextline"; | |
828 | } | |
829 | ||
830 | $$hash{$name} = $rest; | |
831 | $$hash{"$name-hide"} = 1 if $hide ne ""; | |
832 | } | |
833 | } | |
834 | ||
835 | ||
836 | # Generate the new configuration. Start with a warning rubric. | |
837 | ||
838 | print STDOUT "#!!# This file is output from the convert4r4 script, which tries\n"; | |
839 | print STDOUT "#!!# to convert Exim 3 configurations into Exim 4 configurations.\n"; | |
840 | print STDOUT "#!!# However, it is not perfect, especially with non-simple\n"; | |
841 | print STDOUT "#!!# configurations. You must check it before running it.\n"; | |
842 | print STDOUT "\n\n"; | |
843 | ||
844 | # Output the macro definitions | |
845 | ||
846 | if ($macro_output ne "") | |
847 | { | |
848 | print STDOUT "#!!# All macro definitions have been gathered here to ensure\n"; | |
849 | print STDOUT "#!!# they precede any references to them.\n\n"; | |
850 | print STDOUT "$macro_output\n"; | |
851 | } | |
852 | ||
853 | # Output some default pointers to ACLs for RCPT and DATA time. If no Exim 3 | |
854 | # options that apply are set, non-restricting ACLs are generated. | |
855 | ||
856 | print STDOUT "#!!# These options specify the Access Control Lists (ACLs) that\n"; | |
857 | print STDOUT "#!!# are used for incoming SMTP messages - after the RCPT and DATA\n"; | |
858 | print STDOUT "#!!# commands, respectively.\n\n"; | |
859 | ||
860 | print STDOUT "acl_smtp_rcpt = check_recipient\n"; | |
861 | print STDOUT "acl_smtp_data = check_message\n\n"; | |
862 | ||
863 | if (defined $main{"auth_over_tls_hosts"}) | |
864 | { | |
865 | print STDOUT "#!!# This option specifies the Access Control List (ACL) that\n"; | |
866 | print STDOUT "#!!# is used after an AUTH command.\n\n"; | |
867 | print STDOUT "acl_smtp_auth = check_auth\n\n"; | |
868 | } | |
869 | ||
870 | if (&bool("smtp_verify") || | |
871 | defined $main{"smtp_etrn_hosts"} || | |
872 | defined $main{"smtp_expn_hosts"}) | |
873 | { | |
874 | print STDOUT "#!!# These options specify the Access Control Lists (ACLs) that\n"; | |
875 | print STDOUT "#!!# are used to control the ETRN, EXPN, and VRFY commands.\n"; | |
876 | print STDOUT "#!!# Where no ACL is defined, the command is locked out.\n\n"; | |
877 | ||
878 | print STDOUT "acl_smtp_etrn = check_etrn\n" if defined $main{"smtp_etrn_hosts"}; | |
879 | print STDOUT "acl_smtp_expn = check_expn\n" if defined $main{"smtp_expn_hosts"}; | |
880 | print STDOUT "acl_smtp_vrfy = check_vrfy\n" if &bool("smtp_verify"); | |
881 | print STDOUT "\n"; | |
882 | } | |
883 | ||
884 | # If local_domains was set, get its value; otherwise set to "@". Add into it | |
885 | # appropriate magic for local_domains_include_host[_literals]. | |
886 | ||
887 | $local_domains = (defined $main{"local_domains"})? $main{"local_domains"} : "@"; | |
888 | ||
889 | $ldsep = ":"; | |
890 | if ($local_domains =~ /^\s*<(.)\s*(.*)/s) | |
891 | { | |
892 | $ldsep = $1; | |
893 | $local_domains = $2; | |
894 | } | |
895 | ||
896 | $local_domains = "\@[] $ldsep " . $local_domains | |
897 | if defined $main{"local_domains_include_host_literals"} && | |
898 | $main{"local_domains_include_host_literals"} eq "true"; | |
899 | ||
900 | $local_domains = "\@ $ldsep " . $local_domains | |
901 | if defined $main{"local_domains_include_host"} && | |
902 | $main{"local_domains_include_host"} eq "true"; | |
903 | ||
904 | $local_domains = "<$ldsep " . $local_domains if $ldsep ne ":"; | |
905 | ||
906 | # Output a domain list setting for these domains, provided something is defined | |
907 | ||
908 | if ($local_domains !~ /^\s*$/) | |
909 | { | |
910 | print STDOUT "#!!# This setting defines a named domain list called\n"; | |
911 | print STDOUT "#!!# local_domains, created from the old options that\n"; | |
912 | print STDOUT "#!!# referred to local domains. It will be referenced\n"; | |
913 | print STDOUT "#!!# later on by the syntax \"+local_domains\".\n"; | |
914 | print STDOUT "#!!# Other domain and host lists may follow.\n\n"; | |
915 | ||
916 | printf STDOUT ("domainlist local_domains = %s\n\n", | |
917 | &no_expand_regex($local_domains)); | |
918 | } | |
919 | ||
920 | $relay_domains = (defined $main{"relay_domains"})? $main{"relay_domains"} : ""; | |
921 | ||
922 | $ldsep = ":"; | |
923 | if ($relay_domains =~ /^\s*<(.)\s*(.*)/s) | |
924 | { | |
925 | $ldsep = $1; | |
926 | } | |
927 | ||
928 | if (defined $main{"relay_domains_include_local_mx"}) | |
929 | { | |
930 | $relay_domains .= ($relay_domains =~ /^\s*$/)? "\@mx_any" : | |
931 | " $ldsep \@mx_any"; | |
932 | } | |
933 | ||
934 | printf STDOUT ("domainlist relay_domains = %s\n", | |
935 | &no_expand_regex($relay_domains)) | |
936 | if $relay_domains !~ /^\s*$/; | |
937 | ||
938 | ||
939 | # If ignore_errmsg_errors is set, we are going to force 0s as the value | |
940 | # for ignore_errmsg_errors_after, so arrange to skip any other value. | |
941 | ||
942 | push @skipped_options, "ignore_errmsg_errors_after" | |
943 | if &bool("ignore_errmsg_errors"); | |
944 | ||
945 | ||
946 | # If rbl_domains is set, split it up and generate six lists: | |
947 | # rbl_warn_domains, rbl_warn_domains_skiprelay | |
948 | # rbl_reject_domains, rbl_reject_domains_skiprelay | |
949 | # rbl_accept_domains, rbl_accept_domains_skiprelay | |
950 | ||
951 | if (defined $main{"rbl_domains"}) | |
952 | { | |
953 | my($s) = &unquote($main{"rbl_domains"}); | |
954 | $s =~ s/\s*\\\s*\n\s*/ /g; | |
955 | my(@list) = split /\s*:\s*/, $s; | |
956 | ||
957 | foreach $d (@list) | |
958 | { | |
959 | my(@sublist) = split /\//, $d; | |
960 | my($name) = shift @sublist; | |
961 | my($warn) = 0; | |
962 | if (defined $main{"rbl_reject_recipients"}) | |
963 | { | |
964 | $warn = $main{"rbl_reject_recipients"} ne "true"; | |
965 | } | |
966 | ||
967 | foreach $o (@sublist) | |
968 | { | |
969 | $warn = 1 if $o eq "warn"; | |
970 | $warn = 0 if $o eq "reject"; | |
971 | $warn = 2 if $o eq "accept"; | |
972 | $skiprelay = 1 if $o eq "skiprelay"; | |
973 | } | |
974 | ||
975 | if ($skiprelay) | |
976 | { | |
977 | if ($warn == 0) | |
978 | { | |
979 | $rbl_reject_skiprelay .= ((defined $rbl_reject_skiprelay)? ":":"").$name; | |
980 | } | |
981 | elsif ($warn == 1) | |
982 | { | |
983 | $rbl_warn_skiprelay .= ((defined $rbl_warn_skiprelay)? ":":"").$name; | |
984 | } | |
985 | elsif ($warn == 2) | |
986 | { | |
987 | $rbl_accept_skiprelay .= ((defined $rbl_accept_skiprelay)? ":":"").$name; | |
988 | } | |
989 | } | |
990 | else | |
991 | { | |
992 | if ($warn == 0) | |
993 | { | |
994 | $rbl_reject_domains .= ((defined $rbl_reject_domains)? ":":"").$name; | |
995 | } | |
996 | elsif ($warn == 1) | |
997 | { | |
998 | $rbl_warn_domains .= ((defined $rbl_warn_domains)? ":":"").$name; | |
999 | } | |
1000 | elsif ($warn == 2) | |
1001 | { | |
1002 | $rbl_accept_domains .= ((defined $rbl_accept_domains)? ":":"").$name; | |
1003 | } | |
1004 | } | |
1005 | } | |
1006 | } | |
1007 | ||
1008 | ||
1009 | # Output host list settings | |
1010 | ||
1011 | printf STDOUT ("hostlist auth_hosts = %s\n", | |
1012 | &no_expand_regex($main{"auth_hosts"})) | |
1013 | if defined $main{"auth_hosts"}; | |
1014 | printf STDOUT ("hostlist rbl_hosts = %s\n", | |
1015 | &no_expand_regex($main{"rbl_hosts"})) | |
1016 | if defined $main{"rbl_hosts"}; | |
1017 | printf STDOUT ("hostlist relay_hosts = %s\n", | |
1018 | &no_expand_regex($main{"host_accept_relay"})) | |
1019 | if defined $main{"host_accept_relay"}; | |
1020 | printf STDOUT ("hostlist auth_relay_hosts = %s\n", | |
1021 | &no_expand_regex($main{"host_auth_accept_relay"})) | |
1022 | if defined $main{"host_auth_accept_relay"}; | |
1023 | ||
1024 | printf STDOUT ("hostlist auth_over_tls_hosts = %s\n", | |
1025 | &no_expand_regex($main{"auth_over_tls_hosts"})) | |
1026 | if defined $main{"auth_over_tls_hosts"}; | |
1027 | printf STDOUT ("hostlist tls_hosts = %s\n", | |
1028 | &no_expand_regex($main{"tls_hosts"})) | |
1029 | if defined $main{"tls_hosts"}; | |
1030 | printf STDOUT ("hostlist tls_relay_hosts = %s\n", | |
1031 | &no_expand_regex($main{"tls_host_accept_relay"})) | |
1032 | if defined $main{"tls_host_accept_relay"}; | |
1033 | ||
1034 | print STDOUT "\n"; | |
1035 | ||
1036 | ||
1037 | # Convert various logging options | |
1038 | ||
1039 | $log_selector = ""; | |
1040 | $sep = " \\\n "; | |
1041 | ||
1042 | if (defined $main{"log_level"}) | |
1043 | { | |
1044 | my($level) = $main{"log_level"}; | |
1045 | $log_selector .= "$sep -retry_defer$sep -skip_delivery" if $level < 5; | |
1046 | $log_selector .= "$sep -lost_incoming_connection$sep -smtp_syntax_error" . | |
1047 | "$sep -delay_delivery" if $level < 4; | |
1048 | $log_selector .= "$sep -size_reject" if $level < 2; | |
1049 | } | |
1050 | ||
1051 | $log_selector .= "$sep -queue_run" | |
1052 | if defined $main{"log_queue_run_level"} && | |
1053 | defined $main{"log_level"} && | |
1054 | $main{"log_queue_run_level"} > $main{"log_level"}; | |
1055 | ||
1056 | $log_selector .= "$sep +address_rewrite" if &bool("log_rewrites"); | |
1057 | $log_selector .= "$sep +all_parents" if &bool("log_all_parents"); | |
1058 | $log_selector .= "$sep +arguments" if &bool("log_arguments"); | |
1059 | $log_selector .= "$sep +incoming_port" if &bool("log_incoming_port"); | |
1060 | $log_selector .= "$sep +incoming_interface" if &bool("log_interface"); | |
1061 | $log_selector .= "$sep +received_sender" if &bool("log_received_sender"); | |
1062 | $log_selector .= "$sep +received_recipients" if &bool("log_received_recipients"); | |
1063 | $log_selector .= "$sep +sender_on_delivery" if &bool("log_sender_on_delivery"); | |
1064 | $log_selector .= "$sep +smtp_confirmation" if &bool("log_smtp_confirmation"); | |
1065 | $log_selector .= "$sep +smtp_connection" if &bool("log_smtp_connections"); | |
1066 | $log_selector .= "$sep +smtp_syntax_error" if &bool("log_smtp_syntax_errors"); | |
1067 | $log_selector .= "$sep +subject" if &bool("log_subject"); | |
1068 | $log_selector .= "$sep +tls_cipher" if &bool("tls_log_cipher"); | |
1069 | $log_selector .= "$sep +tls_peerdn" if &bool("tls_log_peerdn"); | |
1070 | ||
1071 | ||
1072 | if ($log_selector ne "") | |
1073 | { | |
1074 | print STDOUT "#!!# All previous logging options are combined into a single\n" | |
1075 | . "#!!# option in Exim 4. This setting is an approximation to\n" | |
1076 | . "#!!# the previous state - some logging has changed.\n\n"; | |
1077 | print STDOUT "log_selector = $log_selector\n\n"; | |
1078 | } | |
1079 | ||
1080 | # If deliver_load_max is set, replace it with queue_only_load (taking the | |
1081 | # lower value if both set) and also set deliver_queue_load_max if it is | |
1082 | # not already set. When scanning for output, deliver_load_max is skipped. | |
1083 | ||
1084 | if (defined $main{"deliver_load_max"}) | |
1085 | { | |
1086 | &rubric(); | |
1087 | print STDERR "\n" . | |
1088 | "** deliver_load_max is abolished in Exim 4.\n"; | |
1089 | ||
1090 | if (defined $main{"queue_only_load"}) | |
1091 | { | |
1092 | $queue_only_load_was_present = 1; | |
1093 | if ($main{"queue_only_load"} < $main{"deliver_load_max"}) | |
1094 | { | |
1095 | print STDERR | |
1096 | " As queue_only_load was set lower, deliver_load_max is just removed.\n"; | |
1097 | } | |
1098 | else | |
1099 | { | |
1100 | print STDERR | |
1101 | " As queue_only_load was set higher, it's value has been replaced by\n" . | |
1102 | " the value of deliver_load_max.\n"; | |
1103 | $main{"queue_only_load"} = $main{"deliver_load_max"}; | |
1104 | } | |
1105 | } | |
1106 | else | |
1107 | { | |
1108 | print STDERR | |
1109 | " queue_only_load has been set to the load value.\n"; | |
1110 | $main{"queue_only_load"} = $main{"deliver_load_max"}; | |
1111 | } | |
1112 | ||
1113 | if (!defined $main{"deliver_queue_load_max"}) | |
1114 | { | |
1115 | print STDERR | |
1116 | " deliver_queue_load_max has been set to the value of queue_only_load.\n"; | |
1117 | $main{"deliver_queue_load_max"} = $main{"queue_only_load"}; | |
1118 | } | |
1119 | else | |
1120 | { | |
1121 | $deliver_queue_load_max_was_present = 1; | |
1122 | } | |
1123 | } | |
1124 | ||
1125 | ||
1126 | # Now we scan through the various parts of the file again, making changes | |
1127 | # as necessary. | |
1128 | ||
1129 | # -------- The main configuration -------- | |
1130 | ||
1131 | $prefix = ""; | |
1132 | MainLine: for ($i = 0; $i < $clen; $i++) | |
1133 | { | |
1134 | my($nextline) = ""; | |
1135 | $type = &checkline($c[$i]); | |
1136 | last if $type eq "end"; | |
1137 | ||
1138 | if ($type eq "macro") | |
1139 | { | |
1140 | $i++ while $c[$i] =~ /\\\s*$|^\s*#/; | |
1141 | next; | |
1142 | } | |
1143 | ||
1144 | if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; } | |
1145 | ||
1146 | # Collect any continuation lines for an option setting | |
1147 | ||
1148 | while ($rest =~ /\\\s*$/s || $nextline =~ /^\s*#/) | |
1149 | { | |
1150 | $nextline = $c[++$i]; | |
1151 | $rest .= "\n$nextline"; | |
1152 | } | |
1153 | ||
1154 | $rest =~ s/^=\s*//; | |
1155 | ||
1156 | # Deal with main options that are skipped (they are used in other | |
1157 | # options in other places). | |
1158 | ||
1159 | for $skipped (@skipped_options) | |
1160 | { | |
1161 | next MainLine if $name eq $skipped; | |
1162 | } | |
1163 | ||
1164 | # Deal with main options that are totally abolished | |
1165 | ||
1166 | for $abolished (@abolished_options) | |
1167 | { | |
1168 | if ($name eq $abolished) | |
1169 | { | |
1170 | &rubric(); | |
1171 | print STDERR "\n" . | |
1172 | "** The $name option no longer exists, and has no equivalent\n" . | |
1173 | " in Exim 4.\n"; | |
1174 | next MainLine; | |
1175 | } | |
1176 | } | |
1177 | ||
1178 | # There is a special case for rbl_warn_header | |
1179 | ||
1180 | if ($name eq "rbl_warn_header") | |
1181 | { | |
1182 | &rubric(); | |
1183 | print STDERR "\n" . | |
1184 | "** The $name option no longer exists. In Exim 4 you can achieve the\n" . | |
1185 | " effect by adding a suitable \"message\" statement in the ACL.\n"; | |
1186 | } | |
1187 | ||
1188 | # There is a special case for sender_reject and host_reject | |
1189 | ||
1190 | elsif ($name eq "sender_reject" || $name eq "host_reject") | |
1191 | { | |
1192 | &rubric(); | |
1193 | print STDERR "\n" . | |
1194 | "** The $name option no longer exists. Its data has been used in\n" . | |
1195 | " an Access Control List as if it were in ${name}_recipients.\n"; | |
1196 | } | |
1197 | ||
1198 | # And a special message for prohibition_message | |
1199 | ||
1200 | elsif ($name eq "prohibition_message") | |
1201 | { | |
1202 | &rubric(); | |
1203 | print STDERR "\n" . | |
1204 | "** The prohibition_message option no longer exists. The facility is\n" . | |
1205 | " provided in a different way in Exim 4, via the \"message\" keyword\n" . | |
1206 | " in Access Control Lists. It isn't possible to do an automatic conversion,\n" . | |
1207 | " so the value of prohibition_message has been ignored. You will have to\n" . | |
1208 | " modify the ACLs if you want to reinstate the feature.\n"; | |
1209 | } | |
1210 | ||
1211 | # auth_always_advertise gets converted to auth_advertise_hosts | |
1212 | ||
1213 | elsif ($name eq "auth_always_advertise") | |
1214 | { | |
1215 | print STDOUT "#!!# auth_always_advertise converted to auth_advertise_hosts\n"; | |
1216 | if (&bool("auth_always_advertise")) | |
1217 | { | |
1218 | print STDOUT "auth_advertise_hosts = *\n"; | |
1219 | } | |
1220 | else | |
1221 | { | |
1222 | $sep = ""; | |
1223 | print STDOUT "auth_advertise_hosts ="; | |
1224 | if (defined $main{"auth_hosts"}) | |
1225 | { | |
1226 | print STDOUT "$sep +auth_hosts"; | |
1227 | $sep = " :"; | |
1228 | } | |
1229 | if (defined $main{"host_accept_relay"}) | |
1230 | { | |
1231 | print STDOUT "$sep !+relay_hosts"; | |
1232 | $sep = " :"; | |
1233 | } | |
1234 | if (defined $main{"host_auth_accept_relay"}) | |
1235 | { | |
1236 | print STDOUT "$sep +auth_relay_hosts"; | |
1237 | } | |
1238 | print STDOUT "\n"; | |
1239 | } | |
1240 | } | |
1241 | ||
1242 | # Deal with main options that have to be rewritten | |
1243 | ||
1244 | elsif ($name eq "accept_timeout") | |
1245 | { | |
1246 | print STDOUT "#!!# accept_timeout renamed receive_timeout\n"; | |
1247 | print STDOUT "receive_timeout = $rest\n"; | |
1248 | } | |
1249 | ||
1250 | elsif ($name eq "collapse_source_routes") | |
1251 | { | |
1252 | print STDOUT "#!!# collapse_source_routes removed\n"; | |
1253 | print STDOUT "#!!# It has been a no-op since 3.10.\n"; | |
1254 | } | |
1255 | ||
1256 | elsif ($name eq "daemon_smtp_service") | |
1257 | { | |
1258 | print STDOUT "#!!# daemon_smtp_service renamed daemon_smtp_port\n"; | |
1259 | print STDOUT "daemon_smtp_port = $rest\n"; | |
1260 | } | |
1261 | ||
1262 | elsif ($name eq "dns_check_names" || $name eq "dns_check_names_pattern") | |
1263 | { | |
1264 | if (!$done_dns_check_names) | |
1265 | { | |
1266 | if (&bool("dns_check_names")) | |
1267 | { | |
1268 | if (defined $main{"dns_check_names_pattern"}) | |
1269 | { | |
1270 | &outopt(\%main, "dns_check_names_pattern", 0); | |
1271 | } | |
1272 | } | |
1273 | ||
1274 | else | |
1275 | { | |
1276 | print STDOUT "#!!# dns_check_names has been abolished\n"; | |
1277 | print STDOUT "#!!# setting dns_check_pattern empty to turn off check\n"; | |
1278 | print STDOUT "dns_check_names_pattern =\n"; | |
1279 | } | |
1280 | ||
1281 | $done_dns_check_names = 1; | |
1282 | } | |
1283 | } | |
1284 | ||
1285 | elsif ($name eq "deliver_load_max") | |
1286 | { | |
1287 | print STDOUT "deliver_queue_load_max = $main{'deliver_queue_load_max'}\n" | |
1288 | if !$deliver_queue_load_max_was_present; | |
1289 | print STDOUT "queue_only_load = $main{'queue_only_load'}\n" | |
1290 | if !$queue_only_load_was_present; | |
1291 | } | |
1292 | ||
1293 | elsif ($name eq "errmsg_file") | |
1294 | { | |
1295 | print STDOUT "#!!# errmsg_file renamed bounce_message_file\n"; | |
1296 | print STDOUT "bounce_message_file = $rest\n"; | |
1297 | } | |
1298 | ||
1299 | elsif ($name eq "errmsg_text") | |
1300 | { | |
1301 | print STDOUT "#!!# errmsg_text renamed bounce_message_text\n"; | |
1302 | print STDOUT "bounce_message_text = $rest\n"; | |
1303 | } | |
1304 | ||
1305 | elsif ($name eq "forbid_domain_literals") | |
1306 | { | |
1307 | print STDOUT "#!!# forbid_domain_literals replaced by allow_domain_literals\n"; | |
1308 | print STDOUT "allow_domain_literals = ", | |
1309 | &bool("forbid_domain_literals")? "false" : "true", "\n"; | |
1310 | } | |
1311 | ||
1312 | elsif ($name eq "freeze_tell_mailmaster") | |
1313 | { | |
1314 | print STDOUT "#!!# freeze_tell_mailmaster replaced by freeze_tell\n"; | |
1315 | if (&bool("freeze_tell_mailmaster")) | |
1316 | { | |
1317 | print STDOUT "freeze_tell = ", | |
1318 | ((defined $main{"errors_address"})? | |
1319 | $main{"errors_address"} : "postmaster"), "\n"; | |
1320 | } | |
1321 | else | |
1322 | { | |
1323 | print STDOUT "#!!# freeze_tell is unset by default\n"; | |
1324 | } | |
1325 | } | |
1326 | ||
1327 | elsif ($name eq "helo_verify") | |
1328 | { | |
1329 | print STDOUT "#!!# helo_verify renamed helo_verify_hosts\n"; | |
1330 | printf STDOUT ("helo_verify_hosts = %s\n", &no_expand_regex($rest)); | |
1331 | } | |
1332 | ||
1333 | elsif ($name eq "ignore_errmsg_errors") | |
1334 | { | |
1335 | print STDOUT "ignore_bounce_errors_after = 0s\n"; | |
1336 | } | |
1337 | ||
1338 | elsif ($name eq "ignore_errmsg_errors_after") | |
1339 | { | |
1340 | print STDOUT "#!!# ignore_errmsg_errors_after renamed ignore_bounce_errors_after\n"; | |
1341 | print STDOUT "ignore_bounce_errors_after = $rest\n"; | |
1342 | } | |
1343 | ||
1344 | elsif ($name eq "ipv4_address_lookup" || $name eq "dns_ipv4_lookup") | |
1345 | { | |
1346 | print STDOUT "#!!# $name changed to dns_ipv4_lookup\n" | |
1347 | if $name eq "ipv4_address_lookup"; | |
1348 | print STDOUT "#!!# dns_ipv4_lookup is now a domain list\n"; | |
1349 | if (&bool($name)) | |
1350 | { | |
1351 | print STDOUT "dns_ipv4_lookup = *\n"; | |
1352 | } | |
1353 | else | |
1354 | { | |
1355 | print STDOUT "#!!# default for dns_ipv4_lookup is unset\n"; | |
1356 | } | |
1357 | } | |
1358 | ||
1359 | elsif ($name eq "locally_caseless") | |
1360 | { | |
1361 | print STDOUT "#!!# locally_caseless removed\n"; | |
1362 | print STDOUT "#!!# caseful_local_part will be added to ex-directors\n"; | |
1363 | $add_caseful_local_part = 1; | |
1364 | } | |
1365 | ||
1366 | elsif ($name eq "message_filter_directory2_transport") | |
1367 | { | |
1368 | print STDOUT "#!!# message_filter_directory2_transport removed\n"; | |
1369 | } | |
1370 | ||
1371 | elsif ($name =~ /^message_filter(.*)/) | |
1372 | { | |
1373 | print STDOUT "#!!# $name renamed system_filter$1\n"; | |
1374 | print STDOUT "system_filter$1 = $rest\n"; | |
1375 | } | |
1376 | ||
1377 | elsif ($name eq "queue_remote_domains") | |
1378 | { | |
1379 | print STDOUT "#!!# queue_remote_domains renamed queue_domains\n"; | |
1380 | printf STDOUT ("queue_domains = %s\n", &no_expand_regex($rest)); | |
1381 | } | |
1382 | ||
1383 | elsif ($name eq "receiver_unqualified_hosts") | |
1384 | { | |
1385 | print STDOUT "#!!# receiver_unqualified_hosts renamed recipient_unqualified_hosts\n"; | |
1386 | printf STDOUT ("recipient_unqualified_hosts = %s\n", | |
1387 | &no_expand_regex($rest)); | |
1388 | } | |
1389 | ||
1390 | elsif ($name eq "remote_sort") | |
1391 | { | |
1392 | print STDOUT "#!!# remote_sort renamed remote_sort_domains\n"; | |
1393 | printf STDOUT ("remote_sort_domains = %s\n", &no_expand_regex($rest)); | |
1394 | } | |
1395 | ||
1396 | elsif ($name eq "security") | |
1397 | { | |
1398 | if ($rest eq "unprivileged") | |
1399 | { | |
1400 | print STDOUT "#!!# security=unprivileged changed to deliver_drop_privilege\n"; | |
1401 | print STDOUT "deliver_drop_privilege\n"; | |
1402 | } | |
1403 | else | |
1404 | { | |
1405 | &rubric(); | |
1406 | print STDERR "\n" . | |
1407 | "** The 'security' option no longer exists.\n"; | |
1408 | } | |
1409 | } | |
1410 | ||
1411 | elsif ($name eq "timestamps_utc") | |
1412 | { | |
1413 | print STDOUT "#!!# timestamps_utc changed to use timezone\n"; | |
1414 | print STDOUT "timezone = utc\n"; | |
1415 | } | |
1416 | ||
1417 | elsif ($name eq "untrusted_set_sender") | |
1418 | { | |
1419 | print STDOUT "#!!# untrusted_set_sender is now a list of what can be set\n"; | |
1420 | print STDOUT "#!!# The default is an empty list.\n"; | |
1421 | if (&bool("untrusted_set_sender")) | |
1422 | { | |
1423 | print STDOUT "untrusted_set_sender = *\n"; | |
1424 | } | |
1425 | } | |
1426 | ||
1427 | elsif ($name eq "warnmsg_file") | |
1428 | { | |
1429 | print STDOUT "#!!# warnmsg_file renamed warn_message_file\n"; | |
1430 | print STDOUT "warn_message_file = $rest\n"; | |
1431 | } | |
1432 | ||
1433 | # Remaining options just get copied unless they are one of those that's | |
1434 | # a list where any regular expressions have to be escaped. | |
1435 | ||
1436 | else | |
1437 | { | |
1438 | my($no_expand) = 0; | |
1439 | foreach $o (@list_options) | |
1440 | { | |
1441 | if ($name eq $o) | |
1442 | { | |
1443 | $no_expand = 1; | |
1444 | last; | |
1445 | } | |
1446 | } | |
1447 | &outopt(\%main, $name, $no_expand); | |
1448 | } | |
1449 | } | |
1450 | ||
1451 | ||
1452 | # -------- The ACL configuration -------- | |
1453 | ||
1454 | print STDOUT "\n"; | |
1455 | print STDOUT "#!!#######################################################!!#\n"; | |
1456 | print STDOUT "#!!# This new section of the configuration contains ACLs #!!#\n"; | |
1457 | print STDOUT "#!!# (Access Control Lists) derived from the Exim 3 #!!#\n"; | |
1458 | print STDOUT "#!!# policy control options. #!!#\n"; | |
1459 | print STDOUT "#!!#######################################################!!#\n"; | |
1460 | ||
1461 | print STDOUT "\n"; | |
1462 | print STDOUT "#!!# These ACLs are crudely constructed from Exim 3 options.\n"; | |
1463 | print STDOUT "#!!# They are almost certainly not optimal. You should study\n"; | |
1464 | print STDOUT "#!!# them and rewrite as necessary.\n"; | |
1465 | ||
1466 | print STDOUT "\nbegin acl\n\n"; | |
1467 | ||
1468 | ||
1469 | # Output an ACL for use after the RCPT command. This combines all the previous | |
1470 | # policy checking options. | |
1471 | ||
1472 | print STDOUT "#!!# ACL that is used after the RCPT command\n"; | |
1473 | print STDOUT "check_recipient:\n"; | |
1474 | ||
1475 | print STDOUT " # Exim 3 had no checking on -bs messages, so for compatibility\n"; | |
1476 | print STDOUT " # we accept if the source is local SMTP (i.e. not over TCP/IP).\n"; | |
1477 | print STDOUT " # We do this by testing for an empty sending host field.\n"; | |
1478 | print STDOUT " accept hosts = :\n"; | |
1479 | ||
1480 | if (defined $main{"tls_verify_ciphers"}) | |
1481 | { | |
1482 | print STDOUT " deny "; | |
1483 | print STDOUT "hosts = $main{'tls_verify_hosts'}\n " | |
1484 | if defined $main{"tls_verify_hosts"}; | |
1485 | print STDOUT " encrypted = *\n "; | |
1486 | print STDOUT "!encrypted = $main{'tls_verify_ciphers'}\n"; | |
1487 | } | |
1488 | ||
1489 | print STDOUT " deny hosts = +auth_hosts\n" . | |
1490 | " message = authentication required\n" . | |
1491 | " !authenticated = *\n" | |
1492 | if defined $main{"auth_hosts"}; | |
1493 | ||
1494 | print STDOUT " deny hosts = +tls_hosts\n" . | |
1495 | " message = encryption required\n" . | |
1496 | " !encrypted = *\n" | |
1497 | if defined $main{"tls_hosts"}; | |
1498 | ||
1499 | printf STDOUT (" accept recipients = %s\n", | |
1500 | &acl_quote(&sort_address_list($main{"recipients_reject_except"}, | |
1501 | "recipients_reject_except"))) | |
1502 | if defined $main{"recipients_reject_except"}; | |
1503 | ||
1504 | printf STDOUT (" accept senders = %s\n", | |
1505 | &acl_quote(&sort_address_list($main{"recipients_reject_except_senders"}, | |
1506 | "recipients_reject_except_senders"))) | |
1507 | if defined $main{"recipients_reject_except_senders"}; | |
1508 | ||
1509 | printf STDOUT (" deny hosts = %s\n", &acl_quote($main{"host_reject"})) | |
1510 | if defined $main{"host_reject"}; | |
1511 | ||
1512 | printf STDOUT (" deny hosts = %s\n", | |
1513 | &acl_quote($main{"host_reject_recipients"})) | |
1514 | if defined $main{"host_reject_recipients"}; | |
1515 | ||
1516 | if (defined $main{"rbl_domains"}) | |
1517 | { | |
1518 | my($msg) = "message = host is listed in \$dnslist_domain\n "; | |
1519 | my($hlist) = (defined $main{"rbl_hosts"})? | |
1520 | "hosts = +rbl_hosts\n " : ""; | |
1521 | ||
1522 | print STDOUT " accept ${hlist}dnslists = $rbl_accept_domains\n" | |
1523 | if defined $rbl_accept_domains; | |
1524 | print STDOUT " deny ${hlist}${msg}dnslists = $rbl_reject_domains\n" | |
1525 | if defined $rbl_reject_domains; | |
1526 | print STDOUT " warn ${hlist}" . | |
1527 | "message = X-Warning: \$sender_host_address is listed at \$dnslist_domain\n" . | |
1528 | " dnslists = $rbl_warn_domains\n" | |
1529 | if defined $rbl_warn_domains; | |
1530 | ||
1531 | if (defined $main{"host_accept_relay"}) | |
1532 | { | |
1533 | $hlist .= "hosts = !+relay_hosts\n "; | |
1534 | print STDOUT " accept ${hlist}dnslists = $rbl_accept_skiprelay\n" | |
1535 | if defined $rbl_accept_skiprelay; | |
1536 | print STDOUT " deny ${hlist}${msg}dnslists = $rbl_reject_skiprelay\n" | |
1537 | if defined $rbl_reject_skiprelay; | |
1538 | print STDOUT " warn ${hlist}" . | |
1539 | "message = X-Warning: \$sender_host_address is listed at \$dnslist_domain\n" . | |
1540 | " dnslists = $rbl_warn_skiprelay\n" | |
1541 | if defined $rbl_warn_skiprelay; | |
1542 | } | |
1543 | } | |
1544 | ||
1545 | printf STDOUT (" deny senders = %s\n", | |
1546 | &acl_quote(&sort_address_list($main{"sender_reject"}, "sender_reject"))) | |
1547 | if defined $main{"sender_reject"}; | |
1548 | ||
1549 | printf STDOUT (" deny senders = %s\n", | |
1550 | &acl_quote(&sort_address_list($main{"sender_reject_recipients"}, | |
1551 | "sender_reject_recipients"))) | |
1552 | if defined $main{"sender_reject_recipients"}; | |
1553 | ||
1554 | if (&bool("sender_verify")) | |
1555 | { | |
1556 | if (defined $main{"sender_verify_hosts_callback"} && | |
1557 | defined $main{"sender_verify_callback_domains"}) | |
1558 | { | |
1559 | printf STDOUT (" deny hosts = %s\n", | |
1560 | &acl_quote($main{"sender_verify_hosts_callback"})); | |
1561 | printf STDOUT (" sender_domains = %s\n", | |
1562 | &acl_quote($main{"sender_verify_callback_domains"})); | |
1563 | print STDOUT " !verify = sender/callout"; | |
1564 | print STDOUT "=$main{\"sender_verify_callback_timeout\"}" | |
1565 | if defined $main{"sender_verify_callback_timeout"}; | |
1566 | print STDOUT "\n"; | |
1567 | } | |
1568 | ||
1569 | if (defined $main{"sender_verify_hosts"}) | |
1570 | { | |
1571 | printf STDOUT (" deny hosts = %s\n", | |
1572 | &acl_quote($main{"sender_verify_hosts"})); | |
1573 | print STDOUT " !verify = sender\n"; | |
1574 | } | |
1575 | else | |
1576 | { | |
1577 | print STDOUT " require verify = sender\n"; | |
1578 | } | |
1579 | } | |
1580 | ||
1581 | if (&bool("receiver_verify")) | |
1582 | { | |
1583 | print STDOUT " deny message = unrouteable address\n"; | |
1584 | printf STDOUT (" recipients = %s\n", | |
1585 | &acl_quote(&sort_address_list($main{"receiver_verify_addresses"}, | |
1586 | "receiver_verify_addresses"))) | |
1587 | if defined $main{"receiver_verify_addresses"}; | |
1588 | printf STDOUT (" hosts = %s\n", | |
1589 | &acl_quote($main{"receiver_verify_hosts"})) | |
1590 | if defined $main{"receiver_verify_hosts"}; | |
1591 | printf STDOUT (" senders = %s\n", | |
1592 | &acl_quote(&sort_address_list($main{"receiver_verify_senders"}, | |
1593 | "receiver_verify_senders"))) | |
1594 | if defined $main{"receiver_verify_senders"}; | |
1595 | print STDOUT " !verify = recipient\n"; | |
1596 | } | |
1597 | ||
1598 | print STDOUT " accept domains = +local_domains\n" | |
1599 | if $local_domains !~ /^\s*$/; | |
1600 | ||
1601 | print STDOUT " accept domains = +relay_domains\n" | |
1602 | if $relay_domains !~ /^\s*$/; | |
1603 | ||
1604 | if (defined $main{"host_accept_relay"}) | |
1605 | { | |
1606 | if (defined $main{"sender_address_relay"}) | |
1607 | { | |
1608 | if (defined $main{"sender_address_relay_hosts"}) | |
1609 | { | |
1610 | printf STDOUT (" accept hosts = %s\n", | |
1611 | &acl_quote($main{"sender_address_relay_hosts"})); | |
1612 | print STDOUT " endpass\n"; | |
1613 | print STDOUT " message = invalid sender\n"; | |
1614 | printf STDOUT (" senders = %s\n", | |
1615 | &acl_quote(&sort_address_list($main{"sender_address_relay"}, | |
1616 | "sender_address_relay"))); | |
1617 | print STDOUT " accept hosts = +relay_hosts\n"; | |
1618 | } | |
1619 | else | |
1620 | { | |
1621 | print STDOUT " accept hosts = +relay_hosts\n"; | |
1622 | print STDOUT " endpass\n"; | |
1623 | print STDOUT " message = invalid sender\n"; | |
1624 | printf STDOUT (" senders = %s\n", | |
1625 | &acl_quote(&sort_address_list($main{"sender_address_relay"}, | |
1626 | "sender_address_relay"))); | |
1627 | } | |
1628 | } | |
1629 | else | |
1630 | { | |
1631 | print STDOUT " accept hosts = +relay_hosts\n"; | |
1632 | } | |
1633 | } | |
1634 | ||
1635 | print STDOUT " accept hosts = +auth_relay_hosts\n" . | |
1636 | " endpass\n" . | |
1637 | " message = authentication required\n" . | |
1638 | " authenticated = *\n" | |
1639 | if defined $main{"host_auth_accept_relay"}; | |
1640 | ||
1641 | print STDOUT " accept hosts = +tls_relay_hosts\n" . | |
1642 | " endpass\n" . | |
1643 | " message = encryption required\n" . | |
1644 | " encrypted = *\n" | |
1645 | if defined $main{"tls_host_accept_relay"}; | |
1646 | ||
1647 | print STDOUT " deny message = relay not permitted\n\n"; | |
1648 | ||
1649 | ||
1650 | # Output an ACL for use after the DATA command. This is concerned with | |
1651 | # header checking. | |
1652 | ||
1653 | print STDOUT "#!!# ACL that is used after the DATA command\n"; | |
1654 | print STDOUT "check_message:\n"; | |
1655 | ||
1656 | # Default for headers_checks_fail is true | |
1657 | ||
1658 | if (!defined $main{"headers_checks_fail"} || | |
1659 | $main{"headers_checks_fail"} eq "true") | |
1660 | { | |
1661 | print STDOUT " require verify = header_syntax\n" | |
1662 | if &bool("headers_check_syntax"); | |
1663 | print STDOUT " require verify = header_sender\n" | |
1664 | if &bool("headers_sender_verify"); | |
1665 | print STDOUT " accept senders = !:\n require verify = header_sender\n" | |
1666 | if &bool("headers_sender_verify_errmsg"); | |
1667 | } | |
1668 | else | |
1669 | { | |
1670 | print STDOUT " warn !verify = header_syntax\n" | |
1671 | if &bool("headers_check_syntax"); | |
1672 | print STDOUT " warn !verify = header_sender\n" | |
1673 | if &bool("headers_sender_verify"); | |
1674 | print STDOUT " accept senders = !:\n warn !verify = header_sender\n" | |
1675 | if &bool("headers_sender_verify_errmsg"); | |
1676 | } | |
1677 | ||
1678 | print STDOUT " accept\n\n"; | |
1679 | ||
1680 | ||
1681 | # Output an ACL for AUTH if required | |
1682 | ||
1683 | if (defined $main{"auth_over_tls_hosts"}) | |
1684 | { | |
1685 | print STDOUT "#!!# ACL that is used after the AUTH command\n" . | |
1686 | "check_auth:\n" . | |
1687 | " accept hosts = +auth_over_tls_hosts\n" . | |
1688 | " endpass\n" . | |
1689 | " message = STARTTLS required before AUTH\n" . | |
1690 | " encrypted = *\n" . | |
1691 | " accept\n"; | |
1692 | } | |
1693 | ||
1694 | ||
1695 | # Output ACLs for ETRN, EXPN, and VRFY if required | |
1696 | ||
1697 | if (defined $main{"smtp_etrn_hosts"}) | |
1698 | { | |
1699 | print STDOUT "#!!# ACL that is used after the ETRN command\n" . | |
1700 | "check_etrn:\n"; | |
1701 | print STDOUT " deny hosts = +auth_hosts\n" . | |
1702 | " message = authentication required\n" . | |
1703 | " !authenticated = *\n" | |
1704 | if defined $main{"auth_hosts"}; | |
1705 | print STDOUT " accept hosts = $main{\"smtp_etrn_hosts\"}\n\n"; | |
1706 | } | |
1707 | ||
1708 | if (defined $main{"smtp_expn_hosts"}) | |
1709 | { | |
1710 | print STDOUT "#!!# ACL that is used after the EXPN command\n" . | |
1711 | "check_expn:\n"; | |
1712 | print STDOUT " deny hosts = +auth_hosts\n" . | |
1713 | " message = authentication required\n" . | |
1714 | " !authenticated = *\n" | |
1715 | if defined $main{"auth_hosts"}; | |
1716 | print STDOUT " accept hosts = $main{\"smtp_expn_hosts\"}\n\n"; | |
1717 | } | |
1718 | ||
1719 | if (&bool("smtp_verify")) | |
1720 | { | |
1721 | print STDOUT "#!!# ACL that is used after the VRFY command\n" . | |
1722 | "check_vrfy:\n"; | |
1723 | print STDOUT " deny hosts = +auth_hosts\n" . | |
1724 | " message = authentication required\n" . | |
1725 | " !authenticated = *\n" | |
1726 | if defined $main{"auth_hosts"}; | |
1727 | print STDOUT " accept\n\n"; | |
1728 | } | |
1729 | ||
1730 | # -------- The authenticators -------- | |
1731 | ||
1732 | $started = 0; | |
1733 | for ($i = $auth_start; $i < $clen; $i++) | |
1734 | { | |
1735 | if (!$started) | |
1736 | { | |
1737 | if ($c[$i] !~ /^\s*(#|$)/) | |
1738 | { | |
1739 | print STDOUT "\nbegin authenticators\n\n"; | |
1740 | $started = 1; | |
1741 | } | |
1742 | } | |
1743 | print STDOUT "$c[$i]\n"; | |
1744 | } | |
1745 | ||
1746 | ||
1747 | # -------- Rewrite section -------- | |
1748 | ||
1749 | $started = 0; | |
1750 | for ($i = $rewrite_start; $i < $clen && $i < $auth_start - 1; $i++) | |
1751 | { | |
1752 | if (!$started) | |
1753 | { | |
1754 | if ($c[$i] !~ /^\s*(#|$)/) | |
1755 | { | |
1756 | print STDOUT "\nbegin rewrite\n\n"; | |
1757 | $started = 1; | |
1758 | } | |
1759 | } | |
1760 | &print_no_expand($c[$i]); | |
1761 | } | |
1762 | ||
1763 | ||
1764 | # -------- The routers configuration -------- | |
1765 | ||
1766 | # The new routers configuration is created out of the old directors and routers | |
1767 | # configuration. We put the old routers first, adding a "domains" option to | |
1768 | # any that don't have one, to make them select the domains that do not match | |
1769 | # the original local_domains. The routers get modified as necessary, and the | |
1770 | # final one has "no_more" set, unless it has conditions. In that case we have | |
1771 | # to add an extra router to be sure of failing all non-local addresses that | |
1772 | # fall through. We do this also if there are no routers at all. The old | |
1773 | # directors follow, modified as required. | |
1774 | ||
1775 | $prefix = "r."; | |
1776 | undef @comments; | |
1777 | ||
1778 | print STDOUT "\n"; | |
1779 | print STDOUT "#!!#######################################################!!#\n"; | |
1780 | print STDOUT "#!!# Here follow routers created from the old routers, #!!#\n"; | |
1781 | print STDOUT "#!!# for handling non-local domains. #!!#\n"; | |
1782 | print STDOUT "#!!#######################################################!!#\n"; | |
1783 | ||
1784 | print STDOUT "\nbegin routers\n\n"; | |
1785 | ||
1786 | for ($i = $router_start; $i < $clen; $i++) | |
1787 | { | |
1788 | $type = &checkline($c[$i]); | |
1789 | last if $type eq "end"; | |
1790 | ||
1791 | if ($type eq "comment") { push(@comments, "$c[$i]\n"); next; } | |
1792 | ||
1793 | # When we hit the start of a driver, modify its options as necessary, | |
1794 | # and then output it from the stored option settings, having first output | |
1795 | # and previous comments. | |
1796 | ||
1797 | if ($type eq "driver") | |
1798 | { | |
1799 | print STDOUT shift @comments while scalar(@comments) > 0; | |
1800 | ||
1801 | $hash = $driverlist{"$prefix$name"}; | |
1802 | $driver = $$hash{"driver"}; | |
1803 | print STDOUT "$name:\n"; | |
1804 | ||
1805 | $add_no_more = | |
1806 | ! defined $$hash{"domains"} && | |
1807 | ! defined $$hash{"local_parts"} && | |
1808 | ! defined $$hash{"senders"} && | |
1809 | ! defined $$hash{"condition"} && | |
1810 | ! defined $$hash{"require_files"} && | |
1811 | (!defined $$hash{"verify_only"} || $$hash{"verify_only"} eq "false") && | |
1812 | (!defined $$hash{"verify"} || $$hash{"verify"} eq "true"); | |
1813 | ||
1814 | # Create a "domains" setting if there isn't one, unless local domains | |
1815 | # was explicitly empty. | |
1816 | ||
1817 | $$hash{"domains"} = "! +local_domains" | |
1818 | if !defined $$hash{"domains"} && $local_domains !~ /^\s*$/; | |
1819 | ||
1820 | # If the router had a local_parts setting, add caseful_local_part | |
1821 | ||
1822 | $$hash{"caseful_local_part"} = "true" if defined $$hash{"local_parts"}; | |
1823 | ||
1824 | # If the router has "self=local" set, change it to "self=pass", and | |
1825 | # set pass_router to the router that was the first director. Change the | |
1826 | # obsolete self settings of "fail_hard" and "fail_soft" to "fail" and | |
1827 | # "pass". | |
1828 | ||
1829 | if (defined $$hash{"self"}) | |
1830 | { | |
1831 | if ($$hash{"self"} eq "local") | |
1832 | { | |
1833 | $$hash{"self"} = "pass"; | |
1834 | $$hash{"pass_router"} = $first_director; | |
1835 | } | |
1836 | elsif ($$hash{"self"} eq "fail_hard") | |
1837 | { | |
1838 | $$hash{"self"} = "fail"; | |
1839 | } | |
1840 | elsif ($$hash{"self"} eq "fail_soft") | |
1841 | { | |
1842 | $$hash{"self"} = "pass"; | |
1843 | } | |
1844 | } | |
1845 | ||
1846 | # If the router had a require_files setting, check it for user names | |
1847 | # and colons that are part of expansion items | |
1848 | ||
1849 | if (defined $$hash{"require_files"}) | |
1850 | { | |
1851 | &check_require($$hash{"require_files"}, "'$name' router"); | |
1852 | if (($$hash{"require_files"} =~ s/(\$\{\w+):/$1::/g) > 0 || | |
1853 | ($$hash{"require_files"} =~ s/ldap:/ldap::/g) > 0) | |
1854 | { | |
1855 | &rubric(); | |
1856 | print STDERR "\n" . | |
1857 | "*** A setting of require_files in the $name router contains\n" . | |
1858 | " a colon in what appears to be an expansion item. In Exim 3, the\n" . | |
1859 | " whole string was expanded before splitting the list, but in Exim 4\n" . | |
1860 | " each item is expanded separately, so colons that are not list\n" . | |
1861 | " item separators have to be doubled. One or more such colons in this\n" . | |
1862 | " list have been doubled as a precaution. Please check the result.\n"; | |
1863 | } | |
1864 | } | |
1865 | ||
1866 | # If the router had a "senders" setting, munge the address list | |
1867 | ||
1868 | $$hash{"senders"} = &sort_address_list($$hash{"senders"}, "senders") | |
1869 | if defined $$hash{"senders"}; | |
1870 | ||
1871 | # ---- Changes to domainlist router ---- | |
1872 | ||
1873 | if ($driver eq "domainlist") | |
1874 | { | |
1875 | &abolished($hash, "A domainlist router", | |
1876 | "modemask", "owners", "owngroups", | |
1877 | "qualify_single", "search_parents"); | |
1878 | ||
1879 | # The name has changed | |
1880 | ||
1881 | $$hash{"driver"} = "manualroute"; | |
1882 | ||
1883 | # Turn "route_file", "route_query" and "route_queries" into lookups for | |
1884 | # route_data. | |
1885 | ||
1886 | if (defined $$hash{"route_file"}) | |
1887 | { | |
1888 | $$hash{"route_data"} = "\${lookup\{\$domain\}$$hash{'search_type'}" . | |
1889 | "\{$$hash{'route_file'}\}\}"; | |
1890 | } | |
1891 | elsif (defined $$hash{"route_query"}) | |
1892 | { | |
1893 | $$hash{"route_data"} = "\${lookup $$hash{'search_type'}" . | |
1894 | "\{" . &unquote($$hash{'route_query'}) . "\}\}"; | |
1895 | } | |
1896 | elsif (defined $$hash{"route_queries"}) | |
1897 | { | |
1898 | $endkets = 0; | |
1899 | $$hash{"route_data"} = ""; | |
1900 | $route_queries = $$hash{'route_queries'}; | |
1901 | $route_queries =~ s/^"(.*)"$/$1/s; | |
1902 | $route_queries =~ s/::/++colons++/g; | |
1903 | @qq = split(/:/, $route_queries); | |
1904 | ||
1905 | foreach $q (@qq) | |
1906 | { | |
1907 | $q =~ s/\+\+colons\+\+/:/g; | |
1908 | $q =~ s/^\s+//; | |
1909 | $q =~ s/\s+$//; | |
1910 | if ($endkets > 0) | |
1911 | { | |
1912 | $$hash{"route_data"} .= "\\\n {"; | |
1913 | $endkets++; | |
1914 | } | |
1915 | $$hash{"route_data"} .= "\${lookup $$hash{'search_type'} \{$q\}\{\$value\}"; | |
1916 | $endkets++; | |
1917 | } | |
1918 | ||
1919 | $$hash{"route_data"} .= "}" x $endkets; | |
1920 | } | |
1921 | ||
1922 | delete $$hash{"route_file"}; | |
1923 | delete $$hash{"route_query"}; | |
1924 | delete $$hash{"route_queries"}; | |
1925 | delete $$hash{"search_type"}; | |
1926 | ||
1927 | # But we can't allow both route_data and route_list | |
1928 | ||
1929 | if (defined $$hash{"route_data"} && defined $$hash{"route_list"}) | |
1930 | { | |
1931 | &rubric(); | |
1932 | print STDERR "\n" . | |
1933 | "** An Exim 3 'domainlist' router called '$name' contained a 'route_list'\n" . | |
1934 | " option as well as a setting of 'route_file', 'route_query', or\n" . | |
1935 | " 'route_queries'. The latter has been turned into a 'route_data' setting,\n". | |
1936 | " but in Exim 4 you can't have both 'route_data' and 'route_list'. You'll\n" . | |
1937 | " have to rewrite this router; in the meantime, 'route_list' has been\n" . | |
1938 | " omitted.\n"; | |
1939 | print STDOUT "#!!# route_list option removed\n"; | |
1940 | delete $$hash{"route_list"}; | |
1941 | } | |
1942 | ||
1943 | # Change bydns_a into bydns in a route_list; also bydns_mx, but that | |
1944 | # works differently. | |
1945 | ||
1946 | if (defined $$hash{"route_list"}) | |
1947 | { | |
1948 | $$hash{"route_list"} =~ s/bydns_a/bydns/g; | |
1949 | if ($$hash{"route_list"} =~ /bydns_mx/) | |
1950 | { | |
1951 | $$hash{"route_list"} =~ s/bydns_mx/bydns/g; | |
1952 | &rubric(); | |
1953 | print STDERR "\n" . | |
1954 | "*** An Exim 3 'domainlist' router called '$name' contained a 'route_list'\n" . | |
1955 | " option which used 'bydns_mx'. This feature no longer exists in Exim 4.\n" . | |
1956 | " It has been changed to 'bydns', but it won't have the same effect,\n" . | |
1957 | " because it will look for A rather than MX records. Use the 'dnslookup'\n" . | |
1958 | " router to do MX lookups - if you want to override the hosts found from\n" . | |
1959 | " MX records, you should route to a special 'smtp' transport which has\n" . | |
1960 | " both 'hosts' and 'hosts_override' set.\n"; | |
1961 | } | |
1962 | } | |
1963 | ||
1964 | # Arrange to not expand regex | |
1965 | ||
1966 | $$hash{"route_list"} = &no_expand_regex($$hash{"route_list"}, ";") | |
1967 | if (defined $$hash{"route_list"}) | |
1968 | } | |
1969 | ||
1970 | ||
1971 | # ---- Changes to iplookup router ---- | |
1972 | ||
1973 | elsif ($driver eq "iplookup") | |
1974 | { | |
1975 | &renamed($hash, "service", "port"); | |
1976 | } | |
1977 | ||
1978 | ||
1979 | # ---- Changes to lookuphost router ---- | |
1980 | ||
1981 | elsif ($driver eq "lookuphost") | |
1982 | { | |
1983 | $$hash{"driver"} = "dnslookup"; | |
1984 | ||
1985 | if (defined $$hash{"gethostbyname"}) | |
1986 | { | |
1987 | &rubric(); | |
1988 | print STDERR "\n" . | |
1989 | "** An Exim 3 'lookuphost' router called '$name' used the 'gethostbyname'\n" . | |
1990 | " option, which no longer exists. You will have to rewrite it.\n"; | |
1991 | print STDOUT "#!!# gethostbyname option removed\n"; | |
1992 | delete $$hash{"gethostbyname"}; | |
1993 | } | |
1994 | ||
1995 | $$hash{"mx_domains"} = &no_expand_regex($$hash{"mx_domains"}) | |
1996 | if defined $$hash{"mx_domains"}; | |
1997 | } | |
1998 | ||
1999 | ||
2000 | # ---- Changes to the queryprogram router ---- | |
2001 | ||
2002 | elsif ($driver eq "queryprogram") | |
2003 | { | |
2004 | &rubric(); | |
2005 | print STDERR "\n" . | |
2006 | "** The configuration contains a 'queryprogram' router. Please note that\n" . | |
2007 | " the specification for the text that is returned by the program run\n" . | |
2008 | " by this router has changed in Exim 4. You will need to modify your\n" . | |
2009 | " program.\n"; | |
2010 | ||
2011 | if (!defined $$hash{'command_user'}) | |
2012 | { | |
2013 | &rubric(); | |
2014 | print STDERR "\n" . | |
2015 | "** The 'queryprogram' router called '$name' does not have a setting for\n" . | |
2016 | " the 'command_user' option. This is mandatory in Exim 4. A setting of\n" . | |
2017 | " 'nobody' has been created.\n"; | |
2018 | $$hash{"command_user"} = "nobody"; | |
2019 | } | |
2020 | } | |
2021 | ||
2022 | ||
2023 | # ------------------------------------- | |
2024 | ||
2025 | # Output the router's option settings | |
2026 | ||
2027 | &outdriver($hash); | |
2028 | next; | |
2029 | } | |
2030 | ||
2031 | # Skip past any continuation lines for an option setting | |
2032 | while ($c[$i] =~ /\\\s*$/s && $i < $clen - 1) | |
2033 | { | |
2034 | $i++; | |
2035 | $i++ while ($c[$i] =~ /^\s*#/); | |
2036 | } | |
2037 | } | |
2038 | ||
2039 | # Add "no_more" to the final driver from the old routers, provided it had no | |
2040 | # conditions. Otherwise, or if there were no routers, make up one to fail all | |
2041 | # non-local domains. | |
2042 | ||
2043 | if ($add_no_more) | |
2044 | { | |
2045 | print STDOUT " no_more\n"; | |
2046 | print STDOUT shift @comments while scalar(@comments) > 0; | |
2047 | } | |
2048 | else | |
2049 | { | |
2050 | print STDOUT shift @comments while scalar(@comments) > 0; | |
2051 | print STDOUT "\n#!!# This new router is put here to fail all domains that\n"; | |
2052 | print STDOUT "#!!# were not in local_domains in the Exim 3 configuration.\n\n"; | |
2053 | print STDOUT "fail_remote_domains:\n"; | |
2054 | print STDOUT " driver = redirect\n"; | |
2055 | print STDOUT " domains = ! +local_domains\n"; | |
2056 | print STDOUT " allow_fail\n"; | |
2057 | print STDOUT " data = :fail: unrouteable mail domain \"\$domain\"\n\n"; | |
2058 | } | |
2059 | ||
2060 | # Now copy the directors, making appropriate changes | |
2061 | ||
2062 | print STDOUT "\n"; | |
2063 | print STDOUT "#!!#######################################################!!#\n"; | |
2064 | print STDOUT "#!!# Here follow routers created from the old directors, #!!#\n"; | |
2065 | print STDOUT "#!!# for handling local domains. #!!#\n"; | |
2066 | print STDOUT "#!!#######################################################!!#\n"; | |
2067 | ||
2068 | $prefix = "d."; | |
2069 | for ($i = $director_start; $i < $clen; $i++) | |
2070 | { | |
2071 | $type = &checkline($c[$i]); | |
2072 | last if $type eq "end"; | |
2073 | ||
2074 | if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; } | |
2075 | ||
2076 | undef $second_router; | |
2077 | ||
2078 | if ($type eq "driver") | |
2079 | { | |
2080 | $hash = $driverlist{"$prefix$name"}; | |
2081 | $driver = $$hash{"driver"}; | |
2082 | print STDOUT "$name:\n"; | |
2083 | ||
2084 | $$hash{"caseful_local_part"} = "true" if $add_caseful_local_part; | |
2085 | ||
2086 | if (defined $$hash{"local_parts"} && | |
2087 | (defined $$hash{"prefix"} || defined $hash{"suffix"})) | |
2088 | { | |
2089 | &rubric(); | |
2090 | print STDERR "\n" . | |
2091 | "** The Exim 3 configuration contains a director called '$name' which has\n" . | |
2092 | " 'local_parts' set, together with either or both of 'prefix' and 'suffix'\n". | |
2093 | " This combination has a different effect in Exim 4, where the affix\n" . | |
2094 | " is removed *before* 'local_parts' is tested. You will probably need\n" . | |
2095 | " to make changes to this driver.\n"; | |
2096 | } | |
2097 | ||
2098 | &renamed($hash, "prefix", "local_part_prefix"); | |
2099 | &renamed($hash, "prefix_optional", "local_part_prefix_optional"); | |
2100 | &renamed($hash, "suffix", "local_part_suffix"); | |
2101 | &renamed($hash, "suffix_optional", "local_part_suffix_optional"); | |
2102 | &renamed($hash, "new_director", "redirect_router"); | |
2103 | ||
2104 | &handle_current_and_home_directory($hash, $driver, $name); | |
2105 | ||
2106 | # If the director had a require_files setting, check it for user names | |
2107 | # and colons that are part of expansion items | |
2108 | ||
2109 | if (defined $$hash{"require_files"}) | |
2110 | { | |
2111 | &check_require($$hash{"require_files"}, "'$name' director"); | |
2112 | if (($$hash{"require_files"} =~ s/(\$\{\w+):/$1::/g) > 0 || | |
2113 | ($$hash{"require_files"} =~ s/ldap:/ldap::/g) > 0) | |
2114 | { | |
2115 | &rubric(); | |
2116 | print STDERR "\n" . | |
2117 | "*** A setting of require_files in the $name director contains\n" . | |
2118 | " a colon in what appears to be an expansion item. In Exim 3, the\n" . | |
2119 | " whole string was expanded before splitting the list, but in Exim 4\n" . | |
2120 | " each item is expanded separately, so colons that are not list\n" . | |
2121 | " item separators have to be doubled. One or more such colons in this\n" . | |
2122 | " list have been doubled as a precaution. Please check the result.\n"; | |
2123 | } | |
2124 | } | |
2125 | ||
2126 | # If the director had a "senders" setting, munge the address list | |
2127 | ||
2128 | $$hash{"senders"} = &sort_address_list($$hash{"senders"}, "senders") | |
2129 | if defined $$hash{"senders"}; | |
2130 | ||
2131 | # ---- Changes to aliasfile director ---- | |
2132 | ||
2133 | if ($driver eq "aliasfile") | |
2134 | { | |
2135 | &abolished($hash, "An aliasfile director", | |
2136 | "directory2_transport", "freeze_missing_include", | |
2137 | "modemask", "owners", "owngroups"); | |
2138 | ||
2139 | $$hash{"driver"} = "redirect"; | |
2140 | ||
2141 | $key = "\$local_part"; | |
2142 | $key = "\$local_part\@\$domain" | |
2143 | if defined $$hash{"include_domain"} && | |
2144 | $$hash{"include_domain"} eq "true"; | |
2145 | delete $$hash{"include_domain"}; | |
2146 | ||
2147 | if (defined $$hash{"forbid_special"} && $$hash{"forbid_special"} eq "true") | |
2148 | { | |
2149 | $$hash{"forbid_blackhole"} = "true"; | |
2150 | } | |
2151 | else | |
2152 | { | |
2153 | $$hash{"allow_defer"} = "true"; | |
2154 | $$hash{"allow_fail"} = "true"; | |
2155 | } | |
2156 | delete $$hash{"forbid_special"}; | |
2157 | ||
2158 | # Deal with "file", "query", or "queries" | |
2159 | ||
2160 | if (defined $$hash{"file"}) | |
2161 | { | |
2162 | $$hash{"data"} = | |
2163 | "\$\{lookup\{$key\}$$hash{'search_type'}\{$$hash{'file'}\}\}"; | |
2164 | if (defined $$hash{"optional"} && $$hash{"optional"} eq "true") | |
2165 | { | |
2166 | $$hash{"data"} = | |
2167 | "\$\{if exists\{$$hash{'file'}\}\{$$hash{'data'}\}\}"; | |
2168 | } | |
2169 | delete $$hash{"optional"}; | |
2170 | } | |
2171 | elsif (defined $$hash{"query"}) | |
2172 | { | |
2173 | &abolished($hash, "An aliasfile director", "optional"); | |
2174 | $$hash{"data"} = "\${lookup $$hash{'search_type'} " . | |
2175 | "\{" . &unquote($$hash{'query'}) . "\}\}"; | |
2176 | } | |
2177 | else # Must be queries | |
2178 | { | |
2179 | &abolished($hash, "An aliasfile director", "optional"); | |
2180 | $endkets = 0; | |
2181 | $$hash{"data"} = ""; | |
2182 | $queries = $$hash{'queries'}; | |
2183 | $queries =~ s/^"(.*)"$/$1/s; | |
2184 | $queries =~ s/::/++colons++/g; | |
2185 | @qq = split(/:/, $queries); | |
2186 | ||
2187 | foreach $q (@qq) | |
2188 | { | |
2189 | $q =~ s/\+\+colons\+\+/:/g; | |
2190 | $q =~ s/^\s+//; | |
2191 | $q =~ s/\s+$//; | |
2192 | if ($endkets > 0) | |
2193 | { | |
2194 | $$hash{"data"} .= "\\\n {"; | |
2195 | $endkets++; | |
2196 | } | |
2197 | $$hash{"data"} .= "\${lookup $$hash{'search_type'} \{$q\}\{\$value\}"; | |
2198 | $endkets++; | |
2199 | } | |
2200 | ||
2201 | $$hash{"data"} .= "}" x $endkets; | |
2202 | } | |
2203 | ||
2204 | $$hash{"data"} = "\${expand:$$hash{'data'}\}" | |
2205 | if (defined $$hash{"expand"} && $$hash{"expand"} eq "true"); | |
2206 | ||
2207 | delete $$hash{"expand"}; | |
2208 | delete $$hash{"file"}; | |
2209 | delete $$hash{"query"}; | |
2210 | delete $$hash{"queries"}; | |
2211 | delete $$hash{"search_type"}; | |
2212 | ||
2213 | # Turn aliasfile + transport into accept + condition | |
2214 | ||
2215 | if (defined $$hash{'transport'}) | |
2216 | { | |
2217 | &rubric(); | |
2218 | if (!defined $$hash{'condition'}) | |
2219 | { | |
2220 | print STDERR "\n" . | |
2221 | "** The Exim 3 configuration contains an aliasfile director called '$name',\n". | |
2222 | " which has 'transport' set. This has been turned into an 'accept' router\n". | |
2223 | " with a 'condition' setting, but should be carefully checked.\n"; | |
2224 | $$hash{'driver'} = "accept"; | |
2225 | $$hash{'condition'} = | |
2226 | "\$\{if eq \{\}\{$$hash{'data'}\}\{no\}\{yes\}\}"; | |
2227 | delete $$hash{'data'}; | |
2228 | delete $$hash{'allow_defer'}; | |
2229 | delete $$hash{'allow_fail'}; | |
2230 | } | |
2231 | else | |
2232 | { | |
2233 | print STDERR "\n" . | |
2234 | "** The Exim 3 configuration contains an aliasfile director called '$name',\n". | |
2235 | " which has 'transport' set. This cannot be turned into an 'accept' router\n". | |
2236 | " with a 'condition' setting, because there is already a 'condition'\n" . | |
2237 | " setting. It has been left as 'redirect' with a transport, which is\n" . | |
2238 | " invalid - you must sort this one out.\n"; | |
2239 | } | |
2240 | } | |
2241 | } | |
2242 | ||
2243 | ||
2244 | # ---- Changes to forwardfile director ---- | |
2245 | ||
2246 | elsif ($driver eq "forwardfile") | |
2247 | { | |
2248 | &abolished($hash, "A forwardfile director", | |
2249 | "check_group", "directory2_transport", | |
2250 | "freeze_missing_include", "match_directory", | |
2251 | "seteuid"); | |
2252 | ||
2253 | &renamed($hash, "filter", "allow_filter"); | |
2254 | ||
2255 | $$hash{"driver"} = "redirect"; | |
2256 | $$hash{"check_local_user"} = "true" | |
2257 | if !defined $$hash{"check_local_user"}; | |
2258 | ||
2259 | if (defined $$hash{"forbid_pipe"} && $$hash{"forbid_pipe"} eq "true") | |
2260 | { | |
2261 | print STDOUT "#!!# forbid_filter_run added because forbid_pipe is set\n"; | |
2262 | $$hash{"forbid_filter_run"} = "true"; | |
2263 | } | |
2264 | ||
2265 | if (defined $$hash{'allow_system_actions'} && | |
2266 | $$hash{'allow_system_actions'} eq 'true') | |
2267 | { | |
2268 | $$hash{'allow_freeze'} = "true"; | |
2269 | } | |
2270 | delete $$hash{'allow_system_actions'}; | |
2271 | ||
2272 | # If file_directory is defined, use it to qualify relative paths; if not, | |
2273 | # and check_local_user is defined, use $home. Remove file_directory from | |
2274 | # the output. | |
2275 | ||
2276 | $dir = ""; | |
2277 | if (defined $$hash{"file_directory"}) | |
2278 | { | |
2279 | $dir = $$hash{"file_directory"} . "/"; | |
2280 | delete $$hash{"file_directory"}; | |
2281 | } | |
2282 | elsif ($$hash{"check_local_user"} eq "true") | |
2283 | { | |
2284 | $dir = "\$home/"; | |
2285 | } | |
2286 | ||
2287 | # If it begins with an upper case letter, guess that this is really | |
2288 | # a macro. | |
2289 | ||
2290 | if (defined $$hash{"file"} && $$hash{"file"} !~ /^[\/A-Z]/) | |
2291 | { | |
2292 | $$hash{"file"} = $dir . $$hash{"file"}; | |
2293 | } | |
2294 | } | |
2295 | ||
2296 | ||
2297 | # ---- Changes to localuser director ---- | |
2298 | ||
2299 | elsif ($driver eq "localuser") | |
2300 | { | |
2301 | &abolished($hash, "A localuser director", "match_directory"); | |
2302 | $$hash{"driver"} = "accept"; | |
2303 | $$hash{"check_local_user"} = "true"; | |
2304 | } | |
2305 | ||
2306 | ||
2307 | # ---- Changes to smartuser director ---- | |
2308 | ||
2309 | elsif ($driver eq "smartuser") | |
2310 | { | |
2311 | &abolished($hash, "A smartuser director", "panic_expansion_fail"); | |
2312 | ||
2313 | $transport = $$hash{"transport"}; | |
2314 | $new_address = $$hash{"new_address"}; | |
2315 | ||
2316 | if (defined $transport && defined $new_address) | |
2317 | { | |
2318 | &rubric(); | |
2319 | print STDERR "\n" . | |
2320 | "** The Exim 3 configuration contains a smartuser director called '$name',\n". | |
2321 | " which has both 'transport' and 'new_address' set. This has been turned\n". | |
2322 | " into two routers for Exim 4. However, if the new address contains a\n" . | |
2323 | " reference to \$local_part, this won't work correctly. In any case, you\n". | |
2324 | " may be able to make it tidier by rewriting.\n"; | |
2325 | $$hash{"driver"} = "redirect"; | |
2326 | $$hash{"data"} = $new_address; | |
2327 | $$hash{"redirect_router"} = "${name}_part2"; | |
2328 | ||
2329 | $second_router = "\n". | |
2330 | "#!!# This router is invented to go with the previous one because\n". | |
2331 | "#!!# in Exim 4 you can't have a change of address and a transport\n". | |
2332 | "#!!# setting in the same router as you could in Exim 3.\n\n" . | |
2333 | "${name}_part2:\n". | |
2334 | " driver = accept\n". | |
2335 | " condition = \$\{if eq\{\$local_part@\$domain\}" . | |
2336 | "\{$new_address\}\{yes\}\{no\}\}\n". | |
2337 | " transport = $$hash{'transport'}\n"; | |
2338 | ||
2339 | delete $$hash{"new_address"}; | |
2340 | delete $$hash{"transport"}; | |
2341 | } | |
2342 | elsif (defined $new_address) | |
2343 | { | |
2344 | $$hash{"driver"} = "redirect"; | |
2345 | $$hash{"data"} = $new_address; | |
2346 | $$hash{"allow_defer"} = "true"; | |
2347 | $$hash{"allow_fail"} = "true"; | |
2348 | delete $$hash{"new_address"}; | |
2349 | } | |
2350 | else # Includes the case of neither set (verify_only) | |
2351 | { | |
2352 | $$hash{"driver"} = "accept"; | |
2353 | if (defined $$hash{"rewrite"}) | |
2354 | { | |
2355 | &rubric(); | |
2356 | print STDERR "\n" . | |
2357 | "** The Exim 3 configuration contains a setting of the 'rewrite' option on\n". | |
2358 | " a smartuser director called '$name', but this director does not have\n". | |
2359 | " a setting of 'new_address', so 'rewrite' has no effect. The director\n". | |
2360 | " has been turned into an 'accept' router, and 'rewrite' has been discarded."; | |
2361 | delete $$hash{"rewrite"}; | |
2362 | } | |
2363 | } | |
2364 | } | |
2365 | ||
2366 | ||
2367 | # ------------------------------------- | |
2368 | ||
2369 | # For ex-directors that don't have check_local_user set, add | |
2370 | # retry_use_local_part to imitate what Exim 3 would have done. | |
2371 | ||
2372 | $$hash{"retry_use_local_part"} = "true" | |
2373 | if (!defined $$hash{"check_local_user"} || | |
2374 | $$hash{"check_local_user"} eq "false") ; | |
2375 | ||
2376 | # Output the router's option settings | |
2377 | ||
2378 | &outdriver($hash); | |
2379 | ||
2380 | # Output an auxiliary router if one is needed | |
2381 | ||
2382 | print STDOUT $second_router if defined $second_router; | |
2383 | ||
2384 | next; | |
2385 | } | |
2386 | ||
2387 | # Skip past any continuation lines for an option setting | |
2388 | while ($c[$i] =~ /\\\s*$/s) | |
2389 | { | |
2390 | $i++; | |
2391 | $i++ while ($c[$i] =~ /^\s*#/); | |
2392 | } | |
2393 | } | |
2394 | ||
2395 | ||
2396 | ||
2397 | # -------- The transports configuration -------- | |
2398 | ||
2399 | $started = 0; | |
2400 | $prefix = "t."; | |
2401 | for ($i = $transport_start; $i < $clen; $i++) | |
2402 | { | |
2403 | $type = &checkline($c[$i]); | |
2404 | last if $type eq "end"; | |
2405 | ||
2406 | if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; } | |
2407 | ||
2408 | if (!$started) | |
2409 | { | |
2410 | print STDOUT "begin transports\n\n"; | |
2411 | $started = 1; | |
2412 | } | |
2413 | ||
2414 | if ($type eq "driver") | |
2415 | { | |
2416 | $hash = $driverlist{"$prefix$name"}; | |
2417 | $driver = $$hash{"driver"}; | |
2418 | print STDOUT "$name:\n"; | |
2419 | ||
2420 | # ---- Changes to the appendfile transport ---- | |
2421 | ||
2422 | if ($driver eq "appendfile") | |
2423 | { | |
2424 | &renamed($hash, "prefix", "message_prefix"); | |
2425 | &renamed($hash, "suffix", "message_suffix"); | |
2426 | &abolished($hash, "An appendfile transport", | |
2427 | "require_lockfile"); | |
2428 | &handle_batch_and_bsmtp($hash); | |
2429 | if (defined $$hash{"from_hack"} && $$hash{"from_hack"} eq "false") | |
2430 | { | |
2431 | print STDOUT "#!!# no_from_hack replaced by check_string\n"; | |
2432 | $$hash{"check_string"} = ""; | |
2433 | } | |
2434 | delete $$hash{"from_hack"}; | |
2435 | } | |
2436 | ||
2437 | # ---- Changes to the lmtp transport ---- | |
2438 | ||
2439 | elsif ($driver eq "lmtp") | |
2440 | { | |
2441 | if (defined $$hash{"batch"} && $$hash{"batch"} ne "none") | |
2442 | { | |
2443 | $$hash{"batch_max"} = "100" if !defined $$hash{"batch_max"}; | |
2444 | $$hash{"batch_id"} = "\$domain" if $$hash{"batch"} eq "domain"; | |
2445 | } | |
2446 | else | |
2447 | { | |
2448 | $$hash{"batch_max"} = "1" if defined $$hash{"batch_max"}; | |
2449 | } | |
2450 | delete $$hash{"batch"}; | |
2451 | } | |
2452 | ||
2453 | # ---- Changes to the pipe transport ---- | |
2454 | ||
2455 | elsif ($driver eq "pipe") | |
2456 | { | |
2457 | &renamed($hash, "prefix", "message_prefix"); | |
2458 | &renamed($hash, "suffix", "message_suffix"); | |
2459 | &handle_batch_and_bsmtp($hash); | |
2460 | if (defined $$hash{"from_hack"} && $$hash{"from_hack"} eq "false") | |
2461 | { | |
2462 | print STDOUT "#!!# no_from_hack replaced by check_string\n"; | |
2463 | $$hash{"check_string"} = ""; | |
2464 | } | |
2465 | delete $$hash{"from_hack"}; | |
2466 | } | |
2467 | ||
2468 | # ---- Changes to the smtp transport ---- | |
2469 | ||
2470 | elsif ($driver eq "smtp") | |
2471 | { | |
2472 | &abolished($hash, "An smtp transport", "mx_domains"); | |
2473 | &renamed($hash, "service", "port"); | |
2474 | &renamed($hash, "tls_verify_ciphers", "tls_require_ciphers"); | |
2475 | &renamed($hash, "authenticate_hosts", "hosts_try_auth"); | |
2476 | ||
2477 | if (defined $$hash{"batch_max"}) | |
2478 | { | |
2479 | print STDOUT "#!!# batch_max renamed connection_max_messages\n"; | |
2480 | $$hash{"connection_max_messages"} = $$hash{"batch_max"}; | |
2481 | delete $$hash{"batch_max"}; | |
2482 | } | |
2483 | ||
2484 | foreach $o ("hosts_try_auth", "hosts_avoid_tls", "hosts_require_tls", | |
2485 | "mx_domains", "serialize_hosts") | |
2486 | { | |
2487 | $$hash{$o} = &no_expand_regex($$hash{$o}) if defined $$hash{$o}; | |
2488 | } | |
2489 | } | |
2490 | ||
2491 | &outdriver($driverlist{"$prefix$name"}); | |
2492 | next; | |
2493 | } | |
2494 | ||
2495 | # Skip past any continuation lines for an option setting | |
2496 | while ($c[$i] =~ /\\\s*$/s) | |
2497 | { | |
2498 | $i++; | |
2499 | $i++ while ($c[$i] =~ /^\s*#/); | |
2500 | } | |
2501 | } | |
2502 | ||
2503 | ||
2504 | # -------- The retry configuration -------- | |
2505 | ||
2506 | $started = 0; | |
2507 | for ($i = $retry_start; $i < $clen && $i < $rewrite_start - 1; $i++) | |
2508 | { | |
2509 | if (!$started) | |
2510 | { | |
2511 | if ($c[$i] !~ /^\s*(#|$)/) | |
2512 | { | |
2513 | print STDOUT "\nbegin retry\n\n"; | |
2514 | $started = 1; | |
2515 | } | |
2516 | } | |
2517 | &print_no_expand($c[$i]); | |
2518 | } | |
2519 | ||
2520 | print STDOUT "\n# End of Exim 4 configuration\n"; | |
2521 | ||
2522 | print STDERR "\n*******************************************************\n"; | |
2523 | print STDERR "***** Please review the generated file carefully. *****\n"; | |
2524 | print STDERR "*******************************************************\n\n"; | |
2525 | ||
2526 | # End of convert4r4 | |
2527 |