X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/2b60ac102164f379dff0f26a42f9bb14c9ce94ad..a1108b5118d32e969c5fe91b2110944f7483a7cb:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index 905ef0a70..8526cbbf3 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -53,7 +53,7 @@ return store_get((int)size, TRUE); } static void -function_dummy_free(void *block) { block = block; } +function_dummy_free(void * block) {} static void * function_store_malloc(size_t size) @@ -62,7 +62,7 @@ return store_malloc((int)size); } static void -function_store_free(void *block) +function_store_free(void * block) { store_free(block); } @@ -279,7 +279,6 @@ Returns: nothing void sigalrm_handler(int sig) { -sig = sig; /* Keep picky compilers happy */ sigalrm_seen = TRUE; os_non_restarting_signal(SIGALRM, sigalrm_handler); } @@ -384,14 +383,20 @@ return 0; *************************************************/ #ifdef _POSIX_MONOTONIC_CLOCK -/* Amount CLOCK_MONOTONIC is behind realtime, at startup. */ +# ifdef CLOCK_BOOTTIME +# define EXIM_CLOCKTYPE CLOCK_BOOTTIME +# else +# define EXIM_CLOCKTYPE CLOCK_MONOTONIC +# endif + +/* Amount EXIM_CLOCK is behind realtime, at startup. */ static struct timespec offset_ts; static void exim_clock_init(void) { struct timeval tv; -if (clock_gettime(CLOCK_MONOTONIC, &offset_ts) != 0) return; +if (clock_gettime(EXIM_CLOCKTYPE, &offset_ts) != 0) return; (void)gettimeofday(&tv, NULL); offset_ts.tv_sec = tv.tv_sec - offset_ts.tv_sec; offset_ts.tv_nsec = tv.tv_usec * 1000 - offset_ts.tv_nsec; @@ -402,6 +407,29 @@ offset_ts.tv_nsec += 1000*1000*1000; #endif +void +exim_gettime(struct timeval * tv) +{ +#ifdef _POSIX_MONOTONIC_CLOCK +struct timespec now_ts; + +if (clock_gettime(EXIM_CLOCKTYPE, &now_ts) == 0) + { + now_ts.tv_sec += offset_ts.tv_sec; + if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000) + { + now_ts.tv_sec++; + now_ts.tv_nsec -= 1000*1000*1000; + } + tv->tv_sec = now_ts.tv_sec; + tv->tv_usec = now_ts.tv_nsec / 1000; + } +else +#endif + (void)gettimeofday(tv, NULL); +} + + /* Exim uses a time + a pid to generate a unique identifier in two places: its message IDs, and in file names for maildir deliveries. Because some OS now re-use pids within the same second, sub-second times are now being used. @@ -428,28 +456,9 @@ exim_wait_tick(struct timeval * tgt_tv, int resolution) struct timeval now_tv; long int now_true_usec; -#ifdef _POSIX_MONOTONIC_CLOCK -struct timespec now_ts; - -if (clock_gettime(CLOCK_MONOTONIC, &now_ts) == 0) - { - now_ts.tv_sec += offset_ts.tv_sec; - if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000) - { - now_ts.tv_sec++; - now_ts.tv_nsec -= 1000*1000*1000; - } - now_tv.tv_sec = now_ts.tv_sec; - now_true_usec = (now_ts.tv_nsec / (resolution * 1000)) * resolution; - now_tv.tv_usec = now_true_usec; - } -else -#endif - { - (void)gettimeofday(&now_tv, NULL); - now_true_usec = now_tv.tv_usec; - now_tv.tv_usec = (now_true_usec/resolution) * resolution; - } +exim_gettime(&now_tv); +now_true_usec = now_tv.tv_usec; +now_tv.tv_usec = (now_true_usec/resolution) * resolution; while (exim_tvcmp(&now_tv, tgt_tv) <= 0) { @@ -555,7 +564,7 @@ for (int i = 0; i <= 2; i++) { if (devnull < 0) devnull = open("/dev/null", O_RDWR); if (devnull < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", - string_open_failed(errno, "/dev/null", NULL)); + string_open_failed("/dev/null", NULL)); if (devnull != i) (void)dup2(devnull, i); } } @@ -1001,6 +1010,9 @@ g = string_cat(NULL, US"Support for:"); #ifdef EXPERIMENTAL_DSN_INFO g = string_cat(g, US" Experimental_DSN_info"); #endif +#ifdef EXPERIMENTAL_ESMTP_LIMITS + g = string_cat(g, US" Experimental_ESMTP_Limits"); +#endif #ifdef EXPERIMENTAL_QUEUEFILE g = string_cat(g, US" Experimental_QUEUEFILE"); #endif @@ -1618,6 +1630,7 @@ BOOL removed_privilege = FALSE; BOOL usage_wanted = FALSE; BOOL verify_address_mode = FALSE; BOOL verify_as_sender = FALSE; +BOOL rcpt_verify_quota = FALSE; BOOL version_printed = FALSE; uschar *alias_arg = NULL; uschar *called_as = US""; @@ -1659,6 +1672,8 @@ extern char **environ; (void)gettimeofday(×tamp_startup, NULL); #endif +store_init(); /* Initialise the memory allocation susbsystem */ + /* If the Exim user and/or group and/or the configuration file owner/group were defined by ref:name at build time, we must now find the actual uid/gid values. This is a feature to make the lives of binary distributors easier. */ @@ -1728,7 +1743,7 @@ make quite sure. */ setlocale(LC_ALL, "C"); -/* Get the offset between CLOCK_MONOTONIC and wallclock */ +/* Get the offset between CLOCK_MONOTONIC/CLOCK_BOOTTIME and wallclock */ #ifdef _POSIX_MONOTONIC_CLOCK exim_clock_init(); @@ -2148,7 +2163,7 @@ on the second character (the one after '-'), to save some effort. */ concept of *the* alias file, but since Sun's YP make script calls sendmail this way, some support must be provided. */ case 'i': - if (!*++argrest) bi_option = TRUE; + if (!*argrest) bi_option = TRUE; else badarg = TRUE; break; @@ -2245,7 +2260,7 @@ on the second character (the one after '-'), to save some effort. */ case 'P': /* -bP config: we need to setup here, because later, - * when list_options is checked, the config is read already */ + when list_options is checked, the config is read already */ if (*argrest) badarg = TRUE; else if (argv[i+1] && Ustrcmp(argv[i+1], "config") == 0) @@ -2363,6 +2378,7 @@ on the second character (the one after '-'), to save some effort. */ int len = Ustrlen(ALT_CONFIG_PREFIX); const uschar *list = argrest; uschar *filename; + /* The argv is untainted, so big_buffer (also untainted) is ok to use */ while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) if ( ( Ustrlen(filename) < len @@ -2775,11 +2791,42 @@ on the second character (the one after '-'), to save some effort. */ case 'K': smtp_peer_options |= OPTION_CHUNKING; break; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + /* -MCL: peer used LIMITS RCPTMAX and/or RCPTDOMAINMAX */ + case 'L': if (++i < argc) continue_limit_mail = Uatoi(argv[i]); + else badarg = TRUE; + if (++i < argc) continue_limit_rcpt = Uatoi(argv[i]); + else badarg = TRUE; + if (++i < argc) continue_limit_rcptdom = Uatoi(argv[i]); + else badarg = TRUE; + break; +#endif + /* -MCP: set the smtp_use_pipelining flag; this is useful only when it preceded -MC (see above) */ case 'P': smtp_peer_options |= OPTION_PIPE; break; +#ifdef SUPPORT_SOCKS + /* -MCp: Socks proxy in use; nearside IP, port, external IP, port */ + case 'p': proxy_session = TRUE; + if (++i < argc) + { + proxy_local_address = string_copy_taint(argv[i], TRUE); + if (++i < argc) + { + proxy_local_port = Uatoi(argv[i]); + if (++i < argc) + { + proxy_external_address = string_copy_taint(argv[i], TRUE); + if (++i < argc) + { + proxy_external_port = Uatoi(argv[i]); + break; + } } } } + badarg = TRUE; + break; +#endif /* -MCQ: pass on the pid of the queue-running process that started this chain of deliveries and the fd of its synchronizing pipe; this is useful only when it precedes -MC (see above) */ @@ -2790,16 +2837,35 @@ on the second character (the one after '-'), to save some effort. */ else badarg = TRUE; break; + /* -MCq: do a quota check on the given recipient for the given size + of message. Separate from -MC. */ + case 'q': rcpt_verify_quota = TRUE; + if (++i < argc) message_size = Uatoi(argv[i]); + else badarg = TRUE; + break; + /* -MCS: set the smtp_use_size flag; this is useful only when it precedes -MC (see above) */ case 'S': smtp_peer_options |= OPTION_SIZE; break; #ifndef DISABLE_TLS + /* -MCs: used with -MCt; SNI was sent */ + /* -MCr: ditto, DANE */ + + case 'r': + case 's': if (++i < argc) + { + continue_proxy_sni = string_copy_taint(argv[i], TRUE); + if (argrest[1] == 'r') continue_proxy_dane = TRUE; + } + else badarg = TRUE; + break; + /* -MCt: similar to -MCT below but the connection is still open via a proxy process which handles the TLS context and coding. Require three arguments for the proxied local address and port, - and the TLS cipher. */ + and the TLS cipher. */ case 't': if (++i < argc) sending_ip_address = string_copy_taint(argv[i], TRUE); @@ -3191,6 +3257,13 @@ on the second character (the one after '-'), to save some effort. */ else override_local_interfaces = string_copy_taint(argv[++i], TRUE); break; + /* -oY: Override creation of daemon notifier socket */ + + case 'Y': + if (*argrest) badarg = TRUE; + else notifier_socket = NULL; + break; + /* Unknown -o argument */ default: @@ -4094,10 +4167,8 @@ privilege by now. Before the chdir, we try to ensure that the directory exists. if (Uchdir(spool_directory) != 0) { - int dummy; - (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE); - dummy = /* quieten compiler */ Uchdir(spool_directory); - dummy = dummy; /* yet more compiler quietening, sigh */ + (void) directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE); + (void) Uchdir(spool_directory); } /* Handle calls with the -bi option. This is a sendmail option to rebuild *the* @@ -4108,8 +4179,8 @@ script. */ if (bi_option) { - (void)fclose(config_file); - if (bi_command) + (void) fclose(config_file); + if (bi_command && *bi_command) { int i = 0; uschar *argv[3]; @@ -4120,11 +4191,11 @@ if (bi_option) setgroups(group_count, group_list); exim_setugid(real_uid, real_gid, FALSE, US"running bi_command"); - DEBUG(D_exec) debug_printf("exec %.256s %.256s\n", argv[0], - argv[1] ? argv[1] : US""); + DEBUG(D_exec) debug_printf("exec '%.256s' %s%.256s%s\n", argv[0], + argv[1] ? "'" : "", argv[1] ? argv[1] : US"", argv[1] ? "'" : ""); execv(CS argv[0], (char *const *)argv); - exim_fail("exim: exec failed: %s\n", strerror(errno)); + exim_fail("exim: exec '%s' failed: %s\n", argv[0], strerror(errno)); } else { @@ -4296,6 +4367,7 @@ if ( !unprivileged /* originally had root AND */ || msg_action != MSG_DELIVER /* not delivering */ ) /* and */ && (!checking || !f.address_test_mode) /* not address checking */ + && !rcpt_verify_quota /* and not quota checking */ ) ) ) exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed"); @@ -4315,8 +4387,10 @@ else if (!(unprivileged || removed_privilege)) exim_fail("exim: changing group failed: %s\n", strerror(errno)); else + { DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n", (long int)exim_gid, strerror(errno)); + } } /* Handle a request to scan a file for malware */ @@ -4414,6 +4488,18 @@ needed in transports so we lost the optimisation. */ #endif } +/* Handle a request to check quota */ +if (rcpt_verify_quota) + if (real_uid != root_uid && real_uid != exim_uid) + exim_fail("exim: Permission denied\n"); + else if (recipients_arg >= argc) + exim_fail("exim: missing recipient for quota check\n"); + else + { + verify_quota(argv[recipients_arg]); + exim_exit(EXIT_SUCCESS); + } + /* Handle the -brt option. This is for checking out retry configurations. The next three arguments are a domain name or a complete address, and optionally two error numbers. All it does is to call the function that @@ -4728,16 +4814,16 @@ for (i = 0;;) configuration specifies something to use. When running in the test harness, any setting of unknown_login overrides the actual name. */ -if (originator_login == NULL || f.running_in_test_harness) +if (!originator_login || f.running_in_test_harness) { - if (unknown_login != NULL) + if (unknown_login) { originator_login = expand_string(unknown_login); - if (originator_name == NULL && unknown_username != NULL) + if (!originator_name && unknown_username) originator_name = expand_string(unknown_username); - if (originator_name == NULL) originator_name = US""; + if (!originator_name) originator_name = US""; } - if (originator_login == NULL) + if (!originator_login) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to get user name for uid %d", (int)real_uid); } @@ -4745,8 +4831,7 @@ if (originator_login == NULL || f.running_in_test_harness) /* Ensure that the user name is in a suitable form for use as a "phrase" in an RFC822 address.*/ -originator_name = string_copy(parse_fix_phrase(originator_name, - Ustrlen(originator_name), big_buffer, big_buffer_size)); +originator_name = US parse_fix_phrase(originator_name, Ustrlen(originator_name)); /* If a message is created by this call of Exim, the uid/gid of its originator are those of the caller. These values are overridden if an existing message is