X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Ftransports%2Fappendfile.c;h=f96d001825aa5fc5ff94d97ccb10cd3d2319fd21;hb=137ae145e066dda8f9d81cf6d2c9f76c15929605;hp=1e92add35ddf1610a5be3ee19ddfd119a0b25b8a;hpb=d7978c0f8af20ff4c3f770589b1bb81568aecff3;p=exim.git diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 1e92add35..f96d00182 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.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. */ @@ -18,133 +19,77 @@ 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 */ }; @@ -344,9 +289,9 @@ for (int i = 0; i < 5; i++) 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); @@ -433,19 +378,19 @@ if (ob->lock_retries == 0) ob->lock_retries = 1; /* Only one of a file name or directory name must be given. */ -if (ob->filename != NULL && ob->dirname != NULL) +if (ob->filename && ob->dirname) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " "only one of \"file\" or \"directory\" can be specified", tblock->name); /* If a file name was specified, neither quota_filecount nor quota_directory must be given. */ -if (ob->filename != NULL) +if (ob->filename) { - if (ob->quota_filecount != NULL) + if (ob->quota_filecount) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " "quota_filecount must not be set without \"directory\"", tblock->name); - if (ob->quota_directory != NULL) + if (ob->quota_directory) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " "quota_directory must not be set without \"directory\"", tblock->name); } @@ -470,7 +415,6 @@ if (ob->use_flock) #ifdef SUPPORT_MBX if (ob->mbx_format) - { if (!ob->set_use_lockfile && !ob->set_use_fcntl && !ob->set_use_flock && !ob->set_use_mbx_lock) { @@ -484,7 +428,6 @@ if (ob->mbx_format) if (!ob->set_use_flock) ob->use_flock = FALSE; if (!ob->use_fcntl && !ob->use_flock) ob->use_fcntl = TRUE; } - } #endif /* SUPPORT_MBX */ if (!ob->use_fcntl && !ob->use_flock && !ob->use_lockfile && !ob->use_mbx_lock) @@ -500,7 +443,7 @@ if (!ob->use_flock) ob->lock_flock_timeout = 0; specified, and if quota_filecount or quota_directory is given, quota must be set. */ -if (ob->dirname != NULL) +if (ob->dirname) { if (ob->maildir_format && ob->mailstore_format) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " @@ -515,19 +458,20 @@ if (ob->dirname != NULL) /* If a fixed uid field is set, then a gid field must also be set. */ -if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL) +if (tblock->uid_set && !tblock->gid_set && !tblock->expand_gid) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "user set without group for the %s transport", tblock->name); /* If "create_file" is set, check that a valid option is given, and set the integer variable. */ -if (ob->create_file_string != NULL) +if (ob->create_file_string) { 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; + 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; else @@ -541,9 +485,9 @@ if (ob->create_file_string != NULL) not be used if the actual threshold for a given delivery ends up as zero, of if it's given as a percentage and there's no quota setting. */ -if (ob->quota_warn_threshold != NULL) +if (ob->quota_warn_threshold) { - if (tblock->warn_message == NULL) tblock->warn_message = US + if (!tblock->warn_message) tblock->warn_message = US "To: $local_part@$domain\n" "Subject: Your mailbox\n\n" "This message is automatically created by mail delivery software (Exim).\n\n" @@ -564,13 +508,13 @@ if (ob->use_bsmtp) /* If not batch SMTP, not maildir, not mailstore, and directory is not set, insert default values for for the affixes and the check/escape strings. */ -else if (ob->dirname == NULL && !ob->maildir_format && !ob->mailstore_format) +else if (!ob->dirname && !ob->maildir_format && !ob->mailstore_format) { - if (ob->message_prefix == NULL) ob->message_prefix = + if (!ob->message_prefix) ob->message_prefix = US"From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}\n"; - if (ob->message_suffix == NULL) ob->message_suffix = US"\n"; - if (ob->check_string == NULL) ob->check_string = US"From "; - if (ob->escape_string == NULL) ob->escape_string = US">From "; + if (!ob->message_suffix) ob->message_suffix = US"\n"; + if (!ob->check_string) ob->check_string = US"From "; + if (!ob->escape_string) ob->escape_string = US">From "; } @@ -613,11 +557,11 @@ notify_comsat(uschar *user, off_t offset) { struct servent *sp; host_item host; -uschar buffer[256]; +uschar * s; DEBUG(D_transport) debug_printf("notify_comsat called\n"); -sprintf(CS buffer, "%.200s@" OFF_T_FMT "\n", user, offset); +s = string_sprintf("%.200s@" OFF_T_FMT "\n", user, offset); if ((sp = getservbyname("biff", "udp")) == NULL) { @@ -658,7 +602,7 @@ for (host_item * h = &host; h; h = h->next) /* Connect never fails for a UDP socket, so don't set a timeout. */ (void)ip_connect(sock, host_af, h->address, ntohs(sp->s_port), 0, NULL); - rc = send(sock, buffer, Ustrlen(buffer) + 1, 0); + rc = send(sock, s, Ustrlen(s) + 1, 0); (void)close(sock); if (rc >= 0) break; @@ -765,21 +709,18 @@ Returns: the sum of the sizes of the stattable files */ off_t -check_dir_size(uschar *dirname, int *countptr, const pcre *regex) +check_dir_size(const uschar * dirname, int *countptr, const pcre *regex) { DIR *dir; off_t sum = 0; int count = *countptr; -struct dirent *ent; -struct stat statbuf; -dir = opendir(CS dirname); -if (dir == NULL) return 0; +if (!(dir = exim_opendir(dirname))) return 0; -while ((ent = readdir(dir)) != NULL) +for (struct dirent *ent; ent = readdir(dir); ) { - uschar *name = US ent->d_name; - uschar buffer[1024]; + uschar * path, * name = US ent->d_name; + struct stat statbuf; if (Ustrcmp(name, ".") == 0 || Ustrcmp(name, "..") == 0) continue; @@ -787,7 +728,7 @@ while ((ent = readdir(dir)) != NULL) /* If there's a regex, try to find the size using it */ - if (regex != NULL) + if (regex) { int ovector[6]; if (pcre_exec(regex, NULL, CS name, Ustrlen(name), 0, 0, ovector,6) >= 2) @@ -809,26 +750,19 @@ while ((ent = readdir(dir)) != NULL) /* No regex or no match for the regex, or captured non-digits */ - if (!string_format(buffer, sizeof(buffer), "%s/%s", dirname, name)) - { - DEBUG(D_transport) - debug_printf("check_dir_size: name too long: dir=%s name=%s\n", dirname, - name); - continue; - } + path = string_sprintf("%s/%s", dirname, name); - if (Ustat(buffer, &statbuf) < 0) + if (Ustat(path, &statbuf) < 0) { DEBUG(D_transport) - debug_printf("check_dir_size: stat error %d for %s: %s\n", errno, buffer, + debug_printf("check_dir_size: stat error %d for %s: %s\n", errno, path, strerror(errno)); - continue; } - - if ((statbuf.st_mode & S_IFMT) == S_IFREG) - sum += statbuf.st_size; - else if ((statbuf.st_mode & S_IFMT) == S_IFDIR) - sum += check_dir_size(buffer, &count, regex); + else + if ((statbuf.st_mode & S_IFMT) == S_IFREG) + sum += statbuf.st_size / statbuf.st_nlink; + else if ((statbuf.st_mode & S_IFMT) == S_IFDIR) + sum += check_dir_size(path, &count, regex); } closedir(dir); @@ -1015,7 +949,7 @@ check_creation(uschar *filename, int create_file) { BOOL yield = TRUE; -if (deliver_home != NULL && create_file != create_anywhere) +if (deliver_home && create_file != create_anywhere) { int len = Ustrlen(deliver_home); uschar *file = filename; @@ -1046,7 +980,7 @@ if (deliver_home != NULL && create_file != create_anywhere) uschar *next; uschar *rp = NULL; for (uschar * slash = Ustrrchr(file, '/'); /* There is known to be one */ - rp == NULL && slash > file; /* Stop if reached beginning */ + !rp && slash > file; /* Stop if reached beginning */ slash = next) { *slash = 0; @@ -1062,14 +996,13 @@ if (deliver_home != NULL && create_file != create_anywhere) contain symbolic links, so we have to "realpath" it as well, if possible. */ - if (rp != NULL) + if (rp) { uschar hdbuffer[PATH_MAX+1]; uschar *rph = deliver_home; int rlen = Ustrlen(big_buffer); - rp = US realpath(CS deliver_home, CS hdbuffer); - if (rp != NULL) + if ((rp = US realpath(CS deliver_home, CS hdbuffer))) { rph = hdbuffer; len = Ustrlen(rph); @@ -1308,9 +1241,7 @@ variable (that holds the parent local part). It is, however, in the $address_file variable. Below, we update the local part in the address if it changes by expansion, so that the final path ends up in the log. */ -if (testflag(addr, af_file) && - ob->filename == NULL && - ob->dirname == NULL) +if (testflag(addr, af_file) && !ob->filename && !ob->dirname) { fdname = US"$address_file"; if (address_file[Ustrlen(address_file)-1] == '/' || @@ -1323,20 +1254,18 @@ if (testflag(addr, af_file) && explicitly set and (b) a non-address_file delivery, where one of "file" or "directory" must be set; initialization ensures that they are not both set. */ -if (fdname == NULL) +if (!fdname) { - fdname = ob->filename; - if (fdname == NULL) + if (!(fdname = ob->filename)) { fdname = ob->dirname; isdirectory = TRUE; } - if (fdname == 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; } } @@ -1344,22 +1273,24 @@ if (fdname == NULL) 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; } -path = expand_string(fdname); - -if (path == NULL) +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; + } +if (is_tainted(path)) + { + addr->message = string_sprintf("Tainted '%s' (file or directory " + "name for %s transport) not permitted", path, tblock->name); + goto ret_panic; } if (path[0] != '/') @@ -1374,7 +1305,7 @@ 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 @@ -1384,10 +1315,10 @@ if (isdirectory) { mbformat = #ifdef SUPPORT_MAILDIR - (ob->maildir_format) ? mbf_maildir : + ob->maildir_format ? mbf_maildir : #endif #ifdef SUPPORT_MAILSTORE - (ob->mailstore_format) ? mbf_mailstore : + ob->mailstore_format ? mbf_mailstore : #endif mbf_smail; } @@ -1395,7 +1326,7 @@ else { mbformat = #ifdef SUPPORT_MBX - (ob->mbx_format) ? mbf_mbx : + ob->mbx_format ? mbf_mbx : #endif mbf_unix; } @@ -1414,9 +1345,9 @@ DEBUG(D_transport) ob->quota_warn_threshold_is_percent ? "%" : "", isdirectory ? "directory" : "file", path, mailbox_formats[mbformat], - (ob->message_prefix == NULL) ? US"null" : string_printing(ob->message_prefix), - (ob->message_suffix == NULL) ? US"null" : string_printing(ob->message_suffix), - (ob->maildir_use_size_file) ? "yes" : "no"); + !ob->message_prefix ? US"null" : string_printing(ob->message_prefix), + !ob->message_suffix ? US"null" : string_printing(ob->message_suffix), + ob->maildir_use_size_file ? "yes" : "no"); if (!isdirectory) debug_printf(" locking by %s%s%s%s%s\n", ob->use_lockfile ? "lockfile " : "", @@ -1487,7 +1418,7 @@ if (!isdirectory) failures because if an existing file fails to open here, it will also fail again later when O_RDWR is used. */ - if (ob->file_format != NULL) + if (ob->file_format) { int cfd = Uopen(path, O_RDONLY, 0); if (cfd >= 0) @@ -1500,7 +1431,7 @@ if (!isdirectory) if (tt != tblock) { - if (tt != NULL) + if (tt) { set_process_info("delivering %s to %s using %s", message_id, addr->local_part, tt->name); @@ -1659,8 +1590,8 @@ if (!isdirectory) for (i = 0; i < ob->lock_retries; sleep(ob->lock_interval), i++) { int rc; - hd = Uopen(hitchname, O_WRONLY | O_CREAT | O_EXCL, ob->lockfile_mode); + hd = Uopen(hitchname, O_WRONLY | O_CREAT | O_EXCL, ob->lockfile_mode); if (hd < 0) { addr->basic_errno = errno; @@ -1735,7 +1666,7 @@ if (!isdirectory) int sleep_before_retry = TRUE; file_opened = FALSE; - if((use_lstat ? Ulstat(filename, &statbuf) : Ustat(filename, &statbuf)) != 0) + if ((use_lstat ? Ulstat(filename, &statbuf) : Ustat(filename, &statbuf)) != 0) { /* Let's hope that failure to stat (other than non-existence) is a rare event. */ @@ -1798,7 +1729,7 @@ if (!isdirectory) /* We have successfully created and opened the file. Ensure that the group and the mode are correct. */ - if(Uchown(filename, uid, gid) || Uchmod(filename, mode)) + if (exim_chown(filename, uid, gid) || Uchmod(filename, mode)) { addr->basic_errno = errno; addr->message = string_sprintf("while setting perms on mailbox %s", @@ -1889,7 +1820,7 @@ if (!isdirectory) permissions are greater than the existing permissions, don't change things when the mode is not from the address. */ - if ((oldmode = (oldmode & 07777)) != mode) + if ((oldmode &= 07777) != mode) { int diffs = oldmode ^ mode; if (addr->mode > 0 || (diffs & oldmode) == diffs) @@ -1939,14 +1870,10 @@ if (!isdirectory) } addr->basic_errno = errno; if (isfifo) - { addr->message = string_sprintf("while opening named pipe %s " "(could mean no process is reading it)", filename); - } else if (errno != EWOULDBLOCK) - { addr->message = string_sprintf("while opening mailbox %s", filename); - } goto RETURN; } @@ -2016,8 +1943,7 @@ if (!isdirectory) /* If file_format is set, check that the format of the file has not changed. Error data is set by the testing function. */ - if (ob->file_format != NULL && - check_file_format(fd, tblock, addr) != tblock) + if (ob->file_format && check_file_format(fd, tblock, addr) != tblock) { addr->message = US"open mailbox has changed format"; goto RETURN; @@ -2312,11 +2238,10 @@ else /* Compile the regex if there is one. */ - if (ob->quota_size_regex != NULL) + if (ob->quota_size_regex) { - regex = pcre_compile(CS ob->quota_size_regex, PCRE_COPT, - (const char **)&error, &offset, NULL); - if (regex == NULL) + if (!(regex = pcre_compile(CS ob->quota_size_regex, PCRE_COPT, + CCSS &error, &offset, NULL))) { addr->message = string_sprintf("appendfile: regular expression " "error: %s at offset %d while compiling %s", error, offset, @@ -2329,16 +2254,14 @@ else /* Use an explicitly configured directory if set */ - if (ob->quota_directory != NULL) + if (ob->quota_directory) { - check_path = expand_string(ob->quota_directory); - if (check_path == NULL) + 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] != '/') @@ -2400,13 +2323,12 @@ else const uschar *error; int offset; - if (ob->maildir_dir_regex != NULL) + if (ob->maildir_dir_regex) { int check_path_len = Ustrlen(check_path); - dir_regex = pcre_compile(CS ob->maildir_dir_regex, PCRE_COPT, - (const char **)&error, &offset, NULL); - if (dir_regex == NULL) + if (!(dir_regex = pcre_compile(CS ob->maildir_dir_regex, PCRE_COPT, + CCSS &error, &offset, NULL))) { addr->message = string_sprintf("appendfile: regular expression " "error: %s at offset %d while compiling %s", error, offset, @@ -2449,10 +2371,8 @@ else off_t size; int filecount; - maildirsize_fd = maildir_ensure_sizefile(check_path, ob, regex, dir_regex, - &size, &filecount); - - if (maildirsize_fd == -1) + if ((maildirsize_fd = maildir_ensure_sizefile(check_path, ob, regex, dir_regex, + &size, &filecount)) == -1) { addr->basic_errno = errno; addr->message = string_sprintf("while opening or reading " @@ -2543,14 +2463,12 @@ else return. The actual expansion for use happens again later, when $message_size is accurately known. */ - if (nametag != NULL && expand_string(nametag) == NULL && - !f.expand_string_forcedfail) + 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 @@ -2576,8 +2494,8 @@ else errno = EEXIST; else if (errno == ENOENT) { - fd = Uopen(filename, O_WRONLY | O_CREAT | O_EXCL, mode); - if (fd >= 0) break; + if ((fd = Uopen(filename, O_WRONLY | O_CREAT | O_EXCL, mode)) >= 0) + break; DEBUG (D_transport) debug_printf ("open failed for %s: %s\n", filename, strerror(errno)); } @@ -2606,7 +2524,7 @@ else /* Why are these here? Put in because they are present in the non-maildir directory case above. */ - if(Uchown(filename, uid, gid) || Uchmod(filename, mode)) + if (exim_chown(filename, uid, gid) || Uchmod(filename, mode)) { addr->basic_errno = errno; addr->message = string_sprintf("while setting perms on maildir %s", @@ -2652,7 +2570,7 @@ else /* Why are these here? Put in because they are present in the non-maildir directory case above. */ - if(Uchown(filename, uid, gid) || Uchmod(filename, mode)) + if (exim_chown(filename, uid, gid) || Uchmod(filename, mode)) { addr->basic_errno = errno; addr->message = string_sprintf("while setting perms on file %s", @@ -2662,33 +2580,31 @@ else /* Built a C stream from the open file descriptor. */ - if ((env_file = fdopen(fd, "wb")) == NULL) + 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 (ob->mailstore_prefix != NULL) + if (ob->mailstore_prefix) { uschar *s = expand_string(ob->mailstore_prefix); - if (s == NULL) + if (!s) { 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 @@ -2704,20 +2620,19 @@ else for (address_item * taddr = addr; taddr; taddr = taddr->next) fprintf(env_file, "%s@%s\n", taddr->local_part, taddr->domain); - if (ob->mailstore_suffix != NULL) + if (ob->mailstore_suffix) { uschar *s = expand_string(ob->mailstore_suffix); - if (s == NULL) + if (!s) { 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 @@ -2741,15 +2656,14 @@ else /* Now open the data file, and ensure that it has the correct ownership and mode. */ - fd = Uopen(dataname, O_WRONLY|O_CREAT|O_EXCL, mode); - if (fd < 0) + if ((fd = Uopen(dataname, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) { addr->basic_errno = errno; addr->message = string_sprintf("while creating file %s", dataname); Uunlink(filename); return FALSE; } - if(Uchown(dataname, uid, gid) || Uchmod(dataname, mode)) + if (exim_chown(dataname, uid, gid) || Uchmod(dataname, mode)) { addr->basic_errno = errno; addr->message = string_sprintf("while setting perms on file %s", @@ -2764,7 +2678,7 @@ else /* In all cases of writing to a new file, ensure that the file which is going to be renamed has the correct ownership and mode. */ - if(Uchown(filename, uid, gid) || Uchmod(filename, mode)) + if (exim_chown(filename, uid, gid) || Uchmod(filename, mode)) { addr->basic_errno = errno; addr->message = string_sprintf("while setting perms on file %s", @@ -2801,22 +2715,19 @@ if (!disable_quota && ob->quota_value > 0) } if (mailbox_size + (ob->quota_is_inclusive ? message_size:0) > ob->quota_value) - { - - if (!ob->quota_no_check) - { - DEBUG(D_transport) debug_printf("mailbox quota exceeded\n"); - yield = DEFER; - errno = ERRNO_EXIMQUOTA; - } - else DEBUG(D_transport) debug_printf("mailbox quota exceeded but ignored\n"); - - } + if (!ob->quota_no_check) + { + DEBUG(D_transport) debug_printf("mailbox quota exceeded\n"); + yield = DEFER; + errno = ERRNO_EXIMQUOTA; + } + else + DEBUG(D_transport) debug_printf("mailbox quota exceeded but ignored\n"); if (ob->quota_filecount_value > 0 && mailbox_filecount + (ob->quota_is_inclusive ? 1:0) > ob->quota_filecount_value) - if(!ob->quota_filecount_no_check) + if (!ob->quota_filecount_no_check) { DEBUG(D_transport) debug_printf("mailbox file count quota exceeded\n"); yield = DEFER; @@ -2838,8 +2749,7 @@ opened, so that it goes away on closure. */ #ifdef SUPPORT_MBX if (yield == OK && ob->mbx_format) { - temp_file = tmpfile(); - if (temp_file == NULL) + if (!(temp_file = tmpfile())) { addr->basic_errno = errno; addr->message = US"while setting up temporary file"; @@ -2860,10 +2770,10 @@ transport_newlines = 0; /* Write any configured prefix text first */ -if (yield == OK && ob->message_prefix != NULL && ob->message_prefix[0] != 0) +if (yield == OK && ob->message_prefix && *ob->message_prefix) { uschar *prefix = expand_string(ob->message_prefix); - if (prefix == NULL) + if (!prefix) { errno = ERRNO_EXPANDFAIL; addr->transport_return = PANIC; @@ -2889,9 +2799,9 @@ if (yield == OK && ob->use_bsmtp) else { transport_newlines++; - for (address_item * a = addr; a != NULL; a = a->next) + for (address_item * a = addr; a; a = a->next) { - address_item *b = testflag(a, af_pfr) ? a->parent: a; + address_item * b = testflag(a, af_pfr) ? a->parent : a; if (!transport_write_string(fd, "RCPT TO:<%s>%s\n", transport_rcpt_address(b, tblock->rcpt_include_affixes), cr)) { yield = DEFER; break; } @@ -2923,10 +2833,10 @@ if (yield == OK) /* Now a configured suffix. */ -if (yield == OK && ob->message_suffix != NULL && ob->message_suffix[0] != 0) +if (yield == OK && ob->message_suffix && *ob->message_suffix) { uschar *suffix = expand_string(ob->message_suffix); - if (suffix == NULL) + if (!suffix) { errno = ERRNO_EXPANDFAIL; addr->transport_return = PANIC; @@ -2939,10 +2849,9 @@ if (yield == OK && ob->message_suffix != NULL && ob->message_suffix[0] != 0) /* If batch smtp, write the terminating dot. */ -if (yield == OK && ob->use_bsmtp ) { - if(!transport_write_string(fd, ".%s\n", cr)) yield = DEFER; +if (yield == OK && ob->use_bsmtp) + if (!transport_write_string(fd, ".%s\n", cr)) yield = DEFER; else transport_newlines++; -} /* If MBX format is being used, all that writing was to the temporary file. However, if there was an earlier failure (Exim quota exceeded, for example), @@ -2952,7 +2861,7 @@ message in MBX format into the real file. Otherwise use the temporary name in any messages. */ #ifdef SUPPORT_MBX -if (temp_file != NULL && ob->mbx_format) +if (temp_file && ob->mbx_format) { int mbx_save_errno; fd = save_fd; @@ -3070,10 +2979,9 @@ if (yield != OK) "stat error %d for \"new\": %s\n", errno, strerror(errno)); } else /* Want a repeatable time when in test harness */ - { addr->more_errno = f.running_in_test_harness ? 10 : (int)time(NULL) - statbuf.st_mtime; - } + DEBUG(D_transport) debug_printf("maildir: time since \"new\" directory modified = %s\n", readconf_printtime(addr->more_errno)); @@ -3091,7 +2999,7 @@ if (yield != OK) addr->message = string_sprintf("mailbox is full " "(quota exceeded while writing to file %s)", filename); #else - addr->message = string_sprintf("mailbox is full"); + addr->message = US"mailbox is full"; #endif /* EDQUOT */ addr->user_message = US"mailbox is full"; DEBUG(D_transport) debug_printf("System quota exceeded for %s%s%s\n", @@ -3138,19 +3046,15 @@ if (yield != OK) /* Handle failure to complete writing of a data block */ else if (errno == ERRNO_WRITEINCOMPLETE) - { addr->message = string_sprintf("failed to write data block while " "writing to %s", dataname); - } /* Handle length mismatch on MBX copying */ #ifdef SUPPORT_MBX else if (errno == ERRNO_MBXLENGTH) - { addr->message = string_sprintf("length mismatch while copying MBX " "temporary file to %s", dataname); - } #endif /* SUPPORT_MBX */ /* For other errors, a general-purpose explanation, if the message is @@ -3228,7 +3132,7 @@ else This makes it possible to build values that are based on the time, and still cope with races from multiple simultaneous deliveries. */ - if (newname == NULL) + if (!newname) { uschar *renameleaf; uschar *old_renameleaf = US""; @@ -3239,7 +3143,7 @@ else renameleaf = expand_string(ob->dirfilename); deliver_inode = 0; - if (renameleaf == NULL) + if (!renameleaf) { addr->transport_return = PANIC; addr->message = string_sprintf("Expansion of \"%s\" " @@ -3286,22 +3190,19 @@ else else { - if (nametag != NULL) + if (nametag) { uschar *iptr = expand_string(nametag); - if (iptr != NULL) + if (iptr) { - uschar *etag = store_get(Ustrlen(iptr) + 2); + uschar *etag = store_get(Ustrlen(iptr) + 2, is_tainted(iptr)); uschar *optr = etag; - while (*iptr != 0) - { + for ( ; *iptr; iptr++) if (mac_isgraph(*iptr) && *iptr != '/') { if (optr == etag && isalnum(*iptr)) *optr++ = ':'; *optr++ = *iptr; } - iptr++; - } *optr = 0; renamename = string_sprintf("%s%s", newname, etag); } @@ -3342,7 +3243,7 @@ if (!isdirectory) utime(CS filename, ×); /* Notify comsat if configured to do so. It only makes sense if the configured file is the one that the comsat daemon knows about. */ -if (ob->notify_comsat && yield == OK && deliver_localpart != NULL) +if (ob->notify_comsat && yield == OK && deliver_localpart) notify_comsat(deliver_localpart, saved_size); /* Pass back the final return code in the address structure */ @@ -3390,7 +3291,7 @@ if (hd >= 0) Uunlink(lockname); /* We get here with isdirectory and filename set only in error situations. */ -if (isdirectory && filename != NULL) +if (isdirectory && filename) { Uunlink(filename); if (dataname != filename) Uunlink(dataname); @@ -3407,6 +3308,10 @@ if (wait_for_tick) exim_wait_tick(&msg_tv, 1); put in the first address of a batch. */ return FALSE; + +ret_panic: + addr->transport_return = PANIC; + return FALSE; } #endif /*!MACRO_PREDEF*/