X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/fa1c8faf169384bebaa8d172f491574c45ae2aa4..HEAD:/src/src/transports/appendfile.c diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index ec41ca035..08a59543c 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -2,13 +2,15 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim maintainers 2020 - 2023 */ +/* Copyright (c) The Exim maintainers 2020 - 2024 */ /* Copyright (c) University of Cambridge 1995 - 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 @@ -105,7 +107,7 @@ int appendfile_transport_options_count = /* Dummy values */ appendfile_transport_options_block appendfile_transport_option_defaults = {0}; -void appendfile_transport_init(transport_instance *tblock) {} +void appendfile_transport_init(driver_instance *tblock) {} BOOL appendfile_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;} #else /*!MACRO_PREDEF*/ @@ -153,7 +155,6 @@ static const char *mailbox_formats[] = { (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0)) - /************************************************* * Setup entry point * *************************************************/ @@ -179,18 +180,24 @@ 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 *)(tblock->options_block); -uschar *q = ob->quota; +appendfile_transport_options_block * ob = tblock->drinst.options_block; +const uschar * trname = tblock->drinst.name; +uschar * q; double default_value = 0.0; 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); + { + 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", trname); + } /* 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; @@ -204,7 +211,7 @@ for (int i = 0; i < 5; i++) if (!(s = expand_string(q))) { *errmsg = string_sprintf("Expansion of \"%s\" in %s transport failed: " - "%s", q, tblock->name, expand_string_message); + "%s", q, trname, expand_string_message); return f.search_find_defer ? DEFER : FAIL; } @@ -224,7 +231,7 @@ for (int i = 0; i < 5; i++) else if ((int)d < 0 || (int)d > 100) { *errmsg = string_sprintf("Invalid quota_warn_threshold percentage (%d)" - " for %s transport", (int)d, tblock->name); + " for %s transport", (int)d, trname); return FAIL; } ob->quota_warn_threshold_is_percent = TRUE; @@ -245,7 +252,7 @@ for (int i = 0; i < 5; i++) if (*rest) { *errmsg = string_sprintf("Malformed value \"%s\" (expansion of \"%s\") " - "in %s transport", s, q, tblock->name); + "in %s transport", s, q, trname); return FAIL; } } @@ -259,6 +266,7 @@ for (int i = 0; i < 5; i++) which = US"quota"; ob->quota_value = (off_t)d; ob->quota_no_check = no_check; + GET_OPTION("quota_filecount"); q = ob->quota_filecount; break; @@ -267,6 +275,7 @@ for (int i = 0; i < 5; i++) 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; @@ -274,6 +283,7 @@ for (int i = 0; i < 5; i++) 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; @@ -282,6 +292,7 @@ for (int i = 0; i < 5; i++) 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; @@ -295,7 +306,7 @@ for (int i = 0; i < 5; i++) if (which) { *errmsg = string_sprintf("%s value %.10g is too large (overflow) in " - "%s transport", which, d, tblock->name); + "%s transport", which, d, trname); return FAIL; } } @@ -314,10 +325,11 @@ enable consistency checks to be done, or anything else that needs to be set up. */ void -appendfile_transport_init(transport_instance *tblock) +appendfile_transport_init(driver_instance * t) { -appendfile_transport_options_block *ob = - (appendfile_transport_options_block *)(tblock->options_block); +transport_instance * tblock = (transport_instance *)t; +appendfile_transport_options_block * ob = tblock->drinst.options_block; +const uschar * trname = tblock->drinst.name; uschar * s; /* Set up the setup entry point, to be called in the privileged state */ @@ -332,7 +344,7 @@ if (ob->lock_retries == 0) ob->lock_retries = 1; 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); + "only one of \"file\" or \"directory\" can be specified", trname); /* If a file name was specified, neither quota_filecount nor quota_directory must be given. */ @@ -341,10 +353,10 @@ if (ob->filename) { 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); + "quota_filecount must not be set without \"directory\"", trname); 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); + "quota_directory must not be set without \"directory\"", trname); } /* The default locking depends on whether MBX is set or not. Change the @@ -360,7 +372,7 @@ if (ob->use_flock) #ifdef NO_FLOCK log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " "flock() support was not available in the operating system when this " - "binary was built", tblock->name); + "binary was built", trname); #endif /* NO_FLOCK */ if (!ob->set_use_fcntl) ob->use_fcntl = FALSE; } @@ -384,7 +396,7 @@ if (ob->mbx_format) if (!ob->use_fcntl && !ob->use_flock && !ob->use_lockfile && !ob->use_mbx_lock) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " - "no locking configured", tblock->name); + "no locking configured", trname); /* Unset timeouts for non-used locking types */ @@ -399,20 +411,20 @@ if (ob->dirname) { 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) + "only one of maildir and mailstore may be specified", trname); + 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) + "quota must be set if quota_filecount is set", trname); + 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); + "quota must be set if quota_directory is set", trname); } /* 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) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, - "user set without group for the %s transport", tblock->name); + "user set without group for the %s transport", trname); /* If "create_file" is set, check that a valid option is given, and set the integer variable. */ @@ -426,7 +438,7 @@ if ((s = ob->create_file_string ) && *s) else log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "invalid value given for \"create_file\" for the %s transport: '%s'", - tblock->name, s); + trname, s); ob->create_file = val; } @@ -583,8 +595,8 @@ Returns: pointer to the required transport, or NULL transport_instance * check_file_format(int cfd, transport_instance *tblock, address_item *addr) { -const uschar *format = - ((appendfile_transport_options_block *)(tblock->options_block))->file_format; +appendfile_transport_options_block * ob = tblock->drinst.options_block; +const uschar * format = ob->file_format; uschar data[256]; int len = read(cfd, data, sizeof(data)); int sep = 0; @@ -607,11 +619,11 @@ while ((s = string_nextinlist(&format, &sep, big_buffer, big_buffer_size))) if (match && tp) { - for (transport_instance * tt = transports; tt; tt = tt->next) - if (Ustrcmp(tp, tt->name) == 0) + for (transport_instance * tt = transports; tt; tt = tt->drinst.next) + if (Ustrcmp(tp, tt->drinst.name) == 0) { DEBUG(D_transport) - debug_printf("file format -> %s transport\n", tt->name); + debug_printf("file format -> %s transport\n", tt->drinst.name); return tt; } addr->basic_errno = ERRNO_BADTRANSPORT; @@ -661,13 +673,14 @@ Returns: the sum of the sizes of the stattable files off_t 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; @@ -675,6 +688,11 @@ for (struct dirent *ent; ent = readdir(dir); ) 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 */ @@ -726,6 +744,7 @@ DEBUG(D_transport) 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; } @@ -1136,37 +1155,27 @@ appendfile_transport_entry( transport_instance *tblock, /* data for this instantiation */ address_item *addr) /* address we are working on */ { -appendfile_transport_options_block *ob = - (appendfile_transport_options_block *)(tblock->options_block); +appendfile_transport_options_block * ob = tblock->drinst.options_block; +const uschar * trname = tblock->drinst.name; struct stat statbuf; const uschar * deliver_dir; -uschar *fdname = NULL; -uschar *filename = NULL; -uschar *hitchname = NULL; -uschar *dataname = NULL; -uschar *lockname = NULL; -uschar *newname = NULL; -uschar *nametag = NULL; -uschar *cr = US""; -uschar *filecount_msg = US""; -uschar *path; +uschar * fdname = NULL, * filename = NULL; +uschar * hitchname = NULL, * dataname = NULL; +uschar * lockname = NULL, * newname = NULL; +uschar * nametag = NULL, * cr = US""; +uschar * filecount_msg = US""; +uschar * path; struct utimbuf times; struct timeval msg_tv; -BOOL disable_quota = FALSE; -BOOL isdirectory = FALSE; -BOOL isfifo = FALSE; +BOOL disable_quota = FALSE, isdirectory = FALSE, isfifo = FALSE; BOOL wait_for_tick = FALSE; uid_t uid = geteuid(); /* See note above */ gid_t gid = getegid(); int mbformat; -int mode = (addr->mode > 0) ? addr->mode : ob->mode; -off_t saved_size = -1; -off_t mailbox_size = ob->mailbox_size_value; +int mode = addr->mode > 0 ? addr->mode : ob->mode; +off_t saved_size = -1, mailbox_size = ob->mailbox_size_value; int mailbox_filecount = ob->mailbox_filecount_value; -int hd = -1; -int fd = -1; -int yield = FAIL; -int i; +int hd = -1, fd = -1, yield = FAIL, i; #ifdef SUPPORT_MBX int save_fd = 0; @@ -1215,13 +1224,14 @@ if (!fdname) { if (!(fdname = ob->filename)) { + GET_OPTION("directory"); fdname = ob->dirname; isdirectory = TRUE; } if (!fdname) { addr->message = string_sprintf("Mandatory file or directory option " - "missing from %s transport", tblock->name); + "missing from %s transport", trname); goto ret_panic; } } @@ -1232,14 +1242,14 @@ if ((ob->maildir_format || ob->mailstore_format) && !isdirectory) { addr->message = string_sprintf("mail%s_format requires \"directory\" " "to be specified for the %s transport", - ob->maildir_format ? "dir" : "store", tblock->name); + ob->maildir_format ? "dir" : "store", trname); goto ret_panic; } if (!(path = expand_string(fdname))) { addr->message = string_sprintf("Expansion of \"%s\" (file or directory " - "name for %s transport) failed: %s", fdname, tblock->name, + "name for %s transport) failed: %s", fdname, trname, expand_string_message); goto ret_panic; } @@ -1314,7 +1324,7 @@ if (f.dont_deliver) { DEBUG(D_transport) debug_printf("*** delivery by %s transport bypassed by -N option\n", - tblock->name); + trname); addr->transport_return = OK; return FALSE; } @@ -1349,7 +1359,7 @@ if (!isdirectory) && ob->create_file == create_belowhome) if (is_tainted(path)) { - DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path); + DEBUG(D_transport) debug_printf("below-home: de-tainting path '%s'\n", path); path = string_copy_taint(path, GET_UNTAINTED); } @@ -1371,7 +1381,7 @@ if (!isdirectory) addr->message = string_sprintf("failed to create directories for %s: %s", path, exim_errstr(errno)); - DEBUG(D_transport) debug_printf("%s transport: %s\n", tblock->name, path); + DEBUG(D_transport) debug_printf("%s transport: %s\n", trname, path); return FALSE; } } @@ -1399,11 +1409,12 @@ if (!isdirectory) { if (tt) { + transport_info * ti = tt->drinst.info; set_process_info("delivering %s to %s using %s", message_id, - addr->local_part, tt->name); + addr->local_part, tt->drinst.name); debug_print_string(tt->debug_string); addr->transport = tt; - (tt->info->code)(tt, addr); + (ti->code)(tt, addr); } return FALSE; } @@ -2188,7 +2199,7 @@ else if (is_tainted(path)) if (ob->create_file == create_belowhome) { - DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path); + DEBUG(D_transport) debug_printf("below-home: de-tainting path '%s'\n", path); path = string_copy_taint(path, GET_UNTAINTED); } else @@ -2228,13 +2239,14 @@ else /* Use an explicitly configured directory if set */ + GET_OPTION("quota_directory"); if (ob->quota_directory) { if (!(check_path = expand_string(ob->quota_directory))) { addr->message = string_sprintf("Expansion of \"%s\" (quota_directory " "name for %s transport) failed: %s", ob->quota_directory, - tblock->name, expand_string_message); + trname, expand_string_message); goto ret_panic; } @@ -2425,6 +2437,7 @@ else 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 @@ -2434,7 +2447,7 @@ else if (nametag && !expand_string(nametag) && !f.expand_string_forcedfail) { addr->message = string_sprintf("Expansion of \"%s\" (maildir_tag " - "for %s transport) failed: %s", nametag, tblock->name, + "for %s transport) failed: %s", nametag, trname, expand_string_message); goto ret_panic; } @@ -2553,7 +2566,7 @@ else { addr->basic_errno = errno; addr->message = string_sprintf("fdopen of %s (" - "for %s transport) failed", filename, tblock->name); + "for %s transport) failed", filename, trname); (void)close(fd); Uunlink(filename); goto ret_panic; @@ -2561,16 +2574,17 @@ else /* 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) { addr->message = string_sprintf("Expansion of \"%s\" (mailstore " "prefix for %s transport) failed: %s", ob->mailstore_prefix, - tblock->name, expand_string_message); + trname, expand_string_message); (void)fclose(env_file); Uunlink(filename); goto ret_panic; @@ -2589,16 +2603,17 @@ else 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) { addr->message = string_sprintf("Expansion of \"%s\" (mailstore " "suffix for %s transport) failed: %s", ob->mailstore_suffix, - tblock->name, expand_string_message); + trname, expand_string_message); (void)fclose(env_file); Uunlink(filename); goto ret_panic; @@ -2751,18 +2766,21 @@ transport_newlines = 0; /* 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, trname); + 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 @@ -2814,18 +2832,21 @@ if (yield == OK) /* 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, trname); + yield = DEFER; + } + else if (!transport_write_string(fd, "%s", suffix)) + yield = DEFER; } /* If batch smtp, write the terminating dot. */ @@ -3129,7 +3150,7 @@ else addr->transport_return = PANIC; addr->message = string_sprintf("Expansion of \"%s\" " "(directory_file for %s transport) failed: %s", - ob->dirfilename, tblock->name, expand_string_message); + ob->dirfilename, trname, expand_string_message); goto RETURN; } @@ -3292,11 +3313,37 @@ return FALSE; tainted_ret_panic: addr->message = string_sprintf("Tainted '%s' (file or directory " - "name for %s transport) not permitted", path, tblock->name); + "name for %s transport) not permitted", path, trname); ret_panic: addr->transport_return = PANIC; return FALSE; } + + + +# ifdef DYNLOOKUP +# define appendfile_transport_info _transport_info +# endif + +transport_info appendfile_transport_info = { +.drinfo = { + .driver_name = US"appendfile", + .options = appendfile_transport_options, + .options_count = &appendfile_transport_options_count, + .options_block = &appendfile_transport_option_defaults, /* private options defaults */ + .options_len = sizeof(appendfile_transport_options_block), + .init = appendfile_transport_init, +# ifdef DYNLOOKUP + .dyn_magic = TRANSPORT_MAGIC, +# endif + }, +.code = appendfile_transport_entry, +.tidyup = NULL, +.closedown = NULL, +.local = TRUE +}; + #endif /*!MACRO_PREDEF*/ +#endif /*TRANSPORT_APPENDFILE*/ /* End of transport/appendfile.c */