* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim maintainers 2020 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2020 */
-/* Copyright (c) The Exim maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "../exim.h"
+
+#ifdef TRANSPORT_APPENDFILE /* Remainder of file */
#include "appendfile.h"
#ifdef SUPPORT_MAILDIR
(!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
-
/*************************************************
* Setup entry point *
*************************************************/
Returns: OK, FAIL, or DEFER
*/
-void
-open_logs(void);
-
static int
appendfile_transport_setup(transport_instance *tblock, address_item *addrlist,
transport_feedback *dummy, uid_t uid, gid_t gid, uschar **errmsg)
{
-appendfile_transport_options_block *ob =
+appendfile_transport_options_block * ob =
(appendfile_transport_options_block *)(tblock->options_block);
-uschar *q = ob->quota;
+uschar * q;
double default_value = 0.0;
-addrlist = addrlist; /* Keep picky compilers happy */
-dummy = dummy;
-uid = uid;
-gid = gid;
-
-/* we can't wait until we're not privileged anymore */
-open_logs();
-
if (ob->expand_maildir_use_size_file)
- ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file,
+ {
+ GET_OPTION("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);
+ }
/* Loop for quota, quota_filecount, quota_warn_threshold, mailbox_size,
mailbox_filecount */
+GET_OPTION("quota");
+q = ob->quota;
for (int i = 0; i < 5; i++)
{
double d = default_value;
which = US"quota";
ob->quota_value = (off_t)d;
ob->quota_no_check = no_check;
+ GET_OPTION("quota_filecount");
q = ob->quota_filecount;
break;
which = US"quota_filecount";
ob->quota_filecount_value = (int)d;
ob->quota_filecount_no_check = no_check;
+ GET_OPTION("quota_warn_threshold");
q = ob->quota_warn_threshold;
break;
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;
+ GET_OPTION("mailbox_size");
q = ob->mailbox_size_string;
default_value = -1.0;
break;
if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4)
which = US"mailbox_size";;
ob->mailbox_size_value = (off_t)d;
+ GET_OPTION("mailbox_filecount");
q = ob->mailbox_filecount_string;
break;
if (ob->maildir_format && ob->mailstore_format)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
"only one of maildir and mailstore may be specified", tblock->name);
- if (ob->quota_filecount != NULL && ob->quota == NULL)
+ if (ob->quota_filecount != NULL && !ob->quota)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
"quota must be set if quota_filecount is set", tblock->name);
- if (ob->quota_directory != NULL && ob->quota == NULL)
+ if (ob->quota_directory != NULL && !ob->quota)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n "
"quota must be set if quota_directory is set", tblock->name);
}
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'",
+ "invalid value given for \"create_file\" for the %s transport: '%s'",
tblock->name, s);
ob->create_file = val;
}
*/
static void
-notify_comsat(uschar *user, off_t offset)
+notify_comsat(const uschar * user, off_t offset)
{
struct servent *sp;
host_item host;
Arguments:
dirname the name of the directory
countptr where to add the file count (because this function recurses)
- regex a compiled regex to get the size from a name
+ re a compiled regex to get the size from a name
Returns: the sum of the sizes of the stattable files
zero if the directory cannot be opened
*/
off_t
-check_dir_size(const uschar * dirname, int *countptr, const pcre *regex)
+check_dir_size(const uschar * dirname, int * countptr, const pcre2_code * re)
{
-DIR *dir;
+DIR * dir;
off_t sum = 0;
-int count = *countptr;
+int count = *countptr, lcount = REGEX_LOOPCOUNT_STORE_RESET;
+rmark reset_point = store_mark();
if (!(dir = exim_opendir(dirname))) return 0;
-for (struct dirent *ent; 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;
count++;
+ if (--lcount == 0)
+ {
+ store_reset(reset_point); reset_point = store_mark();
+ lcount = REGEX_LOOPCOUNT_STORE_RESET;
+ }
/* If there's a regex, try to find the size using it */
- if (regex)
+ if (re)
{
- int ovector[6];
- if (pcre_exec(regex, NULL, CS name, Ustrlen(name), 0, 0, ovector,6) >= 2)
+ pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx);
+ int rc = pcre2_match(re, (PCRE2_SPTR)name, PCRE2_ZERO_TERMINATED,
+ 0, 0, md, pcre_gen_mtc_ctx);
+ PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
+ if ( rc >= 0
+ && (rc = pcre2_get_ovector_count(md)) >= 2)
{
uschar *endptr;
- off_t size = (off_t)Ustrtod(name + ovector[2], &endptr);
- if (endptr == name + ovector[3])
+ off_t size = (off_t)Ustrtod(name + ovec[2], &endptr);
+ if (endptr == name + ovec[3])
{
sum += size;
DEBUG(D_transport)
debug_printf("check_dir_size: size from %s is " OFF_T_FMT "\n", name,
size);
+ /* pcre2_match_data_free(md); gen ctx needs no free */
continue;
}
}
+ /* pcre2_match_data_free(md); gen ctx needs no free */
DEBUG(D_transport)
debug_printf("check_dir_size: regex did not match %s\n", name);
}
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);
+ sum += check_dir_size(path, &count, re);
}
closedir(dir);
debug_printf("check_dir_size: dir=%s sum=" OFF_T_FMT " count=%d\n", dirname,
sum, count);
+store_reset(reset_point);
*countptr = count;
return sum;
}
{
if (!(fdname = ob->filename))
{
+ GET_OPTION("directory");
fdname = ob->dirname;
isdirectory = TRUE;
}
if (is_tainted(path))
{
DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
- path = string_copy_taint(path, FALSE);
+ path = string_copy_taint(path, GET_UNTAINTED);
}
if (is_tainted(path)) goto tainted_ret_panic;
if (ob->create_directory && allow_creation_here)
{
uschar *p = Ustrrchr(path, '/');
- *p = '\0';
- if (!directory_make(NULL, path, ob->dirmode, FALSE))
+ p = string_copyn(path, p - path);
+ if (!directory_make(NULL, p, ob->dirmode, FALSE))
{
addr->basic_errno = errno;
addr->message =
DEBUG(D_transport) debug_printf("%s transport: %s\n", tblock->name, path);
return FALSE;
}
- *p = '/';
}
/* If file_format is set we must check that any existing file matches one of
else
{
uschar *check_path; /* Default quota check path */
- const pcre *regex = NULL; /* Regex for file size from file name */
+ const pcre2_code * re = NULL; /* Regex for file size from file name */
if (!check_creation(string_sprintf("%s/any", path),
ob->create_file, deliver_dir))
if (ob->create_file == create_belowhome)
{
DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
- path = string_copy_taint(path, FALSE);
+ path = string_copy_taint(path, GET_UNTAINTED);
}
else
goto tainted_ret_panic;
if (ob->quota_value > 0 || THRESHOLD_CHECK || ob->maildir_use_size_file)
{
- const uschar *error;
- int offset;
-
/* Compile the regex if there is one. */
if (ob->quota_size_regex)
{
- 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,
- ob->quota_size_regex);
+ if (!(re = regex_compile(ob->quota_size_regex,
+ MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx)))
return FALSE;
- }
+
DEBUG(D_transport) debug_printf("using regex for file sizes: %s\n",
ob->quota_size_regex);
}
/* Use an explicitly configured directory if set */
+ GET_OPTION("quota_directory");
if (ob->quota_directory)
{
if (!(check_path = expand_string(ob->quota_directory)))
#ifdef SUPPORT_MAILDIR
if (ob->maildir_use_size_file)
{
- const pcre *dir_regex = NULL;
- const uschar *error;
- int offset;
+ const pcre2_code * dir_regex = NULL;
if (ob->maildir_dir_regex)
{
int check_path_len = Ustrlen(check_path);
- 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,
- ob->maildir_dir_regex);
+ if (!(dir_regex = regex_compile(ob->maildir_dir_regex,
+ MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx)))
return FALSE;
- }
DEBUG(D_transport)
debug_printf("using regex for maildir directory selection: %s\n",
uschar *s = path + check_path_len;
while (*s == '/') 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)
+ if (!regex_match(dir_regex, s, -1, NULL))
{
disable_quota = TRUE;
DEBUG(D_transport) debug_printf("delivery directory does not match "
off_t size;
int filecount;
- if ((maildirsize_fd = maildir_ensure_sizefile(check_path, ob, regex, dir_regex,
+ if ((maildirsize_fd = maildir_ensure_sizefile(check_path, ob, re, dir_regex,
&size, &filecount)) == -1)
{
addr->basic_errno = errno;
* (void)unlink(CS string_sprintf("%s/maildirsize", check_path));
* if (THRESHOLD_CHECK)
* mailbox_size = maildir_compute_size(check_path, &mailbox_filecount, &old_latest,
- * regex, dir_regex, FALSE);
+ * re, dir_regex, FALSE);
* }
*/
int filecount = 0;
DEBUG(D_transport)
debug_printf("quota checks on directory %s\n", check_path);
- size = check_dir_size(check_path, &filecount, regex);
+ size = check_dir_size(check_path, &filecount, re);
if (mailbox_size < 0) mailbox_size = size;
if (mailbox_filecount < 0) mailbox_filecount = filecount;
}
DEBUG(D_transport)
debug_printf("delivering in maildir format in %s\n", path);
+ GET_OPTION("maildir_tag");
nametag = ob->maildir_tag;
/* Check that nametag expands successfully; a hard failure causes a panic
else
{
- FILE *env_file;
+ FILE * env_file;
mailstore_basename = string_sprintf("%s/%s-%s", path, message_id,
- string_base62((long int)getpid()));
+ string_base62_64((long int)getpid()));
DEBUG(D_transport)
debug_printf("delivering in mailstore format in %s\n", path);
/* Write the envelope file, then close it. */
+ GET_OPTION("mailstore_prefix");
if (ob->mailstore_prefix)
{
- uschar *s = expand_string(ob->mailstore_prefix);
+ uschar * s = expand_string(ob->mailstore_prefix);
if (!s)
{
if (!f.expand_string_forcedfail)
for (address_item * taddr = addr; taddr; taddr = taddr->next)
fprintf(env_file, "%s@%s\n", taddr->local_part, taddr->domain);
+ GET_OPTION("mailstore_suffix");
if (ob->mailstore_suffix)
{
- uschar *s = expand_string(ob->mailstore_suffix);
+ uschar * s = expand_string(ob->mailstore_suffix);
if (!s)
{
if (!f.expand_string_forcedfail)
/* Write any configured prefix text first */
-if (yield == OK && ob->message_prefix && *ob->message_prefix)
+if (yield == OK)
{
- uschar *prefix = expand_string(ob->message_prefix);
- if (!prefix)
- {
- errno = ERRNO_EXPANDFAIL;
- addr->transport_return = PANIC;
- addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s "
- "transport) failed", ob->message_prefix, tblock->name);
- yield = DEFER;
- }
- else if (!transport_write_string(fd, "%s", prefix)) yield = DEFER;
+ uschar * prefix = ob->message_prefix;
+ GET_OPTION("message_prefix");
+ if (prefix && *prefix)
+ if (!(prefix = expand_string(prefix)))
+ {
+ errno = ERRNO_EXPANDFAIL;
+ addr->transport_return = PANIC;
+ addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s "
+ "transport) failed", ob->message_prefix, tblock->name);
+ yield = DEFER;
+ }
+ else if (!transport_write_string(fd, "%s", prefix))
+ yield = DEFER;
}
/* If the use_bsmtp option is on, we need to write SMTP prefix information. The
/* Now a configured suffix. */
-if (yield == OK && ob->message_suffix && *ob->message_suffix)
+if (yield == OK)
{
- uschar *suffix = expand_string(ob->message_suffix);
- if (!suffix)
- {
- errno = ERRNO_EXPANDFAIL;
- addr->transport_return = PANIC;
- addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s "
- "transport) failed", ob->message_suffix, tblock->name);
- yield = DEFER;
- }
- else if (!transport_write_string(fd, "%s", suffix)) yield = DEFER;
+ uschar * suffix = ob->message_suffix;
+ GET_OPTION("message_suffix");
+ if (suffix && *suffix)
+ if (!(suffix = expand_string(suffix)))
+ {
+ errno = ERRNO_EXPANDFAIL;
+ addr->transport_return = PANIC;
+ addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s "
+ "transport) failed", ob->message_suffix, tblock->name);
+ yield = DEFER;
+ }
+ else if (!transport_write_string(fd, "%s", suffix))
+ yield = DEFER;
}
/* If batch smtp, write the terminating dot. */
uschar *iptr = expand_string(nametag);
if (iptr)
{
- uschar *etag = store_get(Ustrlen(iptr) + 2, is_tainted(iptr));
+ uschar *etag = store_get(Ustrlen(iptr) + 2, iptr);
uschar *optr = etag;
for ( ; *iptr; iptr++)
if (mac_isgraph(*iptr) && *iptr != '/')
}
#endif /*!MACRO_PREDEF*/
+#endif /*TRANSPORT_APPENDFILE*/
/* End of transport/appendfile.c */