X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fexim.c;h=042b97861c2f15368a2cdd1a9f96555a3d559fa3;hp=7b1c8ead972c8a33ac8ad5758cc37328d55699c7;hb=1e1ddfac79fbcd052f199500a6493c7f79cb8462;hpb=8102279385f5f70c959aa219feca37031c0a1828 diff --git a/src/src/exim.c b/src/src/exim.c index 7b1c8ead9..042b97861 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -831,7 +832,7 @@ int start, end, domain; uschar *parse_error = NULL; uschar *address = parse_extract_address(s, &parse_error, &start, &end, &domain, FALSE); -if (address == NULL) +if (!address) { fprintf(stdout, "syntax error: %s\n", parse_error); *exit_value = 2; @@ -895,195 +896,198 @@ Returns: nothing static void show_whats_supported(FILE * fp) { +rmark reset_point = store_mark(); +gstring * g; DEBUG(D_any) {} else show_db_version(fp); -fprintf(fp, "Support for:"); +g = string_cat(NULL, US"Support for:"); #ifdef SUPPORT_CRYPTEQ - fprintf(fp, " crypteq"); + g = string_cat(g, US" crypteq"); #endif #if HAVE_ICONV - fprintf(fp, " iconv()"); + g = string_cat(g, US" iconv()"); #endif #if HAVE_IPV6 - fprintf(fp, " IPv6"); + g = string_cat(g, US" IPv6"); #endif #ifdef HAVE_SETCLASSRESOURCES - fprintf(fp, " use_setclassresources"); + g = string_cat(g, US" use_setclassresources"); #endif #ifdef SUPPORT_PAM - fprintf(fp, " PAM"); + g = string_cat(g, US" PAM"); #endif #ifdef EXIM_PERL - fprintf(fp, " Perl"); + g = string_cat(g, US" Perl"); #endif #ifdef EXPAND_DLFUNC - fprintf(fp, " Expand_dlfunc"); + g = string_cat(g, US" Expand_dlfunc"); #endif #ifdef USE_TCP_WRAPPERS - fprintf(fp, " TCPwrappers"); + g = string_cat(g, US" TCPwrappers"); #endif #ifdef USE_GNUTLS - fprintf(fp, " GnuTLS"); + g = string_cat(g, US" GnuTLS"); #endif #ifdef USE_OPENSSL - fprintf(fp, " OpenSSL"); + g = string_cat(g, US" OpenSSL"); #endif #ifdef SUPPORT_TRANSLATE_IP_ADDRESS - fprintf(fp, " translate_ip_address"); + g = string_cat(g, US" translate_ip_address"); #endif #ifdef SUPPORT_MOVE_FROZEN_MESSAGES - fprintf(fp, " move_frozen_messages"); + g = string_cat(g, US" move_frozen_messages"); #endif #ifdef WITH_CONTENT_SCAN - fprintf(fp, " Content_Scanning"); + g = string_cat(g, US" Content_Scanning"); #endif #ifdef SUPPORT_DANE - fprintf(fp, " DANE"); + g = string_cat(g, US" DANE"); #endif #ifndef DISABLE_DKIM - fprintf(fp, " DKIM"); + g = string_cat(g, US" DKIM"); #endif #ifndef DISABLE_DNSSEC - fprintf(fp, " DNSSEC"); + g = string_cat(g, US" DNSSEC"); #endif #ifndef DISABLE_EVENT - fprintf(fp, " Event"); + g = string_cat(g, US" Event"); #endif #ifdef SUPPORT_I18N - fprintf(fp, " I18N"); + g = string_cat(g, US" I18N"); #endif #ifndef DISABLE_OCSP - fprintf(fp, " OCSP"); + g = string_cat(g, US" OCSP"); #endif #ifndef DISABLE_PIPE_CONNECT - fprintf(fp, " PIPE_CONNECT"); + g = string_cat(g, US" PIPE_CONNECT"); #endif #ifndef DISABLE_PRDR - fprintf(fp, " PRDR"); + g = string_cat(g, US" PRDR"); #endif #ifdef SUPPORT_PROXY - fprintf(fp, " PROXY"); + g = string_cat(g, US" PROXY"); #endif #ifdef SUPPORT_SOCKS - fprintf(fp, " SOCKS"); + g = string_cat(g, US" SOCKS"); #endif #ifdef SUPPORT_SPF - fprintf(fp, " SPF"); + g = string_cat(g, US" SPF"); #endif #ifdef SUPPORT_DMARC - fprintf(fp, " DMARC"); + g = string_cat(g, US" DMARC"); #endif #ifdef TCP_FASTOPEN tcp_init(); - if (f.tcp_fastopen_ok) fprintf(fp, " TCP_Fast_Open"); + if (f.tcp_fastopen_ok) g = string_cat(g, US" TCP_Fast_Open"); #endif #ifdef EXPERIMENTAL_ARC - fprintf(fp, " Experimental_ARC"); + g = string_cat(g, US" Experimental_ARC"); #endif #ifdef EXPERIMENTAL_BRIGHTMAIL - fprintf(fp, " Experimental_Brightmail"); + g = string_cat(g, US" Experimental_Brightmail"); #endif #ifdef EXPERIMENTAL_DCC - fprintf(fp, " Experimental_DCC"); + g = string_cat(g, US" Experimental_DCC"); #endif #ifdef EXPERIMENTAL_DSN_INFO - fprintf(fp, " Experimental_DSN_info"); + g = string_cat(g, US" Experimental_DSN_info"); #endif #ifdef EXPERIMENTAL_LMDB - fprintf(fp, " Experimental_LMDB"); + g = string_cat(g, US" Experimental_LMDB"); #endif #ifdef EXPERIMENTAL_QUEUE_RAMP - fprintf(fp, " Experimental_Queue_Ramp"); + g = string_cat(g, US" Experimental_Queue_Ramp"); #endif #ifdef EXPERIMENTAL_QUEUEFILE - fprintf(fp, " Experimental_QUEUEFILE"); + g = string_cat(g, US" Experimental_QUEUEFILE"); #endif #if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE) - fprintf(fp, " Experimental_SRS"); + g = string_cat(g, US" Experimental_SRS"); #endif #ifdef EXPERIMENTAL_TLS_RESUME - fprintf(fp, " Experimental_TLS_resume"); + g = string_cat(g, US" Experimental_TLS_resume"); #endif -fprintf(fp, "\n"); +g = string_cat(g, US"\n"); -fprintf(fp, "Lookups (built-in):"); +g = string_cat(g, US"Lookups (built-in):"); #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2 - fprintf(fp, " lsearch wildlsearch nwildlsearch iplsearch"); + g = string_cat(g, US" lsearch wildlsearch nwildlsearch iplsearch"); #endif #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2 - fprintf(fp, " cdb"); + g = string_cat(g, US" cdb"); #endif #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2 - fprintf(fp, " dbm dbmjz dbmnz"); + g = string_cat(g, US" dbm dbmjz dbmnz"); #endif #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2 - fprintf(fp, " dnsdb"); + g = string_cat(g, US" dnsdb"); #endif #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2 - fprintf(fp, " dsearch"); + g = string_cat(g, US" dsearch"); #endif #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2 - fprintf(fp, " ibase"); + g = string_cat(g, US" ibase"); #endif #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2 - fprintf(fp, " json"); + g = string_cat(g, US" json"); #endif #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 - fprintf(fp, " ldap ldapdn ldapm"); + g = string_cat(g, US" ldap ldapdn ldapm"); #endif #ifdef EXPERIMENTAL_LMDB - fprintf(fp, " lmdb"); + g = string_cat(g, US" lmdb"); #endif #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2 - fprintf(fp, " mysql"); + g = string_cat(g, US" mysql"); #endif #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2 - fprintf(fp, " nis nis0"); + g = string_cat(g, US" nis nis0"); #endif #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2 - fprintf(fp, " nisplus"); + g = string_cat(g, US" nisplus"); #endif #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2 - fprintf(fp, " oracle"); + g = string_cat(g, US" oracle"); #endif #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2 - fprintf(fp, " passwd"); + g = string_cat(g, US" passwd"); #endif #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2 - fprintf(fp, " pgsql"); + g = string_cat(g, US" pgsql"); #endif #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2 - fprintf(fp, " redis"); + g = string_cat(g, US" redis"); #endif #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2 - fprintf(fp, " sqlite"); + g = string_cat(g, US" sqlite"); #endif #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2 - fprintf(fp, " testdb"); + g = string_cat(g, US" testdb"); #endif #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2 - fprintf(fp, " whoson"); + g = string_cat(g, US" whoson"); #endif -fprintf(fp, "\n"); +g = string_cat(g, US"\n"); -auth_show_supported(fp); -route_show_supported(fp); -transport_show_supported(fp); +g = auth_show_supported(g); +g = route_show_supported(g); +g = transport_show_supported(g); #ifdef WITH_CONTENT_SCAN -malware_show_supported(fp); +g = malware_show_supported(g); #endif if (fixed_never_users[0] > 0) { int i; - fprintf(fp, "Fixed never_users: "); + g = string_cat(g, US"Fixed never_users: "); for (i = 1; i <= (int)fixed_never_users[0] - 1; i++) - fprintf(fp, "%d:", (unsigned int)fixed_never_users[i]); - fprintf(fp, "%d\n", (unsigned int)fixed_never_users[i]); + string_fmt_append(g, "%u:", (unsigned)fixed_never_users[i]); + g = string_fmt_append(g, "%u\n", (unsigned)fixed_never_users[i]); } -fprintf(fp, "Configure owner: %d:%d\n", config_uid, config_gid); +g = string_fmt_append(g, "Configure owner: %d:%d\n", config_uid, config_gid); +fputs(CS string_from_gstring(g), fp); fprintf(fp, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t)); @@ -1163,6 +1167,7 @@ show_db_version(fp); #endif } while (0); +store_reset(reset_point); } @@ -1629,7 +1634,6 @@ uschar *malware_test_file = NULL; uschar *real_sender_address; uschar *originator_home = US"/"; size_t sz; -rmark reset_point; struct passwd *pw; struct stat statbuf; @@ -1948,15 +1952,20 @@ running in an unprivileged state. */ unprivileged = (real_uid != root_uid && original_euid != root_uid); +/* For most of the args-parsing we need to use permanent pool memory */ + { + int old_pool = store_pool; + store_pool = POOL_PERM; + /* 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. */ -for (i = 1; i < argc; i++) + for (i = 1; i < argc; i++) { BOOL badarg = FALSE; - uschar *arg = argv[i]; - uschar *argrest; + uschar * arg = argv[i]; + uschar * argrest; int switchchar; /* An argument not starting with '-' is the start of a recipients list; @@ -2035,7 +2044,7 @@ for (i = 1; i < argc; i++) /* sendmail uses -Ac and -Am to control which .cf file is used; we ignore them. */ case 'A': - if (*argrest == '\0') { badarg = TRUE; break; } + if (!*argrest) { badarg = TRUE; break; } else { BOOL ignore = FALSE; @@ -2091,9 +2100,9 @@ for (i = 1; i < argc; i++) /* -bF: Run system filter test */ case 'F': filter_test |= checking = FTEST_SYSTEM; - if (*argrest) { badarg = TRUE; break; } - if (++i < argc) filter_test_sfile = argv[i]; else - exim_fail("exim: file name expected after %s\n", argv[i-1]); + if (*argrest) badarg = TRUE; + else if (++i < argc) filter_test_sfile = argv[i]; + else exim_fail("exim: file name expected after %s\n", argv[i-1]); break; /* -bf: Run user filter test @@ -2126,7 +2135,7 @@ for (i = 1; i < argc; i++) if (!*argrest || Ustrcmp(argrest, "c") == 0) { if (++i >= argc) { badarg = TRUE; break; } - sender_host_address = argv[i]; + sender_host_address = string_copy_taint(argv[i], TRUE); host_checking = checking = f.log_testing_mode = TRUE; f.host_checking_callout = *argrest == 'c'; message_logs = FALSE; @@ -2345,11 +2354,8 @@ for (i = 1; i < argc; i++) a change! Enforce a prefix check if required. */ case 'C': - if (*argrest == 0) - { - if(++i < argc) argrest = argv[i]; else - { badarg = TRUE; break; } - } + if (!*argrest) + if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; } if (Ustrcmp(config_main_filelist, argrest) != 0) { #ifdef ALT_CONFIG_PREFIX @@ -2358,14 +2364,14 @@ for (i = 1; i < argc; i++) const uschar *list = argrest; uschar *filename; while((filename = string_nextinlist(&list, &sep, big_buffer, - big_buffer_size)) != NULL) - { - if ((Ustrlen(filename) < len || - Ustrncmp(filename, ALT_CONFIG_PREFIX, len) != 0 || - Ustrstr(filename, "/../") != NULL) && - (Ustrcmp(filename, "/dev/null") != 0 || real_uid != root_uid)) + big_buffer_size))) + if ( ( Ustrlen(filename) < len + || Ustrncmp(filename, ALT_CONFIG_PREFIX, len) != 0 + || Ustrstr(filename, "/../") != NULL + ) + && (Ustrcmp(filename, "/dev/null") != 0 || real_uid != root_uid) + ) exim_fail("-C Permission denied\n"); - } #endif if (real_uid != root_uid) { @@ -2404,11 +2410,14 @@ for (i = 1; i < argc; i++) else { /* Well, the trust list at least is up to scratch... */ - rmark reset_point = store_mark(); + rmark reset_point; uschar *trusted_configs[32]; int nr_configs = 0; int i = 0; + int old_pool = store_pool; + store_pool = POOL_MAIN; + reset_point = store_mark(); while (Ufgets(big_buffer, big_buffer_size, trust_list)) { uschar *start = big_buffer, *nl; @@ -2420,7 +2429,7 @@ for (i = 1; i < argc; i++) if (nl) *nl = 0; trusted_configs[nr_configs++] = string_copy(start); - if (nr_configs == 32) + if (nr_configs == nelem(trusted_configs)) break; } fclose(trust_list); @@ -2431,7 +2440,7 @@ for (i = 1; i < argc; i++) const uschar *list = argrest; uschar *filename; while (f.trusted_config && (filename = string_nextinlist(&list, - &sep, big_buffer, big_buffer_size)) != NULL) + &sep, big_buffer, big_buffer_size))) { for (i=0; i < nr_configs; i++) if (Ustrcmp(filename, trusted_configs[i]) == 0) @@ -2446,6 +2455,7 @@ for (i = 1; i < argc; i++) else /* No valid prefixes found in trust_list file. */ f.trusted_config = FALSE; store_reset(reset_point); + store_pool = old_pool; } } else /* Could not open trust_list file. */ @@ -2533,7 +2543,7 @@ for (i = 1; i < argc; i++) f.debug_daemon = TRUE; argrest++; } - if (*argrest != 0) + if (*argrest) decode_bits(&selector, 1, debug_notall, argrest, debug_options, debug_options_count, US"debug", 0); debug_selector = selector; @@ -2580,12 +2590,9 @@ for (i = 1; i < argc; i++) the -F or be in the next argument. */ case 'F': - if (*argrest == 0) - { - if(++i < argc) argrest = argv[i]; else - { badarg = TRUE; break; } - } - originator_name = argrest; + if (!*argrest) + if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; } + originator_name = string_copy_taint(argrest, TRUE); f.sender_name_forced = TRUE; break; @@ -2609,16 +2616,13 @@ for (i = 1; i < argc; i++) { int dummy_start, dummy_end; uschar *errmess; - if (*argrest == 0) - { - if (i+1 < argc) argrest = argv[++i]; else - { badarg = TRUE; break; } - } - if (*argrest == 0) + if (!*argrest) + if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; } + if (!*argrest) *(sender_address = store_get(1, FALSE)) = '\0'; /* Ensure writeable memory */ else { - uschar *temp = argrest + Ustrlen(argrest) - 1; + uschar * temp = argrest + Ustrlen(argrest) - 1; while (temp >= argrest && isspace(*temp)) temp--; if (temp >= argrest && *temp == '.') f_end_dot = TRUE; allow_domain_literals = TRUE; @@ -2626,8 +2630,10 @@ for (i = 1; i < argc; i++) #ifdef SUPPORT_I18N allow_utf8_domains = TRUE; #endif - sender_address = parse_extract_address(argrest, &errmess, - &dummy_start, &dummy_end, &sender_address_domain, TRUE); + if (!(sender_address = parse_extract_address(argrest, &errmess, + &dummy_start, &dummy_end, &sender_address_domain, TRUE))) + exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess); + sender_address = string_copy_taint(sender_address, TRUE); #ifdef SUPPORT_I18N message_smtputf8 = string_is_utf8(sender_address); @@ -2635,8 +2641,6 @@ for (i = 1; i < argc; i++) #endif allow_domain_literals = FALSE; strip_trailing_dot = FALSE; - if (!sender_address) - exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess); } f.sender_address_forced = TRUE; } @@ -2656,11 +2660,8 @@ for (i = 1; i < argc; i++) To put it in will require a change to the spool header file format. */ case 'h': - if (*argrest == 0) - { - if(++i < argc) argrest = argv[i]; else - { badarg = TRUE; break; } - } + if (!*argrest) + if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; } if (!isdigit(*argrest)) badarg = TRUE; break; @@ -2669,7 +2670,7 @@ for (i = 1; i < argc; i++) not to be documented for sendmail but mailx (at least) uses it) */ case 'i': - if (*argrest == 0) f.dot_ends = FALSE; else badarg = TRUE; + if (!*argrest) f.dot_ends = FALSE; else badarg = TRUE; break; @@ -2677,16 +2678,13 @@ for (i = 1; i < argc; i++) syslog_processname in the config file, but needs to be an admin option. */ case 'L': - if (*argrest == '\0') - { - if(++i < argc) argrest = argv[i]; else - { badarg = TRUE; break; } - } + if (!*argrest) + if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; } if ((sz = Ustrlen(argrest)) > 32) exim_fail("exim: the -L syslog name is too long: \"%s\"\n", argrest); if (sz < 1) exim_fail("exim: the -L syslog name is too short\n"); - cmdline_syslog_name = argrest; + cmdline_syslog_name = string_copy_taint(argrest, TRUE); break; case 'M': @@ -2716,9 +2714,9 @@ for (i = 1; i < argc; i++) if (msg_action_arg >= 0) exim_fail("exim: incompatible arguments\n"); - continue_transport = argv[++i]; - continue_hostname = argv[++i]; - continue_host_address = argv[++i]; + continue_transport = string_copy_taint(argv[++i], TRUE); + continue_hostname = string_copy_taint(argv[++i], TRUE); + continue_host_address = string_copy_taint(argv[++i], TRUE); continue_sequence = Uatoi(argv[++i]); msg_action = MSG_DELIVER; msg_action_arg = ++i; @@ -2769,7 +2767,7 @@ for (i = 1; i < argc; i++) /* -MCG: set the queue name, to a non-default value */ - case 'G': if (++i < argc) queue_name = string_copy(argv[i]); + case 'G': if (++i < argc) queue_name = string_copy_taint(argv[i], TRUE); else badarg = TRUE; break; @@ -2803,11 +2801,14 @@ for (i = 1; i < argc; i++) Require three arguments for the proxied local address and port, and the TLS cipher. */ - case 't': if (++i < argc) sending_ip_address = argv[i]; + case 't': if (++i < argc) + sending_ip_address = string_copy_taint(argv[i], TRUE); else badarg = TRUE; - if (++i < argc) sending_port = (int)(Uatol(argv[i])); + if (++i < argc) + sending_port = (int)(Uatol(argv[i])); else badarg = TRUE; - if (++i < argc) continue_proxy_cipher = argv[i]; + if (++i < argc) + continue_proxy_cipher = string_copy_taint(argv[i], TRUE); else badarg = TRUE; /*FALLTHROUGH*/ @@ -2844,7 +2845,7 @@ for (i = 1; i < argc; i++) -Mvl show log */ - else if (*argrest == 0) + else if (!*argrest) { msg_action = MSG_DELIVER; forced_delivery = f.deliver_force_thaw = TRUE; @@ -2869,7 +2870,7 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "G") == 0) { msg_action = MSG_SETQUEUE; - queue_name_dest = argv[++i]; + queue_name_dest = string_copy_taint(argv[++i], TRUE); } else if (Ustrcmp(argrest, "mad") == 0) { @@ -2942,7 +2943,7 @@ for (i = 1; i < argc; i++) for sendmail it askes for "me too". Exim always does this. */ case 'm': - if (*argrest != 0) badarg = TRUE; + if (*argrest) badarg = TRUE; break; @@ -2950,7 +2951,7 @@ for (i = 1; i < argc; i++) their thing. It implies debugging at the D_v level. */ case 'N': - if (*argrest == 0) + if (!*argrest) { f.dont_deliver = TRUE; debug_selector |= D_v; @@ -2973,7 +2974,7 @@ for (i = 1; i < argc; i++) -O option=value and -Ooption=value. */ case 'O': - if (*argrest == 0) + if (!*argrest) if (++i >= argc) exim_fail("exim: string expected after -O\n"); break; @@ -3081,12 +3082,13 @@ for (i = 1; i < argc; i++) /* -oMa: Set sender host address */ - if (Ustrcmp(argrest, "a") == 0) sender_host_address = argv[++i]; + if (Ustrcmp(argrest, "a") == 0) + sender_host_address = string_copy_taint(argv[++i], TRUE); /* -oMaa: Set authenticator name */ else if (Ustrcmp(argrest, "aa") == 0) - sender_host_authenticated = argv[++i]; + sender_host_authenticated = string_copy_taint(argv[++i], TRUE); /* -oMas: setting authenticated sender */ @@ -3100,7 +3102,8 @@ for (i = 1; i < argc; i++) /* -oMi: Set incoming interface address */ - else if (Ustrcmp(argrest, "i") == 0) interface_address = argv[++i]; + else if (Ustrcmp(argrest, "i") == 0) + interface_address = string_copy_taint(argv[++i], TRUE); /* -oMm: Message reference */ @@ -3120,7 +3123,7 @@ for (i = 1; i < argc; i++) if (received_protocol) exim_fail("received_protocol is set already\n"); else - received_protocol = argv[++i]; + received_protocol = string_copy_taint(argv[++i], TRUE); /* -oMs: Set sender host name */ @@ -3132,7 +3135,7 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "t") == 0) { sender_ident_set = TRUE; - sender_ident = argv[++i]; + sender_ident = string_copy_taint(argv[++i], TRUE); } /* Else a bad argument */ @@ -3185,7 +3188,7 @@ for (i = 1; i < argc; i++) case 'X': if (*argrest) badarg = TRUE; - else override_local_interfaces = argv[++i]; + else override_local_interfaces = string_copy_taint(argv[++i], TRUE); break; /* Unknown -o argument */ @@ -3215,29 +3218,22 @@ for (i = 1; i < argc; i++) /* -panythingelse is taken as the Sendmail-compatible argument -prval:sval, which sets the host protocol and host name */ - if (*argrest == 0) - if (i+1 < argc) - argrest = argv[++i]; - else - { badarg = TRUE; break; } + if (!*argrest) + if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; } - if (*argrest != 0) + if (*argrest) { - uschar *hn; + uschar * hn = Ustrchr(argrest, ':'); if (received_protocol) exim_fail("received_protocol is set already\n"); - hn = Ustrchr(argrest, ':'); - if (hn == NULL) - received_protocol = argrest; + if (!hn) + received_protocol = string_copy_taint(argrest, TRUE); else { - int old_pool = store_pool; - store_pool = POOL_PERM; - received_protocol = string_copyn(argrest, hn - argrest); - store_pool = old_pool; - sender_host_name = hn + 1; + received_protocol = string_copyn_taint(argrest, hn - argrest, TRUE); + sender_host_name = string_copy_taint(hn + 1, TRUE); } } break; @@ -3300,14 +3296,14 @@ for (i = 1; i < argc; i++) only, optionally named, optionally starting from a given message id. */ if (!(list_queue || count_queue)) - if (*argrest == 0 + if ( !*argrest && (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1]))) { queue_interval = 0; if (i+1 < argc && mac_ismsgid(argv[i+1])) - start_queue_run_id = argv[++i]; + start_queue_run_id = string_copy_taint(argv[++i], TRUE); if (i+1 < argc && mac_ismsgid(argv[i+1])) - stop_queue_run_id = argv[++i]; + stop_queue_run_id = string_copy_taint(argv[++i], TRUE); } /* -q[f][f][l][G/]: Run the queue at regular intervals, optionally @@ -3331,7 +3327,7 @@ for (i = 1; i < argc; i++) in all cases provided there are no further characters in this argument. */ - if (*argrest != 0) + if (*argrest) for (int i = 0; i < nelem(rsopts); i++) if (Ustrcmp(argrest, rsopts[i]) == 0) { @@ -3345,9 +3341,9 @@ for (i = 1; i < argc; i++) pick out particular messages. */ if (*argrest) - deliver_selectstring = argrest; + deliver_selectstring = string_copy_taint(argrest, TRUE); else if (i+1 < argc) - deliver_selectstring = argv[++i]; + deliver_selectstring = string_copy_taint(argv[++i], TRUE); else exim_fail("exim: string expected after -R\n"); break; @@ -3384,9 +3380,9 @@ for (i = 1; i < argc; i++) pick out particular messages. */ if (*argrest) - deliver_selectstring_sender = argrest; + deliver_selectstring_sender = string_copy_taint(argrest, TRUE); else if (i+1 < argc) - deliver_selectstring_sender = argv[++i]; + deliver_selectstring_sender = string_copy_taint(argv[++i], TRUE); else exim_fail("exim: string expected after -S\n"); break; @@ -3398,7 +3394,7 @@ for (i = 1; i < argc; i++) case 'T': if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0) - fudged_queue_times = argv[++i]; + fudged_queue_times = string_copy_taint(argv[++i], TRUE); else badarg = TRUE; break; @@ -3406,7 +3402,7 @@ for (i = 1; i < argc; i++) /* -t: Set flag to extract recipients from body of message. */ case 't': - if (*argrest == 0) extract_recipients = TRUE; + if (!*argrest) extract_recipients = TRUE; /* -ti: Set flag to extract recipients from body of message, and also specify that dot does not end the message. */ @@ -3438,7 +3434,7 @@ for (i = 1; i < argc; i++) /* -v: verify things - this is a very low-level debugging */ case 'v': - if (*argrest == 0) + if (!*argrest) { debug_selector |= D_v; debug_file = stderr; @@ -3458,22 +3454,22 @@ for (i = 1; i < argc; i++) As Exim is 8-bit clean, it just ignores this flag. */ case 'x': - if (*argrest != 0) badarg = TRUE; + if (*argrest) badarg = TRUE; break; /* -X: in sendmail: takes one parameter, logfile, and sends debugging logs to that file. We swallow the parameter and otherwise ignore it. */ case 'X': - if (*argrest == '\0') + if (!*argrest) if (++i >= argc) exim_fail("exim: string expected after -X\n"); break; case 'z': - if (*argrest == '\0') + if (!*argrest) if (++i < argc) - log_oneline = argv[i]; + log_oneline = string_copy_taint(argv[i], TRUE); else exim_fail("exim: file name expected after %s\n", argv[i-1]); break; @@ -3495,12 +3491,15 @@ for (i = 1; i < argc; i++) /* If -R or -S have been specified without -q, assume a single queue run. */ -if ( (deliver_selectstring || deliver_selectstring_sender) - && queue_interval < 0) - queue_interval = 0; + if ( (deliver_selectstring || deliver_selectstring_sender) + && queue_interval < 0) + queue_interval = 0; END_ARG: + store_pool = old_pool; + } + /* If usage_wanted is set we call the usage function - which never returns */ if (usage_wanted) exim_usage(called_as); @@ -4083,11 +4082,12 @@ if ( (debug_selector & D_any || LOGGING(arguments)) p = big_buffer + 3; } printing = string_printing(argv[i]); - if (printing[0] == 0) quote = US"\""; else + if (!*printing) quote = US"\""; + else { const uschar *pp = printing; quote = US""; - while (*pp != 0) if (isspace(*pp++)) { quote = US"\""; break; } + while (*pp) if (isspace(*pp++)) { quote = US"\""; break; } } p += sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size - (p - big_buffer) - 4), printing, quote); @@ -4123,19 +4123,19 @@ script. */ if (bi_option) { (void)fclose(config_file); - if (bi_command != NULL) + if (bi_command) { int i = 0; uschar *argv[3]; argv[i++] = bi_command; - if (alias_arg != NULL) argv[i++] = alias_arg; + if (alias_arg) argv[i++] = alias_arg; argv[i++] = NULL; 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] == NULL)? US"" : argv[1]); + argv[1] ? argv[1] : US""); execv(CS argv[0], (char *const *)argv); exim_fail("exim: exec failed: %s\n", strerror(errno)); @@ -4614,6 +4614,8 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD) { int status; pid_t pid; + /*XXX This use of argv[i] for msg_id should really be tainted, but doing + that runs into a later copy into the untainted global message_id[] */ if (i == argc - 1) (void)deliver_message(argv[i], forced_delivery, deliver_give_up); else if ((pid = exim_fork(US"cmdline-delivery")) == 0) @@ -5098,6 +5100,7 @@ if (host_checking) if (smtp_start_session()) { + rmark reset_point; for (; (reset_point = store_mark()); store_reset(reset_point)) { if (smtp_setup_msg() <= 0) break; @@ -5349,7 +5352,7 @@ collapsed). */ while (more) { - reset_point = store_mark(); + rmark reset_point = store_mark(); message_id[0] = 0; /* Handle the SMTP case; call smtp_setup_mst() to deal with the initial SMTP @@ -5479,8 +5482,7 @@ while (more) errmess = US"unqualified recipient address not allowed"; } - if (recipient == NULL) - { + if (!recipient) if (error_handling == ERRORS_STDERR) { fprintf(stderr, "exim: bad recipient address \"%s\": %s\n", @@ -5497,7 +5499,6 @@ while (more) moan_to_sender(ERRMESS_BADARGADDRESS, &eblock, NULL, stdin, TRUE)? errors_sender_rc : EXIT_FAILURE; } - } receive_add_recipient(string_copy_taint(recipient, TRUE), -1); s = ss; @@ -5510,8 +5511,8 @@ while (more) DEBUG(D_receive) { - if (sender_address != NULL) debug_printf("Sender: %s\n", sender_address); - if (recipients_list != NULL) + if (sender_address) debug_printf("Sender: %s\n", sender_address); + if (recipients_list) { debug_printf("Recipients:\n"); for (int i = 0; i < recipients_count; i++)