X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/69358f0206debf14a18c7e798e23133d304232b6..8e669ac162fe3b1040297f1d021de10778dce9d9:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index c8d1917a4..214427bf5 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/exim.c,v 1.5 2004/10/19 11:04:26 ph10 Exp $ */ +/* $Cambridge: exim/src/src/exim.c,v 1.14 2005/02/17 11:58:26 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2004 */ +/* Copyright (c) University of Cambridge 1995 - 2005 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -196,9 +196,9 @@ os_non_restarting_signal(SIGALRM, sigalrm_handler); /* This function is called by millisleep() and exim_wait_tick() to wait for a period of time that may include a fraction of a second. The coding is somewhat -tedious. We do not expect setitimer() ever to fail, but if it does, the process -will wait for ever, so we panic in this instance. (There was a case of this -when a bug in a function that calls milliwait() caused it to pass invalid data. +tedious. We do not expect setitimer() ever to fail, but if it does, the process +will wait for ever, so we panic in this instance. (There was a case of this +when a bug in a function that calls milliwait() caused it to pass invalid data. That's when I added the check. :-) Argument: an itimerval structure containing the interval @@ -214,8 +214,8 @@ sigset_t old_sigmask; (void)sigaddset(&sigmask, SIGALRM); /* Add SIGALRM */ (void)sigprocmask(SIG_BLOCK, &sigmask, &old_sigmask); /* Block SIGALRM */ if (setitimer(ITIMER_REAL, itval, NULL) < 0) /* Start timer */ - log_write(0, LOG_MAIN|LOG_PANIC_DIE, - "setitimer() failed: %s", strerror(errno)); + log_write(0, LOG_MAIN|LOG_PANIC_DIE, + "setitimer() failed: %s", strerror(errno)); (void)sigfillset(&sigmask); /* All signals */ (void)sigdelset(&sigmask, SIGALRM); /* Remove SIGALRM */ (void)sigsuspend(&sigmask); /* Until SIGALRM */ @@ -599,7 +599,7 @@ static int check_port(uschar *address) { int port = host_extract_port(address); -if (!string_is_ip_address(address, NULL)) +if (string_is_ip_address(address, NULL) == 0) { fprintf(stderr, "exim abandoned: \"%s\" is not an IP address\n", address); exit(EXIT_FAILURE); @@ -622,7 +622,7 @@ Arguments: flags flag bits for verify_address() exit_value to be set for failures -Returns: nothint +Returns: nothing */ static void @@ -640,7 +640,7 @@ if (address == NULL) else { int rc = verify_address(deliver_make_addr(address,TRUE), stdout, flags, -1, - -1, NULL, NULL, NULL); + -1, -1, NULL, NULL, NULL); if (rc == FAIL) *exit_value = 2; else if (rc == DEFER && *exit_value == 0) *exit_value = 1; } @@ -839,6 +839,21 @@ fprintf(f, "Support for:"); fprintf(f, " OpenSSL"); #endif #endif +#ifdef WITH_CONTENT_SCAN + fprintf(f, " Content_Scanning"); +#endif +#ifdef WITH_OLD_DEMIME + fprintf(f, " Old_Demime"); +#endif +#ifdef EXPERIMENTAL_SPF + fprintf(f, " Experimental_SPF"); +#endif +#ifdef EXPERIMENTAL_SRS + fprintf(f, " Experimental_SRS"); +#endif +#ifdef EXPERIMENTAL_BRIGHTMAIL + fprintf(f, " Experimental_Brightmail"); +#endif fprintf(f, "\n"); fprintf(f, "Lookups:"); @@ -1169,7 +1184,8 @@ uschar **argv = USS cargv; int arg_receive_timeout = -1; int arg_smtp_receive_timeout = -1; int arg_error_handling = error_handling; -int filter_fd = -1; +int filter_sfd = -1; +int filter_ufd = -1; int group_count; int i; int list_queue_option = 0; @@ -1215,7 +1231,6 @@ uschar *ftest_prefix = NULL; uschar *ftest_suffix = NULL; uschar *real_sender_address; uschar *originator_home = US"/"; -BOOL ftest_system = FALSE; void *reset_point; struct passwd *pw; @@ -1581,20 +1596,32 @@ for (i = 1; i < argc; i++) else if (*argrest == 'e') expansion_test = checking = TRUE; - /* -bf: Run in mail filter testing mode - -bF: Ditto, but for system filters + /* -bF: Run system filter test */ + + else if (*argrest == 'F') + { + filter_test |= FTEST_SYSTEM; + if (*(++argrest) != 0) { badarg = TRUE; break; } + if (++i < argc) filter_test_sfile = argv[i]; else + { + fprintf(stderr, "exim: file name expected after %s\n", argv[i-1]); + exit(EXIT_FAILURE); + } + } + + /* -bf: Run user filter test -bfd: Set domain for filter testing -bfl: Set local part for filter testing -bfp: Set prefix for filter testing -bfs: Set suffix for filter testing */ - else if (*argrest == 'f' || *argrest == 'F') + else if (*argrest == 'f') { - ftest_system = *argrest++ == 'F'; - if (*argrest == 0) + if (*(++argrest) == 0) { - if(++i < argc) filter_test = argv[i]; else + filter_test |= FTEST_USER; + if (++i < argc) filter_test_ufile = argv[i]; else { fprintf(stderr, "exim: file name expected after %s\n", argv[i-1]); exit(EXIT_FAILURE); @@ -1863,7 +1890,8 @@ for (i = 1; i < argc; i++) break; /* -d: Set debug level (see also -v below) or set the drop_cr option. - The latter is now a no-opt, retained for compatibility only. */ + The latter is now a no-op, retained for compatibility only. If -dd is used, + debugging subprocesses of the daemon is disabled. */ case 'd': if (Ustrcmp(argrest, "ropcr") == 0) @@ -1879,6 +1907,11 @@ for (i = 1; i < argc; i++) unsigned int selector = D_default; debug_selector = 0; debug_file = NULL; + if (*argrest == 'd') + { + debug_daemon = TRUE; + argrest++; + } if (*argrest != 0) decode_bits(&selector, NULL, argrest, debug_options, debug_options_count, US"debug"); @@ -2755,7 +2788,7 @@ if (( (smtp_input || extract_recipients || recipients_arg < argc) && (daemon_listen || queue_interval >= 0 || bi_option || test_retry_arg >= 0 || test_rewrite_arg >= 0 || - filter_test != NULL || (msg_action_arg > 0 && !one_msg_action)) + filter_test != FTEST_NONE || (msg_action_arg > 0 && !one_msg_action)) ) || ( msg_action_arg > 0 && @@ -2773,19 +2806,19 @@ if (( ( list_options && (checking || smtp_input || extract_recipients || - filter_test != NULL || bi_option) + filter_test != FTEST_NONE || bi_option) ) || ( verify_address_mode && (address_test_mode || smtp_input || extract_recipients || - filter_test != NULL || bi_option) + filter_test != FTEST_NONE || bi_option) ) || ( address_test_mode && (smtp_input || extract_recipients || - filter_test != NULL || bi_option) + filter_test != FTEST_NONE || bi_option) ) || ( - smtp_input && (sender_address != NULL || filter_test != NULL || + smtp_input && (sender_address != NULL || filter_test != FTEST_NONE || extract_recipients) ) || ( @@ -2837,21 +2870,21 @@ else strerror(errno)); rlp.rlim_cur = rlp.rlim_max = 0; } - - /* I originally chose 1000 as a nice big number that was unlikely to + + /* I originally chose 1000 as a nice big number that was unlikely to be exceeded. It turns out that some older OS have a fixed upper limit of 256. */ - + if (rlp.rlim_cur < 1000) { rlp.rlim_cur = rlp.rlim_max = 1000; if (setrlimit(RLIMIT_NOFILE, &rlp) < 0) - { + { rlp.rlim_cur = rlp.rlim_max = 256; if (setrlimit(RLIMIT_NOFILE, &rlp) < 0) log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NOFILE) failed: %s", strerror(errno)); - } + } } #endif @@ -2945,7 +2978,7 @@ if (( /* EITHER */ ) || /* OR */ expansion_test /* expansion testing */ || /* OR */ - filter_test != NULL) /* Filter testing */ + filter_test != FTEST_NONE) /* Filter testing */ { setgroups(group_count, group_list); exim_setugid(real_uid, real_gid, FALSE, @@ -2968,15 +3001,26 @@ privileged user. */ else exim_setugid(geteuid(), getegid(), FALSE, US"forcing real = effective"); -/* If testing a filter, open the file now, before wasting time doing other +/* If testing a filter, open the file(s) now, before wasting time doing other setups and reading the message. */ -if (filter_test != NULL) +if ((filter_test & FTEST_SYSTEM) != 0) + { + filter_sfd = Uopen(filter_test_sfile, O_RDONLY, 0); + if (filter_sfd < 0) + { + fprintf(stderr, "exim: failed to open %s: %s\n", filter_test_sfile, + strerror(errno)); + return EXIT_FAILURE; + } + } + +if ((filter_test & FTEST_USER) != 0) { - filter_fd = Uopen(filter_test, O_RDONLY,0); - if (filter_fd < 0) + filter_ufd = Uopen(filter_test_ufile, O_RDONLY, 0); + if (filter_ufd < 0) { - fprintf(stderr, "exim: failed to open %s: %s\n", filter_test, + fprintf(stderr, "exim: failed to open %s: %s\n", filter_test_ufile, strerror(errno)); return EXIT_FAILURE; } @@ -3371,11 +3415,11 @@ if (real_uid != root_uid && real_uid != exim_uid && } /* If the caller is not trusted, certain arguments are ignored when running for -real, but are permitted when checking things (-be, -bv, -bt, -bh, -bf). Note -that authority for performing certain actions on messages is tested in the +real, but are permitted when checking things (-be, -bv, -bt, -bh, -bf, -bF). +Note that authority for performing certain actions on messages is tested in the queue_action() function. */ -if (!trusted_caller && !checking && filter_test == NULL) +if (!trusted_caller && !checking && filter_test == FTEST_NONE) { sender_host_name = sender_host_address = interface_address = sender_ident = received_protocol = NULL; @@ -3772,7 +3816,7 @@ for (i = 0;;) if (originator_name == NULL) { if (sender_address == NULL || - (!trusted_caller && filter_test == NULL)) + (!trusted_caller && filter_test == FTEST_NONE)) { uschar *name = US pw->pw_gecos; uschar *amp = Ustrchr(name, '&'); @@ -3906,7 +3950,7 @@ unless a trusted caller supplies a sender address with -f, or is passing in the message via SMTP (inetd invocation or otherwise). */ if ((sender_address == NULL && !smtp_input) || - (!trusted_caller && filter_test == NULL)) + (!trusted_caller && filter_test == FTEST_NONE)) { sender_local = TRUE; @@ -3937,7 +3981,7 @@ if ((!smtp_input && sender_address == NULL) || || /* OR */ (sender_address[0] != 0 && /* Non-empty sender address, AND */ !checking && /* Not running tests, AND */ - filter_test == NULL)) /* Not testing a filter */ + filter_test == FTEST_NONE)) /* Not testing a filter */ { sender_address = originator_login; sender_address_forced = FALSE; @@ -4088,11 +4132,23 @@ call to find the ident for. */ if (host_checking) { + int x[4]; + int size; + sender_ident = NULL; if (running_in_test_harness && sender_host_port != 0 && interface_address != NULL && interface_port != 0) verify_get_ident(1413); + /* In case the given address is a non-canonical IPv6 address, canonicize + it. The code works for both IPv4 and IPv6, as it happens. */ + + size = host_aton(sender_host_address, x); + sender_host_address = store_get(48); /* large enough for full IPv6 */ + (void)host_nmtoa(size, x, -1, sender_host_address, ':'); + + /* Now set up for testing */ + host_build_sender_fullhost(); smtp_input = TRUE; smtp_in = stdin; @@ -4135,7 +4191,7 @@ if (recipients_arg >= argc && !extract_recipients && !smtp_input) printf("Configuration file is %s\n", config_main_filename); return EXIT_SUCCESS; } - if (filter_test == NULL) + if (filter_test == FTEST_NONE) { fprintf(stderr, "Exim is a Mail Transfer Agent. It is normally called by Mail User Agents,\n" @@ -4393,11 +4449,11 @@ while (more) int rcount = 0; int count = argc - recipients_arg; uschar **list = argv + recipients_arg; - + /* These options cannot be changed dynamically for non-SMTP messages */ - + active_local_sender_retain = local_sender_retain; - active_local_from_check = local_from_check; + active_local_from_check = local_from_check; /* Save before any rewriting */ @@ -4489,9 +4545,9 @@ while (more) } } - /* Read the data for the message. If filter_test is true, this will - just read the headers for the message, and not write anything onto - the spool. */ + /* Read the data for the message. If filter_test is not FTEST_NONE, this + will just read the headers for the message, and not write anything onto the + spool. */ message_ended = END_NOTENDED; more = receive_msg(extract_recipients); @@ -4510,7 +4566,7 @@ while (more) unless specified. The the return path is set to to the sender unless it has already been set from a return-path header in the message. */ - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { deliver_domain = (ftest_domain != NULL)? ftest_domain : qualify_domain_recipient; @@ -4545,8 +4601,27 @@ while (more) if (ftest_suffix != NULL) printf("Suffix = %s\n", ftest_suffix); chdir("/"); /* Get away from wherever the user is running this from */ - exim_exit(filter_runtest(filter_fd, ftest_system, more)? - EXIT_SUCCESS : EXIT_FAILURE); + + /* Now we run either a system filter test, or a user filter test, or both. + In the latter case, headers added by the system filter will persist and be + available to the user filter. We need to copy the filter variables + explicitly. */ + + if ((filter_test & FTEST_SYSTEM) != 0) + { + if (!filter_runtest(filter_sfd, filter_test_sfile, TRUE, more)) + exim_exit(EXIT_FAILURE); + } + + memcpy(filter_sn, filter_n, sizeof(filter_sn)); + + if ((filter_test & FTEST_USER) != 0) + { + if (!filter_runtest(filter_ufd, filter_test_ufile, FALSE, more)) + exim_exit(EXIT_FAILURE); + } + + exim_exit(EXIT_SUCCESS); } /* Else act on the result of message reception. We should not get here unless @@ -4602,11 +4677,16 @@ while (more) /* Else do the delivery unless the ACL or local_scan() called for queue only or froze the message. Always deliver in a separate process. A fork failure is not a disaster, as the delivery will eventually happen on a subsequent queue - run. */ + run. The search cache must be tidied before the fork, as the parent will + do it before exiting. The child will trigger a lookup failure and + thereby defer the delivery if it tries to use (for example) a cached ldap + connection that the parent has called unbind on. */ else if (!queue_only_policy && !deliver_freeze) { pid_t pid; + search_tidyup(); + if ((pid = fork()) == 0) { int rc;