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;
/* 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;
/* -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
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;
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
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)
{
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);
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)
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;
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;
{
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;
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;
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;
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':
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;
/* -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;
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*/
-Mvl show log
*/
- else if (*argrest == 0)
+ else if (!*argrest)
{
msg_action = MSG_DELIVER;
forced_delivery = f.deliver_force_thaw = TRUE;
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)
{
for sendmail it askes for "me too". Exim always does this. */
case 'm':
- if (*argrest != 0) badarg = TRUE;
+ if (*argrest) badarg = TRUE;
break;
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;
-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;
/* -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 */
/* -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 */
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 */
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 */
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 */
/* -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;
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);
+ received_protocol = string_copyn_taint(argrest, hn - argrest, TRUE);
store_pool = old_pool;
- sender_host_name = hn + 1;
+ sender_host_name = string_copy_taint(hn + 1, TRUE);
}
}
break;
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<name>/]<n>: Run the queue at regular intervals, optionally
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)
{
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;
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;
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;
/* -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. */
/* -v: verify things - this is a very low-level debugging */
case 'v':
- if (*argrest == 0)
+ if (!*argrest)
{
debug_selector |= D_v;
debug_file = stderr;
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;
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);
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));
{
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 = fork()) == 0)
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++)
*************************************************/
/* This function assumes that memcpy() is faster than strcpy().
+The result is explicitly nul-terminated.
*/
static inline uschar *
-string_copy_taint_trc(const uschar *s, BOOL tainted, const char * func, int line)
+string_copyn_taint_trc(const uschar * s, unsigned len,
+ BOOL tainted, const char * func, int line)
{
-int len = Ustrlen(s) + 1;
-uschar *ss = store_get_3(len, tainted, func, line);
+uschar * ss = store_get_3(len + 1, tainted, func, line);
memcpy(ss, s, len);
+ss[len] = '\0';
return ss;
}
-#define string_copy_taint(s, tainted) \
- string_copy_taint_trc((s), tainted, __FUNCTION__, __LINE__)
+static inline uschar *
+string_copy_taint_trc(const uschar * s, BOOL tainted, const char * func, int line)
+{ return string_copyn_taint_trc(s, Ustrlen(s), tainted, func, line); }
+static inline uschar *
+string_copyn_trc(const uschar * s, unsigned len, const char * func, int line)
+{ return string_copyn_taint_trc(s, len, is_tainted(s), func, line); }
static inline uschar *
string_copy_trc(const uschar * s, const char * func, int line)
-{
-return string_copy_taint_trc((s), is_tainted(s), func, line);
-}
+{ return string_copy_taint_trc(s, is_tainted(s), func, line); }
+
+
+/* String-copy functions explicitly setting the taint status */
+#define string_copyn_taint(s, len, tainted) \
+ string_copyn_taint_trc((s), (len), (tainted), __FUNCTION__, __LINE__)
+#define string_copy_taint(s, tainted) \
+ string_copy_taint_trc((s), (tainted), __FUNCTION__, __LINE__)
+
+/* Simple string-copy functions maintaining the taint */
+
+#define string_copyn(s, len) \
+ string_copyn_taint_trc((s), (len), is_tainted(s), __FUNCTION__, __LINE__)
#define string_copy(s) \
- string_copy_trc((s), __FUNCTION__, __LINE__)
+ string_copy_taint_trc((s), is_tainted(s), __FUNCTION__, __LINE__)
/*************************************************
-/*************************************************
-* Copy and save string, given length *
-*************************************************/
-
-/* It is assumed the data contains no zeros. A zero is added
-onto the end.
-
-Arguments:
- s string to copy
- n number of characters
-
-Returns: copy of string in new store
-
-This is an API for local_scan hence not static.
-*/
-
-static inline uschar *
-string_copyn(const uschar *s, int n)
-{
-uschar *ss = store_get(n + 1, is_tainted(s));
-Ustrncpy(ss, s, n);
-ss[n] = 0;
-return ss;
-}
-
/*************************************************
* Copy, lowercase, and save string, given length *
*************************************************/
╭considering: -oMa sender_host_address = $sender_host_address
├──expanding: -oMa sender_host_address = $sender_host_address
╰─────result: -oMa sender_host_address = V4NET.0.0.1
+ ╰──(tainted)
╭considering: sender_host_port = $sender_host_port
├──expanding: sender_host_port = $sender_host_port
╰─────result: sender_host_port = 1234
╭considering: -oMaa sender_host_authenticated = $sender_host_authenticated
├──expanding: -oMaa sender_host_authenticated = $sender_host_authenticated
╰─────result: -oMaa sender_host_authenticated = AAA
+ ╰──(tainted)
╭considering: -oMai authenticated_id = $authenticated_id
├──expanding: -oMai authenticated_id = $authenticated_id
╰─────result: -oMai authenticated_id = philip
╭considering: -oMi interface_address = $interface_address
├──expanding: -oMi interface_address = $interface_address
╰─────result: -oMi interface_address = 1.1.1.1
+ ╰──(tainted)
╭considering: interface_port = $interface_port
├──expanding: interface_port = $interface_port
╰─────result: interface_port = 99
╭considering: -oMr received_protocol = $received_protocol
├──expanding: -oMr received_protocol = $received_protocol
╰─────result: -oMr received_protocol = special
+ ╰──(tainted)
╭considering: -oMt sender_ident = $sender_ident
├──expanding: -oMt sender_ident = $sender_ident
╰─────result: -oMt sender_ident = me
+ ╰──(tainted)
>>>>>>>>>>>>>>>> Exim pid=pppp (main: expansion test) terminating with rc=0 >>>>>>>>>>>>>>>>
1999-03-02 09:44:33 no host name found for IP address V4NET.11.12.13
Exim version x.yz ....
╭considering: -oMa sender_host_address = $sender_host_address
├──expanding: -oMa sender_host_address = $sender_host_address
╰─────result: -oMa sender_host_address = V4NET.0.0.1
+ ╰──(tainted)
╭considering: sender_host_port = $sender_host_port
├──expanding: sender_host_port = $sender_host_port
╰─────result: sender_host_port = 1234
╭considering: -oMaa sender_host_authenticated = $sender_host_authenticated
├──expanding: -oMaa sender_host_authenticated = $sender_host_authenticated
╰─────result: -oMaa sender_host_authenticated = AAA
+ ╰──(tainted)
╭considering: -oMai authenticated_id = $authenticated_id
├──expanding: -oMai authenticated_id = $authenticated_id
╰─────result: -oMai authenticated_id = philip
╭considering: -oMi interface_address = $interface_address
├──expanding: -oMi interface_address = $interface_address
╰─────result: -oMi interface_address = 1.1.1.1
+ ╰──(tainted)
╭considering: interface_port = $interface_port
├──expanding: interface_port = $interface_port
╰─────result: interface_port = 99
╭considering: -oMr received_protocol = $received_protocol
├──expanding: -oMr received_protocol = $received_protocol
╰─────result: -oMr received_protocol = special
+ ╰──(tainted)
╭considering: ----> No lookup yet: ${if eq{black}{white}{$sender_host_name}{No}}
╭considering: black}{white}{$sender_host_name}{No}}
├──expanding: black
╭considering: -oMt sender_ident = $sender_ident
├──expanding: -oMt sender_ident = $sender_ident
╰─────result: -oMt sender_ident = me
+ ╰──(tainted)
>>>>>>>>>>>>>>>> Exim pid=pppp (main: expansion test) terminating with rc=0 >>>>>>>>>>>>>>>>
Exim version x.yz ....
changed uid/gid: forcing real = effective