* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) University of Cambridge 1995 - 2020 */
+/* Copyright (c) The Exim maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
order (note that "_" comes before the lower case letters). Some of them are
stored in the publicly visible instance block - these are flagged with the
opt_public flag. */
+#define LOFF(field) OPT_OFF(appendfile_transport_options_block, field)
optionlist appendfile_transport_options[] = {
#ifdef SUPPORT_MAILDIR
- { "*expand_maildir_use_size_file", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, expand_maildir_use_size_file) },
+ { "*expand_maildir_use_size_file", opt_stringptr, LOFF(expand_maildir_use_size_file) },
#endif
- { "*set_use_fcntl_lock",opt_bool | opt_hidden,
- (void *)offsetof(appendfile_transport_options_block, set_use_fcntl) },
- { "*set_use_flock_lock",opt_bool | opt_hidden,
- (void *)offsetof(appendfile_transport_options_block, set_use_flock) },
- { "*set_use_lockfile", opt_bool | opt_hidden,
- (void *)offsetof(appendfile_transport_options_block, set_use_lockfile) },
+ { "*set_use_fcntl_lock",opt_bool | opt_hidden, LOFF(set_use_fcntl) },
+ { "*set_use_flock_lock",opt_bool | opt_hidden, LOFF(set_use_flock) },
+ { "*set_use_lockfile", opt_bool | opt_hidden, LOFF(set_use_lockfile) },
#ifdef SUPPORT_MBX
- { "*set_use_mbx_lock", opt_bool | opt_hidden,
- (void *)offsetof(appendfile_transport_options_block, set_use_mbx_lock) },
+ { "*set_use_mbx_lock", opt_bool | opt_hidden, LOFF(set_use_mbx_lock) },
#endif
- { "allow_fifo", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, allow_fifo) },
- { "allow_symlink", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, allow_symlink) },
- { "batch_id", opt_stringptr | opt_public,
- (void *)offsetof(transport_instance, batch_id) },
- { "batch_max", opt_int | opt_public,
- (void *)offsetof(transport_instance, batch_max) },
- { "check_group", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, check_group) },
- { "check_owner", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, check_owner) },
- { "check_string", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, check_string) },
- { "create_directory", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, create_directory) },
- { "create_file", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, create_file_string) },
- { "directory", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, dirname) },
- { "directory_file", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, dirfilename) },
- { "directory_mode", opt_octint,
- (void *)offsetof(appendfile_transport_options_block, dirmode) },
- { "escape_string", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, escape_string) },
- { "file", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, filename) },
- { "file_format", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, file_format) },
- { "file_must_exist", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, file_must_exist) },
- { "lock_fcntl_timeout", opt_time,
- (void *)offsetof(appendfile_transport_options_block, lock_fcntl_timeout) },
- { "lock_flock_timeout", opt_time,
- (void *)offsetof(appendfile_transport_options_block, lock_flock_timeout) },
- { "lock_interval", opt_time,
- (void *)offsetof(appendfile_transport_options_block, lock_interval) },
- { "lock_retries", opt_int,
- (void *)offsetof(appendfile_transport_options_block, lock_retries) },
- { "lockfile_mode", opt_octint,
- (void *)offsetof(appendfile_transport_options_block, lockfile_mode) },
- { "lockfile_timeout", opt_time,
- (void *)offsetof(appendfile_transport_options_block, lockfile_timeout) },
- { "mailbox_filecount", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, mailbox_filecount_string) },
- { "mailbox_size", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, mailbox_size_string) },
+ { "allow_fifo", opt_bool, LOFF(allow_fifo) },
+ { "allow_symlink", opt_bool, LOFF(allow_symlink) },
+ { "batch_id", opt_stringptr | opt_public, OPT_OFF(transport_instance, batch_id) },
+ { "batch_max", opt_int | opt_public, OPT_OFF(transport_instance, batch_max) },
+ { "check_group", opt_bool, LOFF(check_group) },
+ { "check_owner", opt_bool, LOFF(check_owner) },
+ { "check_string", opt_stringptr, LOFF(check_string) },
+ { "create_directory", opt_bool, LOFF(create_directory) },
+ { "create_file", opt_stringptr, LOFF(create_file_string) },
+ { "directory", opt_stringptr, LOFF(dirname) },
+ { "directory_file", opt_stringptr, LOFF(dirfilename) },
+ { "directory_mode", opt_octint, LOFF(dirmode) },
+ { "escape_string", opt_stringptr, LOFF(escape_string) },
+ { "file", opt_stringptr, LOFF(filename) },
+ { "file_format", opt_stringptr, LOFF(file_format) },
+ { "file_must_exist", opt_bool, LOFF(file_must_exist) },
+ { "lock_fcntl_timeout", opt_time, LOFF(lock_fcntl_timeout) },
+ { "lock_flock_timeout", opt_time, LOFF(lock_flock_timeout) },
+ { "lock_interval", opt_time, LOFF(lock_interval) },
+ { "lock_retries", opt_int, LOFF(lock_retries) },
+ { "lockfile_mode", opt_octint, LOFF(lockfile_mode) },
+ { "lockfile_timeout", opt_time, LOFF(lockfile_timeout) },
+ { "mailbox_filecount", opt_stringptr, LOFF(mailbox_filecount_string) },
+ { "mailbox_size", opt_stringptr, LOFF(mailbox_size_string) },
#ifdef SUPPORT_MAILDIR
- { "maildir_format", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, maildir_format ) } ,
- { "maildir_quota_directory_regex", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, maildir_dir_regex) },
- { "maildir_retries", opt_int,
- (void *)offsetof(appendfile_transport_options_block, maildir_retries) },
- { "maildir_tag", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, maildir_tag) },
- { "maildir_use_size_file", opt_expand_bool,
- (void *)offsetof(appendfile_transport_options_block, maildir_use_size_file ) } ,
- { "maildirfolder_create_regex", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, maildirfolder_create_regex ) },
+ { "maildir_format", opt_bool, LOFF(maildir_format ) } ,
+ { "maildir_quota_directory_regex", opt_stringptr, LOFF(maildir_dir_regex) },
+ { "maildir_retries", opt_int, LOFF(maildir_retries) },
+ { "maildir_tag", opt_stringptr, LOFF(maildir_tag) },
+ { "maildir_use_size_file", opt_expand_bool, LOFF(maildir_use_size_file ) } ,
+ { "maildirfolder_create_regex", opt_stringptr, LOFF(maildirfolder_create_regex ) },
#endif /* SUPPORT_MAILDIR */
#ifdef SUPPORT_MAILSTORE
- { "mailstore_format", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, mailstore_format ) },
- { "mailstore_prefix", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, mailstore_prefix ) },
- { "mailstore_suffix", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, mailstore_suffix ) },
+ { "mailstore_format", opt_bool, LOFF(mailstore_format ) },
+ { "mailstore_prefix", opt_stringptr, LOFF(mailstore_prefix ) },
+ { "mailstore_suffix", opt_stringptr, LOFF(mailstore_suffix ) },
#endif /* SUPPORT_MAILSTORE */
#ifdef SUPPORT_MBX
- { "mbx_format", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, mbx_format ) } ,
+ { "mbx_format", opt_bool, LOFF(mbx_format ) } ,
#endif /* SUPPORT_MBX */
- { "message_prefix", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, message_prefix) },
- { "message_suffix", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, message_suffix) },
- { "mode", opt_octint,
- (void *)offsetof(appendfile_transport_options_block, mode) },
- { "mode_fail_narrower",opt_bool,
- (void *)offsetof(appendfile_transport_options_block, mode_fail_narrower) },
- { "notify_comsat", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, notify_comsat) },
- { "quota", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, quota) },
- { "quota_directory", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, quota_directory) },
- { "quota_filecount", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, quota_filecount) },
- { "quota_is_inclusive", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, quota_is_inclusive) },
- { "quota_size_regex", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, quota_size_regex) },
- { "quota_warn_message", opt_stringptr | opt_public,
- (void *)offsetof(transport_instance, warn_message) },
- { "quota_warn_threshold", opt_stringptr,
- (void *)offsetof(appendfile_transport_options_block, quota_warn_threshold) },
- { "use_bsmtp", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, use_bsmtp) },
- { "use_crlf", opt_bool,
- (void *)offsetof(appendfile_transport_options_block, use_crlf) },
- { "use_fcntl_lock", opt_bool_set,
- (void *)offsetof(appendfile_transport_options_block, use_fcntl) },
- { "use_flock_lock", opt_bool_set,
- (void *)offsetof(appendfile_transport_options_block, use_flock) },
- { "use_lockfile", opt_bool_set,
- (void *)offsetof(appendfile_transport_options_block, use_lockfile) },
+ { "message_prefix", opt_stringptr, LOFF(message_prefix) },
+ { "message_suffix", opt_stringptr, LOFF(message_suffix) },
+ { "mode", opt_octint, LOFF(mode) },
+ { "mode_fail_narrower",opt_bool, LOFF(mode_fail_narrower) },
+ { "notify_comsat", opt_bool, LOFF(notify_comsat) },
+ { "quota", opt_stringptr, LOFF(quota) },
+ { "quota_directory", opt_stringptr, LOFF(quota_directory) },
+ { "quota_filecount", opt_stringptr, LOFF(quota_filecount) },
+ { "quota_is_inclusive", opt_bool, LOFF(quota_is_inclusive) },
+ { "quota_size_regex", opt_stringptr, LOFF(quota_size_regex) },
+ { "quota_warn_message", opt_stringptr | opt_public, OPT_OFF(transport_instance, warn_message) },
+ { "quota_warn_threshold", opt_stringptr, LOFF(quota_warn_threshold) },
+ { "use_bsmtp", opt_bool, LOFF(use_bsmtp) },
+ { "use_crlf", opt_bool, LOFF(use_crlf) },
+ { "use_fcntl_lock", opt_bool_set, LOFF(use_fcntl) },
+ { "use_flock_lock", opt_bool_set, LOFF(use_flock) },
+ { "use_lockfile", opt_bool_set, LOFF(use_lockfile) },
#ifdef SUPPORT_MBX
- { "use_mbx_lock", opt_bool_set,
- (void *)offsetof(appendfile_transport_options_block, use_mbx_lock) },
+ { "use_mbx_lock", opt_bool_set, LOFF(use_mbx_lock) },
#endif /* SUPPORT_MBX */
};
/* Default private options block for the appendfile transport. */
appendfile_transport_options_block appendfile_transport_option_defaults = {
- NULL, /* filename */
- NULL, /* dirname */
- US"q${base62:$tod_epoch}-$inode", /* dirfilename */
- NULL, /* message_prefix (default reset in init if not bsmtp) */
- NULL, /* message_suffix (ditto) */
- US"anywhere", /* create_file_string (string value for create_file) */
- NULL, /* quota */
- NULL, /* quota_directory */
- NULL, /* quota_filecount */
- NULL, /* quota_size_regex */
- NULL, /* quota_warn_threshold */
- NULL, /* mailbox_size_string */
- NULL, /* mailbox_filecount_string */
- NULL, /* expand_maildir_use_size_file */
- US"^(?:cur|new|\\..*)$", /* maildir_dir_regex */
- NULL, /* maildir_tag */
- NULL, /* maildirfolder_create_regex */
- NULL, /* mailstore_prefix */
- NULL, /* mailstore_suffix */
- NULL, /* check_string (default changed for non-bsmtp file)*/
- NULL, /* escape_string (ditto) */
- NULL, /* file_format */
- 0, /* quota_value */
- 0, /* quota_warn_threshold_value */
- -1, /* mailbox_size_value */
- -1, /* mailbox_filecount_value */
- 0, /* quota_filecount_value */
- APPENDFILE_MODE, /* mode */
- APPENDFILE_DIRECTORY_MODE, /* dirmode */
- APPENDFILE_LOCKFILE_MODE, /* lockfile_mode */
- 30*60, /* lockfile_timeout */
- 0, /* lock_fcntl_timeout */
- 0, /* lock_flock_timeout */
- 10, /* lock_retries */
- 3, /* lock_interval */
- 10, /* maildir_retries */
- create_anywhere,/* create_file */
- 0, /* options */
- FALSE, /* allow_fifo */
- FALSE, /* allow_symlink */
- FALSE, /* check_group */
- TRUE, /* check_owner */
- TRUE, /* create_directory */
- FALSE, /* notify_comsat */
- TRUE, /* use_lockfile */
- FALSE, /* set_use_lockfile */
- TRUE, /* use_fcntl */
- FALSE, /* set_use_fcntl */
- FALSE, /* use_flock */
- FALSE, /* set_use_flock */
- FALSE, /* use_mbx_lock */
- FALSE, /* set_use_mbx_lock */
- FALSE, /* use_bsmtp */
- FALSE, /* use_crlf */
- FALSE, /* file_must_exist */
- TRUE, /* mode_fail_narrower */
- FALSE, /* maildir_format */
- FALSE, /* maildir_use_size_file */
- FALSE, /* mailstore_format */
- FALSE, /* mbx_format */
- FALSE, /* quota_warn_threshold_is_percent */
- TRUE, /* quota_is_inclusive */
- FALSE, /* quota_no_check */
- FALSE /* quota_filecount_no_check */
+ /* all non-mentioned members zero/null/false */
+ .dirfilename = US"q${base62:$tod_epoch}-$inode",
+ .create_file_string = US"anywhere",
+ .maildir_dir_regex = US"^(?:cur|new|\\..*)$",
+ .mailbox_size_value = -1,
+ .mailbox_filecount_value = -1,
+ .mode = APPENDFILE_MODE,
+ .dirmode = APPENDFILE_DIRECTORY_MODE,
+ .lockfile_mode = APPENDFILE_LOCKFILE_MODE,
+ .lockfile_timeout = 30*60,
+ .lock_retries = 10,
+ .lock_interval = 3,
+ .maildir_retries = 10,
+ .create_file = create_anywhere,
+ .check_owner = TRUE,
+ .create_directory = TRUE,
+ .notify_comsat = FALSE,
+ .use_lockfile = TRUE,
+ .use_fcntl = TRUE,
+ .mode_fail_narrower = TRUE,
+ .quota_is_inclusive = TRUE,
};
uschar *q = ob->quota;
double default_value = 0.0;
-addrlist = addrlist; /* Keep picky compilers happy */
-dummy = dummy;
-uid = uid;
-gid = gid;
-
if (ob->expand_maildir_use_size_file)
ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file,
US"`maildir_use_size_file` in transport", tblock->name);
for (int i = 0; i < 5; i++)
{
- double d;
+ double d = default_value;
int no_check = 0;
uschar *which = NULL;
- if (q == NULL) d = default_value;
- else
+ if (q)
{
- uschar *rest;
- uschar *s = expand_string(q);
+ uschar * rest, * s;
- if (!s)
+ if (!(s = expand_string(q)))
{
*errmsg = string_sprintf("Expansion of \"%s\" in %s transport failed: "
"%s", q, tblock->name, expand_string_message);
rest += sizeof("/no_check") - 1;
}
- while (isspace(*rest)) rest++;
+ Uskip_whitespace(&rest);
- if (*rest != 0)
+ if (*rest)
{
*errmsg = string_sprintf("Malformed value \"%s\" (expansion of \"%s\") "
"in %s transport", s, q, tblock->name);
break;
case 2:
- if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4)
- which = US"quota_warn_threshold";
+ if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4)
+ which = US"quota_warn_threshold";
ob->quota_warn_threshold_value = (off_t)d;
q = ob->mailbox_size_string;
default_value = -1.0;
{
appendfile_transport_options_block *ob =
(appendfile_transport_options_block *)(tblock->options_block);
+uschar * s;
/* Set up the setup entry point, to be called in the privileged state */
/* If "create_file" is set, check that a valid option is given, and set the
integer variable. */
-if (ob->create_file_string)
+if ((s = ob->create_file_string ) && *s)
{
- int value = 0;
- if (Ustrcmp(ob->create_file_string, "anywhere") == 0)
- value = create_anywhere;
- else if (Ustrcmp(ob->create_file_string, "belowhome") == 0)
- value = create_belowhome;
- else if (Ustrcmp(ob->create_file_string, "inhome") == 0)
- value = create_inhome;
+ int val = 0;
+ if (Ustrcmp(s, "anywhere") == 0) val = create_anywhere;
+ else if (*s == '/' || Ustrcmp(s, "belowhome") == 0) val = create_belowhome;
+ else if (Ustrcmp(s, "inhome") == 0) val = create_inhome;
else
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "invalid value given for \"file_create\" for the %s transport: %s",
- tblock->name, ob->create_file_string);
- ob->create_file = value;
+ "invalid value given for \"file_create\" for the %s transport: '%s'",
+ tblock->name, s);
+ ob->create_file = val;
}
/* If quota_warn_threshold is set, set up default for warn_message. It may
/* Search the formats for a match */
-while ((s = string_nextinlist(&format,&sep,big_buffer,big_buffer_size)))
+/* not expanded so cannot be tainted */
+while ((s = string_nextinlist(&format, &sep, big_buffer, big_buffer_size)))
{
int slen = Ustrlen(s);
BOOL match = len >= slen && Ustrncmp(data, s, slen) == 0;
DIR *dir;
off_t sum = 0;
int count = *countptr;
-struct dirent *ent;
-struct stat statbuf;
-if (!(dir = opendir(CS dirname))) return 0;
+if (!(dir = exim_opendir(dirname))) return 0;
-while ((ent = readdir(dir)))
+for (struct dirent *ent; ent = readdir(dir); )
{
uschar * path, * name = US ent->d_name;
+ struct stat statbuf;
if (Ustrcmp(name, ".") == 0 || Ustrcmp(name, "..") == 0) continue;
Arguments:
filename the file name
create_file the ob->create_file option
+ deliver_dir the delivery directory
Returns: TRUE if creation is permitted
*/
static BOOL
-check_creation(uschar *filename, int create_file)
+check_creation(uschar *filename, int create_file, const uschar * deliver_dir)
{
BOOL yield = TRUE;
-if (deliver_home && create_file != create_anywhere)
+if (deliver_dir && create_file != create_anywhere)
{
- int len = Ustrlen(deliver_home);
+ int len = Ustrlen(deliver_dir);
uschar *file = filename;
while (file[0] == '/' && file[1] == '/') file++;
- if (Ustrncmp(file, deliver_home, len) != 0 || file[len] != '/' ||
- ( Ustrchr(file+len+2, '/') != NULL &&
- (
- create_file != create_belowhome ||
- Ustrstr(file+len, "/../") != NULL
- )
- )
+ if ( Ustrncmp(file, deliver_dir, len) != 0
+ || file[len] != '/'
+ || Ustrchr(file+len+2, '/') != NULL
+ && ( create_file != create_belowhome
+ || Ustrstr(file+len, "/../") != NULL
+ )
) yield = FALSE;
/* If yield is TRUE, the file name starts with the home directory, and does
if (rp)
{
uschar hdbuffer[PATH_MAX+1];
- uschar *rph = deliver_home;
+ const uschar * rph = deliver_dir;
int rlen = Ustrlen(big_buffer);
- if ((rp = US realpath(CS deliver_home, CS hdbuffer)))
+ if ((rp = US realpath(CS deliver_dir, CS hdbuffer)))
{
rph = hdbuffer;
len = Ustrlen(rph);
{
yield = FALSE;
DEBUG(D_transport) debug_printf("Real path \"%s\" does not match \"%s\"\n",
- big_buffer, deliver_home);
+ big_buffer, deliver_dir);
}
}
}
appendfile_transport_options_block *ob =
(appendfile_transport_options_block *)(tblock->options_block);
struct stat statbuf;
+const uschar * deliver_dir;
uschar *fdname = NULL;
uschar *filename = NULL;
uschar *hitchname = NULL;
}
if (!fdname)
{
- addr->transport_return = PANIC;
addr->message = string_sprintf("Mandatory file or directory option "
"missing from %s transport", tblock->name);
- return FALSE;
+ goto ret_panic;
}
}
if ((ob->maildir_format || ob->mailstore_format) && !isdirectory)
{
- addr->transport_return = PANIC;
addr->message = string_sprintf("mail%s_format requires \"directory\" "
"to be specified for the %s transport",
ob->maildir_format ? "dir" : "store", tblock->name);
- return FALSE;
+ goto ret_panic;
}
if (!(path = expand_string(fdname)))
{
- addr->transport_return = PANIC;
addr->message = string_sprintf("Expansion of \"%s\" (file or directory "
"name for %s transport) failed: %s", fdname, tblock->name,
expand_string_message);
- return FALSE;
+ goto ret_panic;
}
+{ uschar *m;
+if (m = is_tainted2(path, 0, "Tainted '%s' (file or directory "
+ "name for %s transport) not permitted", path, tblock->name))
+ {
+ addr->message = m;
+ goto ret_panic;
+ }
+}
if (path[0] != '/')
{
to the true local part. */
if (testflag(addr, af_file))
- for (address_item * addr2 = addr; addr2 != NULL; addr2 = addr2->next)
+ for (address_item * addr2 = addr; addr2; addr2 = addr2->next)
addr2->local_part = string_copy(path);
/* The available mailbox formats depend on whether it is a directory or a file
return FALSE;
}
+/* If an absolute path was given for create_file the it overrides deliver_home
+(here) and de-taints the filename (below, after check_creation() */
+
+deliver_dir = *ob->create_file_string == '/'
+ ? ob->create_file_string : deliver_home;
+
/* Handle the case of a file name. If the file name is /dev/null, we can save
ourselves some effort and just give a success return right away. */
}
/* Set the name of the file to be opened, and the file to which the data
- is written, and find out if we are permitted to create a non-existent file. */
+ is written, and find out if we are permitted to create a non-existent file.
+ If the create_file option is an absolute path and the file was within it,
+ de-taint. Chaeck for a tainted path. */
+ if ( (allow_creation_here = check_creation(path, ob->create_file, deliver_dir))
+ && ob->create_file == create_belowhome)
+ if (is_tainted(path))
+ {
+ DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
+ path = string_copy_taint(path, FALSE);
+ }
+
+ if (is_tainted(path)) goto tainted_ret_panic;
dataname = filename = path;
- allow_creation_here = check_creation(filename, ob->create_file);
/* If ob->create_directory is set, attempt to create the directories in
which this mailbox lives, but only if we are permitted to create the file
addr->basic_errno = errno;
addr->message =
string_sprintf("failed to create directories for %s: %s", path,
- strerror(errno));
+ exim_errstr(errno));
DEBUG(D_transport) debug_printf("%s transport: %s\n", tblock->name, path);
return FALSE;
}
if (statbuf.st_nlink != 1)
{
addr->basic_errno = ERRNO_NOTREGULAR;
- addr->message = string_sprintf("mailbox %s%s has too many links (%d)",
- filename, islink ? " (symlink)" : "", statbuf.st_nlink);
+ addr->message = string_sprintf("mailbox %s%s has too many links (%lu)",
+ filename, islink ? " (symlink)" : "", (unsigned long)statbuf.st_nlink);
goto RETURN;
}
else
{
- uschar *check_path = path; /* Default quota check path */
+ uschar *check_path; /* Default quota check path */
const pcre *regex = NULL; /* Regex for file size from file name */
- if (!check_creation(string_sprintf("%s/any", path), ob->create_file))
+ if (!check_creation(string_sprintf("%s/any", path),
+ ob->create_file, deliver_dir))
{
addr->basic_errno = ERRNO_BADCREATE;
addr->message = string_sprintf("tried to create file in %s, but "
goto RETURN;
}
+ /* If the create_file option is an absolute path and the file was within
+ it, de-taint. Otherwise check for taint. */
+
+ if (is_tainted(path))
+ if (ob->create_file == create_belowhome)
+ {
+ DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
+ path = string_copy_taint(path, FALSE);
+ }
+ else
+ goto tainted_ret_panic;
+
+ check_path = path;
+
#ifdef SUPPORT_MAILDIR
/* For a maildir delivery, ensure that all the relevant directories exist,
and a maildirfolder file if necessary. */
{
if (!(check_path = expand_string(ob->quota_directory)))
{
- addr->transport_return = PANIC;
addr->message = string_sprintf("Expansion of \"%s\" (quota_directory "
"name for %s transport) failed: %s", ob->quota_directory,
tblock->name, expand_string_message);
- return FALSE;
+ goto ret_panic;
}
if (check_path[0] != '/')
{
uschar *new_check_path = string_copy(check_path);
uschar *slash = Ustrrchr(new_check_path, '/');
- if (slash != NULL)
+ if (slash)
{
- if (slash[1] == 0)
+ if (!slash[1])
{
*slash = 0;
slash = Ustrrchr(new_check_path, '/');
}
- if (slash != NULL)
+ if (slash)
{
*slash = 0;
check_path = new_check_path;
{
uschar *s = path + check_path_len;
while (*s == '/') s++;
- s = (*s == 0) ? US "new" : string_sprintf("%s/new", s);
+ s = *s ? string_sprintf("%s/new", s) : US"new";
if (pcre_exec(dir_regex, NULL, CS s, Ustrlen(s), 0, 0, NULL, 0) < 0)
{
disable_quota = TRUE;
count. Note that ob->quota_filecount_value cannot be set without
ob->quota_value being set. */
- if (!disable_quota &&
- (ob->quota_value > 0 || THRESHOLD_CHECK) &&
- (mailbox_size < 0 ||
- (mailbox_filecount < 0 && ob->quota_filecount_value > 0)))
+ if ( !disable_quota
+ && (ob->quota_value > 0 || THRESHOLD_CHECK)
+ && ( mailbox_size < 0
+ || mailbox_filecount < 0 && ob->quota_filecount_value > 0
+ ) )
{
off_t size;
int filecount = 0;
if (nametag && !expand_string(nametag) && !f.expand_string_forcedfail)
{
- addr->transport_return = PANIC;
addr->message = string_sprintf("Expansion of \"%s\" (maildir_tag "
"for %s transport) failed: %s", nametag, tblock->name,
expand_string_message);
- return FALSE;
+ goto ret_panic;
}
/* We ensured the existence of all the relevant directories above. Attempt
uschar *basename;
(void)gettimeofday(&msg_tv, NULL);
- basename = string_sprintf(TIME_T_FMT ".H%luP" PID_T_FMT ".%s",
+ basename = string_sprintf(TIME_T_FMT ".M%luP" PID_T_FMT ".%s",
msg_tv.tv_sec, msg_tv.tv_usec, getpid(), primary_hostname);
filename = dataname = string_sprintf("tmp/%s", basename);
dataname = string_sprintf("%s.msg", mailstore_basename);
fd = Uopen(filename, O_WRONLY|O_CREAT|O_EXCL, mode);
- if (fd < 0 && /* failed to open, and */
- (errno != ENOENT || /* either not non-exist */
- !ob->create_directory || /* or not allowed to make */
- !directory_make(NULL, path, ob->dirmode, FALSE) || /* or failed to create dir */
- (fd = Uopen(filename, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0)) /* or then failed to open */
+ if ( fd < 0 /* failed to open, and */
+ && ( errno != ENOENT /* either not non-exist */
+ || !ob->create_directory /* or not allowed to make */
+ || !directory_make(NULL, path, ob->dirmode, FALSE) /* or failed to create dir */
+ || (fd = Uopen(filename, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0 /* or then failed to open */
+ ) )
{
addr->basic_errno = errno;
addr->message = string_sprintf("while creating file %s", filename);
if (!(env_file = fdopen(fd, "wb")))
{
addr->basic_errno = errno;
- addr->transport_return = PANIC;
addr->message = string_sprintf("fdopen of %s ("
"for %s transport) failed", filename, tblock->name);
(void)close(fd);
Uunlink(filename);
- return FALSE;
+ goto ret_panic;
}
/* Write the envelope file, then close it. */
{
if (!f.expand_string_forcedfail)
{
- addr->transport_return = PANIC;
addr->message = string_sprintf("Expansion of \"%s\" (mailstore "
"prefix for %s transport) failed: %s", ob->mailstore_prefix,
tblock->name, expand_string_message);
(void)fclose(env_file);
Uunlink(filename);
- return FALSE;
+ goto ret_panic;
}
}
else
{
if (!f.expand_string_forcedfail)
{
- addr->transport_return = PANIC;
addr->message = string_sprintf("Expansion of \"%s\" (mailstore "
"suffix for %s transport) failed: %s", ob->mailstore_suffix,
tblock->name, expand_string_message);
(void)fclose(env_file);
Uunlink(filename);
- return FALSE;
+ goto ret_panic;
}
}
else
}
+if (verify_mode)
+ {
+ addr->basic_errno = errno;
+ addr->message = US"Over quota";
+ addr->transport_return = yield;
+ DEBUG(D_transport)
+ debug_printf("appendfile (verify) yields %d with errno=%d more_errno=%d\n",
+ yield, addr->basic_errno, addr->more_errno);
+
+ goto RETURN;
+ }
+
/* If we are writing in MBX format, what we actually do is to write the message
to a temporary file, and then copy it to the real file once we know its size.
This is the most straightforward way of getting the correct length in the
put in the first address of a batch. */
return FALSE;
+
+tainted_ret_panic:
+ addr->message = string_sprintf("Tainted '%s' (file or directory "
+ "name for %s transport) not permitted", path, tblock->name);
+ret_panic:
+ addr->transport_return = PANIC;
+ return FALSE;
}
#endif /*!MACRO_PREDEF*/