X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/36f12725ebda2bfd6ed4fe98b0eeaf1ce01f2604..e2f5dc151e2e79058e93924e6d35510557f0535d:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index 9a8bbb365..0d8f24492 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/exim.c,v 1.63 2009/10/14 13:52:48 nm4 Exp $ */ +/* $Cambridge: exim/src/src/exim.c,v 1.71 2010/06/07 00:12:42 pdp Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2007 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -681,161 +681,12 @@ else -/************************************************* -* Decode bit settings for log/debug * -*************************************************/ - -/* This function decodes a string containing bit settings in the form of +name -and/or -name sequences, and sets/unsets bits in a bit string accordingly. It -also recognizes a numeric setting of the form =, but this is not -intended for user use. It's an easy way for Exim to pass the debug settings -when it is re-exec'ed. - -The log options are held in two unsigned ints (because there became too many -for one). The top bit in the table means "put in 2nd selector". This does not -yet apply to debug options, so the "=" facility sets only the first selector. - -The "all" selector, which must be equal to 0xffffffff, is recognized specially. -It sets all the bits in both selectors. However, there is a facility for then -unsetting certain bits, because we want to turn off "memory" in the debug case. - -A bad value for a debug setting is treated as an unknown option - error message -to stderr and die. For log settings, which come from the configuration file, -we write to the log on the way out... - -Arguments: - selector1 address of the first bit string - selector2 address of the second bit string, or NULL - notall1 bits to exclude from "all" for selector1 - notall2 bits to exclude from "all" for selector2 - string the configured string - options the table of option names - count size of table - which "log" or "debug" - -Returns: nothing on success - bomb out on failure -*/ - -static void -decode_bits(unsigned int *selector1, unsigned int *selector2, int notall1, - int notall2, uschar *string, bit_table *options, int count, uschar *which) -{ -uschar *errmsg; -if (string == NULL) return; - -if (*string == '=') - { - char *end; /* Not uschar */ - *selector1 = strtoul(CS string+1, &end, 0); - if (*end == 0) return; - errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which, - string); - goto ERROR_RETURN; - } - -/* Handle symbolic setting */ - -else for(;;) - { - BOOL adding; - uschar *s; - int len; - bit_table *start, *end; - - while (isspace(*string)) string++; - if (*string == 0) return; - - if (*string != '+' && *string != '-') - { - errmsg = string_sprintf("malformed %s_selector setting: " - "+ or - expected but found \"%s\"", which, string); - goto ERROR_RETURN; - } - - adding = *string++ == '+'; - s = string; - while (isalnum(*string) || *string == '_') string++; - len = string - s; - - start = options; - end = options + count; - - while (start < end) - { - bit_table *middle = start + (end - start)/2; - int c = Ustrncmp(s, middle->name, len); - if (c == 0) - { - if (middle->name[len] != 0) c = -1; else - { - unsigned int bit = middle->bit; - unsigned int *selector; - - /* The value with all bits set means "force all bits in both selectors" - in the case where two are being handled. However, the top bit in the - second selector is never set. When setting, some bits can be excluded. - */ - - if (bit == 0xffffffff) - { - if (adding) - { - *selector1 = 0xffffffff ^ notall1; - if (selector2 != NULL) *selector2 = 0x7fffffff ^ notall2; - } - else - { - *selector1 = 0; - if (selector2 != NULL) *selector2 = 0; - } - } - - /* Otherwise, the 0x80000000 bit means "this value, without the top - bit, belongs in the second selector". */ - - else - { - if ((bit & 0x80000000) != 0) - { - selector = selector2; - bit &= 0x7fffffff; - } - else selector = selector1; - if (adding) *selector |= bit; else *selector &= ~bit; - } - break; /* Out of loop to match selector name */ - } - } - if (c < 0) end = middle; else start = middle + 1; - } /* Loop to match selector name */ - - if (start >= end) - { - errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", which, - adding? '+' : '-', len, s); - goto ERROR_RETURN; - } - } /* Loop for selector names */ - -/* Handle disasters */ - -ERROR_RETURN: -if (Ustrcmp(which, "debug") == 0) - { - fprintf(stderr, "exim: %s\n", errmsg); - exit(EXIT_FAILURE); - } -else log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "%s", errmsg); -} - - - /************************************************* * Show supported features * *************************************************/ -/* This function is called for -bV and for -d to output the optional features -of the current Exim binary. +/* This function is called for -bV/--version and for -d to output the optional +features of the current Exim binary. Arguments: a FILE for printing Returns: nothing @@ -1054,7 +905,7 @@ if (fixed_never_users[0] > 0) fprintf(f, "%d\n", (unsigned int)fixed_never_users[i]); } -fprintf(f, "Size of off_t: %d\n", sizeof(off_t)); +fprintf(f, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t)); /* This runtime check is to help diagnose library linkage mismatches which result in segfaults and the like; as such, it's left until the end, @@ -1355,6 +1206,7 @@ uschar *ftest_domain = NULL; uschar *ftest_localpart = NULL; uschar *ftest_prefix = NULL; uschar *ftest_suffix = NULL; +uschar *malware_test_file = NULL; uschar *real_sender_address; uschar *originator_home = US"/"; void *reset_point; @@ -1382,6 +1234,12 @@ This is a feature to make the lives of binary distributors easier. */ #ifdef EXIM_USERNAME if (route_finduser(US EXIM_USERNAME, &pw, &exim_uid)) { + if (exim_uid == 0) + { + fprintf(stderr, "exim: refusing to run with uid 0 for \"%s\"\n", + EXIM_USERNAME); + exit(EXIT_FAILURE); + } exim_gid = pw->pw_gid; } else @@ -1637,16 +1495,6 @@ running in an unprivileged state. */ unprivileged = (real_uid != root_uid && original_euid != root_uid); -/* If the first argument is --help, set usage_wanted and pretend there -are no arguments. This will cause a brief message to be given. We do -the message generation downstream so we can pick up how we were invoked */ - -if (argc > 1 && Ustrcmp(argv[1], "--help") == 0) - { - argc = 1; - usage_wanted = TRUE; - } - /* Scan the program's arguments. Some can be dealt with right away; others are simply recorded for checking and handling afterwards. Do a high-level switch on the second character (the one after '-'), to save some effort. */ @@ -1711,6 +1559,21 @@ for (i = 1; i < argc; i++) argrest++; } + /* deal with --option_aliases */ + else if (switchchar == '-') + { + if (Ustrcmp(argrest, "help") == 0) + { + usage_wanted = TRUE; + break; + } + else if (Ustrcmp(argrest, "version") == 0) + { + switchchar = 'b'; + argrest = US"V"; + } + } + /* High-level switch on active initial letter */ switch(switchchar) @@ -1821,6 +1684,14 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "m") == 0) receiving_message = TRUE; + /* -bmalware: test the filename given for malware */ + + else if (Ustrcmp(argrest, "malware") == 0) + { + if (++i >= argc) { badarg = TRUE; break; } + malware_test_file = argv[i]; + } + /* -bnq: For locally originating messages, do not qualify unqualified addresses. In the envelope, this causes errors; in header lines they just get left. */ @@ -1977,6 +1848,7 @@ for (i = 1; i < argc; i++) config_main_filelist = argrest; config_changed = TRUE; + trusted_config = FALSE; } break; @@ -2071,7 +1943,7 @@ for (i = 1; i < argc; i++) } if (*argrest != 0) decode_bits(&selector, NULL, D_memory, 0, argrest, debug_options, - debug_options_count, US"debug"); + debug_options_count, US"debug", 0); debug_selector = selector; } break; @@ -3175,7 +3047,7 @@ values (such as the path name). If running in the test harness, pretend that configuration file changes and macro definitions haven't happened. */ if (( /* EITHER */ - (config_changed || macros != NULL) && /* Config changed, and */ + (!trusted_config || macros != NULL) && /* Config changed, and */ real_uid != root_uid && /* Not root, and */ #ifndef ALT_CONFIG_ROOT_ONLY /* (when not locked out) */ real_uid != exim_uid && /* Not exim, and */ @@ -3240,8 +3112,8 @@ readconf_main(); /* Handle the decoding of logging options. */ -decode_bits(&log_write_selector, &log_extra_selector, 0, 0, log_selector_string, - log_options, log_options_count, US"log"); +decode_bits(&log_write_selector, &log_extra_selector, 0, 0, + log_selector_string, log_options, log_options_count, US"log", 0); DEBUG(D_any) { @@ -3394,7 +3266,7 @@ If ALT_CONFIG_ROOT_ONLY is defined, we don't know whether we were called by the built-in exim user or one defined in the configuration. In either event, re-enable log processing, assuming the sysadmin knows what they are doing. */ -if (removed_privilege && (config_changed || macros != NULL) && +if (removed_privilege && (!trusted_config || macros != NULL) && real_uid == exim_uid) { #ifdef ALT_CONFIG_ROOT_ONLY @@ -3406,7 +3278,7 @@ if (removed_privilege && (config_changed || macros != NULL) && else log_write(0, LOG_MAIN|LOG_PANIC, "exim user (uid=%d) is defined only at runtime; privilege lost for %s", - (int)exim_uid, config_changed? "-C" : "-D"); + (int)exim_uid, trusted_config? "-D" : "-C"); #endif } @@ -3592,12 +3464,13 @@ configuration, but the queue run restriction can be relaxed. Only an admin user may request that a message be returned to its sender forthwith. Only an admin user may specify a debug level greater than D_v (because it might show passwords, etc. in lookup queries). Only an admin user may request a queue -count. */ +count. Only an admin user can use the test interface to scan for email +(because Exim will be in the spool dir and able to look at mails). */ if (!admin_user) { BOOL debugset = (debug_selector & ~D_v) != 0; - if (deliver_give_up || daemon_listen || + if (deliver_give_up || daemon_listen || malware_test_file || (count_queue && queue_list_requires_admin) || (list_queue && queue_list_requires_admin) || (queue_interval >= 0 && prod_requires_admin) || @@ -3748,6 +3621,33 @@ if (!unprivileged && /* originally had root AND */ else setgid(exim_gid); +/* Handle a request to scan a file for malware */ +if (malware_test_file) + { +#ifdef WITH_CONTENT_SCAN + int result; + set_process_info("scanning file for malware"); + result = malware_in_file(malware_test_file); + if (result == FAIL) + { + printf("No malware found.\n"); + exit(EXIT_SUCCESS); + } + if (result != OK) + { + printf("Malware lookup returned non-okay/fail: %d\n", result); + exit(EXIT_FAILURE); + } + if (malware_name) + printf("Malware found: %s\n", malware_name); + else + printf("Malware scan detected malware of unknown name.\n"); +#else + printf("Malware scanning not enabled at compile time.\n"); +#endif + exit(EXIT_FAILURE); + } + /* Handle a request to list the delivery queue */ if (list_queue) @@ -3939,7 +3839,8 @@ if (list_options) if (i < argc - 1 && (Ustrcmp(argv[i], "router") == 0 || Ustrcmp(argv[i], "transport") == 0 || - Ustrcmp(argv[i], "authenticator") == 0)) + Ustrcmp(argv[i], "authenticator") == 0 || + Ustrcmp(argv[i], "macro") == 0)) { readconf_print(argv[i+1], argv[i]); i++;