build: use pkg-config for i18n
[exim.git] / src / src / rda.c
index 35794c2ffdd613a77a7ef39d3d0f224a7b7bff49..405e4646ae913557c9821fb3ab2d0ee25cd2e0b3 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim maintainers 2020 - 2024 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 /* This module contains code for extracting addresses from a forwarding list
 (from an alias or forward file) or by running the filter interpreter. It may do
 
 /* This module contains code for extracting addresses from a forwarding list
 (from an alias or forward file) or by running the filter interpreter. It may do
@@ -179,8 +180,10 @@ struct stat statbuf;
 /* Reading a file is a form of expansion; we wish to deny attackers the
 capability to specify the file name. */
 
 /* Reading a file is a form of expansion; we wish to deny attackers the
 capability to specify the file name. */
 
-if ((*error = is_tainted2(filename, 0, "Tainted name '%s' for file read not permitted\n", filename)))
+if (is_tainted(filename))
   {
   {
+  *error = string_sprintf("Tainted name '%s' for file read not permitted\n",
+                       filename);
   *yield = FF_ERROR;
   return NULL;
   }
   *yield = FF_ERROR;
   return NULL;
   }
@@ -282,7 +285,7 @@ if (statbuf.st_size > MAX_FILTER_SIZE)
 
 /* Read the file in one go in order to minimize the time we have it open. */
 
 
 /* Read the file in one go in order to minimize the time we have it open. */
 
-filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
+filebuf = store_get(statbuf.st_size + 1, filename);
 
 if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size)
   {
 
 if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size)
   {
@@ -319,10 +322,7 @@ Arguments:
   rdata                     the redirection block
   options                   the options bits
   include_directory         restrain to this directory
   rdata                     the redirection block
   options                   the options bits
   include_directory         restrain to this directory
-  sieve_vacation_directory  passed to sieve_interpret
-  sieve_enotify_mailto_owner passed to sieve_interpret
-  sieve_useraddress         passed to sieve_interpret
-  sieve_subaddress          passed to sieve_interpret
+  sieve                            passed to sieve_interpret
   generated                 where to hang generated addresses
   error                     for error messages
   eblockp                   for details of skipped syntax errors
   generated                 where to hang generated addresses
   error                     for error messages
   eblockp                   for details of skipped syntax errors
@@ -337,11 +337,10 @@ Returns:                    a suitable return for rda_interpret()
 */
 
 static int
 */
 
 static int
-rda_extract(const redirect_block *rdata, int options, uschar *include_directory,
-  uschar *sieve_vacation_directory, uschar *sieve_enotify_mailto_owner,
-  uschar *sieve_useraddress, uschar *sieve_subaddress,
-  address_item **generated, uschar **error, error_block **eblockp,
-  int *filtertype)
+rda_extract(const redirect_block * rdata, int options,
+  const uschar * include_directory, const sieve_block * sieve,
+  address_item ** generated, uschar ** error,
+  error_block ** eblockp, int * filtertype)
 {
 const uschar * data;
 
 {
 const uschar * data;
 
@@ -384,23 +383,40 @@ if (*filtertype != FILTER_FORWARD)
 
   if (*filtertype == FILTER_EXIM)
     {
 
   if (*filtertype == FILTER_EXIM)
     {
-    if ((options & RDO_EXIM_FILTER) != 0)
+    const misc_module_info * mi;
+    typedef int (*fn_t)(const uschar *, int, address_item **, uschar **);
+
+    if (options & RDO_EXIM_FILTER)
       {
       *error = US"Exim filtering not enabled";
       return FF_ERROR;
       }
       {
       *error = US"Exim filtering not enabled";
       return FF_ERROR;
       }
-    frc = filter_interpret(data, options, generated, error);
+    if (!(mi = misc_mod_find(US"exim_filter", NULL)))
+      {
+      *error = US"Exim-filtering not available";
+      return FF_ERROR;
+      }
+    frc = (((fn_t *) mi->functions)[EXIM_INTERPRET])
+                                     (data, options, generated, error);
     }
   else
     {
     }
   else
     {
+    const misc_module_info * mi;
+    typedef int (*fn_t)(const uschar *, int, const sieve_block *,
+                      address_item **, uschar **);
+
     if (options & RDO_SIEVE_FILTER)
       {
       *error = US"Sieve filtering not enabled";
       return FF_ERROR;
       }
     if (options & RDO_SIEVE_FILTER)
       {
       *error = US"Sieve filtering not enabled";
       return FF_ERROR;
       }
-    frc = sieve_interpret(data, options, sieve_vacation_directory,
-      sieve_enotify_mailto_owner, sieve_useraddress, sieve_subaddress,
-      generated, error);
+    if (!(mi = misc_mod_find(US"sieve_filter", NULL)))
+      {
+      *error = US"Sieve filtering not available";
+      return FF_ERROR;
+      }
+    frc = (((fn_t *) mi->functions)[SIEVE_INTERPRET])
+                                     (data, options, sieve, generated, error);
     }
 
   expand_forbid = old_expand_forbid;
     }
 
   expand_forbid = old_expand_forbid;
@@ -440,9 +456,9 @@ Returns:     -1 on error, else 0
 static int
 rda_write_string(int fd, const uschar *s)
 {
 static int
 rda_write_string(int fd, const uschar *s)
 {
-int len = (s == NULL)? 0 : Ustrlen(s) + 1;
+int len = s ? Ustrlen(s) + 1 : 0;
 return (  write(fd, &len, sizeof(int)) != sizeof(int)
 return (  write(fd, &len, sizeof(int)) != sizeof(int)
-       || (s != NULL  &&  write(fd, s, len) != len)
+       || (s   &&  write(fd, s, len) != len)
        )
        ? -1 : 0;
 }
        )
        ? -1 : 0;
 }
@@ -463,7 +479,7 @@ Returns:     FALSE if data missing
 */
 
 static BOOL
 */
 
 static BOOL
-rda_read_string(int fd, uschar **sp)
+rda_read_string(int fd, uschar ** sp)
 {
 int len;
 
 {
 int len;
 
@@ -474,7 +490,7 @@ else
   /* We know we have enough memory so disable the error on "len" */
   /* coverity[tainted_data] */
   /* We trust the data source, so untainted */
   /* We know we have enough memory so disable the error on "len" */
   /* coverity[tainted_data] */
   /* We trust the data source, so untainted */
-  if (read(fd, *sp = store_get(len, FALSE), len) != len) return FALSE;
+  if (read(fd, *sp = store_get(len, GET_UNTAINTED), len) != len) return FALSE;
 return TRUE;
 }
 
 return TRUE;
 }
 
@@ -510,10 +526,7 @@ Arguments:
   options                   options to pass to the extraction functions,
                               plus ENOTDIR and EACCES handling bits
   include_directory         restrain :include: to this directory
   options                   options to pass to the extraction functions,
                               plus ENOTDIR and EACCES handling bits
   include_directory         restrain :include: to this directory
-  sieve_vacation_directory  directory passed to sieve_interpret
-  sieve_enotify_mailto_owner passed to sieve_interpret
-  sieve_useraddress         passed to sieve_interpret
-  sieve_subaddress          passed to sieve_interpret
+  sieve                            passed to sieve_interpret
   ugid                      uid/gid to run under - if NULL, no change
   generated                 where to hang generated addresses, initially NULL
   error                     pointer for error message
   ugid                      uid/gid to run under - if NULL, no change
   generated                 where to hang generated addresses, initially NULL
   error                     pointer for error message
@@ -539,11 +552,10 @@ Returns:        values from extraction function, or FF_NONEXIST:
 */
 
 int
 */
 
 int
-rda_interpret(redirect_block *rdata, int options, uschar *include_directory,
-  uschar *sieve_vacation_directory, uschar *sieve_enotify_mailto_owner,
-  uschar *sieve_useraddress, uschar *sieve_subaddress, ugid_block *ugid,
-  address_item **generated, uschar **error, error_block **eblockp,
-  int *filtertype, uschar *rname)
+rda_interpret(redirect_block * rdata, int options,
+  const uschar * include_directory, const sieve_block * sieve,
+  const ugid_block * ugid, address_item ** generated,
+  uschar ** error, error_block ** eblockp, int * filtertype, const uschar * rname)
 {
 int fd, rc, pfd[2];
 int yield, status;
 {
 int fd, rc, pfd[2];
 int yield, status;
@@ -581,13 +593,13 @@ with #Exim filter or #Sieve filter, and does not contain :include:, do all the
 work in this process. Note that for a system filter, we always have a file, so
 the work is done in this process only if no user is supplied. */
 
 work in this process. Note that for a system filter, we always have a file, so
 the work is done in this process only if no user is supplied. */
 
-if (!ugid->uid_set ||                         /* Either there's no uid, or */
-    (!rdata->isfile &&                        /* We've got the data, and */
-     rda_is_filter(data) == FILTER_FORWARD && /* It's not a filter script, */
-     Ustrstr(data, ":include:") == NULL))     /* and there's no :include: */
-  return rda_extract(rdata, options, include_directory,
-    sieve_vacation_directory, sieve_enotify_mailto_owner, sieve_useraddress,
-    sieve_subaddress, generated, error, eblockp, filtertype);
+if (  !ugid->uid_set                           /* Either there's no uid, or */
+   || (  !rdata->isfile                                /* We've got the data, and */
+      && rda_is_filter(data) == FILTER_FORWARD /* It's not a filter script, */
+      && Ustrstr(data, ":include:") == NULL    /* and there's no :include: */
+   )  )
+  return rda_extract(rdata, options, include_directory, sieve,
+                   generated, error, eblockp, filtertype);
 
 /* We need to run the processing code in a sub-process. However, if we can
 determine the non-existence of a file first, we can decline without having to
 
 /* We need to run the processing code in a sub-process. However, if we can
 determine the non-existence of a file first, we can decline without having to
@@ -639,9 +651,8 @@ if ((pid = exim_fork(US"router-interpret")) == 0)
 
   /* Now do the business */
 
 
   /* Now do the business */
 
-  yield = rda_extract(rdata, options, include_directory,
-    sieve_vacation_directory, sieve_enotify_mailto_owner, sieve_useraddress,
-    sieve_subaddress, generated, error, eblockp, filtertype);
+  yield = rda_extract(rdata, options, include_directory, sieve,
+                     generated, error, eblockp, filtertype);
 
   /* Pass back whether it was a filter, and the return code and any overall
   error text via the pipe. */
 
   /* Pass back whether it was a filter, and the return code and any overall
   error text via the pipe. */
@@ -806,7 +817,7 @@ if (eblockp)
     uschar *s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
     if (!s) break;
     uschar *s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
     if (!s) break;
-    e = store_get(sizeof(error_block), FALSE);
+    e = store_get(sizeof(error_block), GET_UNTAINTED);
     e->next = NULL;
     e->text1 = s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
     e->next = NULL;
     e->text1 = s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
@@ -863,9 +874,9 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
   for (;;)
     {
     int i, reply_options;
   for (;;)
     {
     int i, reply_options;
-    address_item *addr;
-    uschar *recipient;
-    uschar *expandn[EXPAND_MAXN + 2];
+    address_item * addr;
+    uschar * recipient, * s;
+    uschar * expandn[EXPAND_MAXN + 2];
 
     /* First string is the address; NULL => end of addresses */
 
 
     /* First string is the address; NULL => end of addresses */
 
@@ -882,10 +893,11 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
 
     if (  read(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode)
        || read(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags)
 
     if (  read(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode)
        || read(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags)
-       || !rda_read_string(fd, &addr->prop.errors_address)
+       || !rda_read_string(fd, &s)
        || read(fd, &i, sizeof(i)) != sizeof(i)
        )
       goto DISASTER;
        || read(fd, &i, sizeof(i)) != sizeof(i)
        )
       goto DISASTER;
+    addr->prop.errors_address = s;
     addr->prop.ignore_error = (i != 0);
 
     /* Next comes a possible setting for $thisaddress and any numerical
     addr->prop.ignore_error = (i != 0);
 
     /* Next comes a possible setting for $thisaddress and any numerical
@@ -905,7 +917,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
 
     if (i > 0)
       {
 
     if (i > 0)
       {
-      addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), FALSE);
+      addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), GET_UNTAINTED);
       addr->pipe_expandn[i] = NULL;
       while (--i >= 0) addr->pipe_expandn[i] = expandn[i];
       }
       addr->pipe_expandn[i] = NULL;
       while (--i >= 0) addr->pipe_expandn[i] = expandn[i];
       }
@@ -915,7 +927,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
     if (read(fd, &reply_options, sizeof(int)) != sizeof(int)) goto DISASTER;
     if ((reply_options & REPLY_EXISTS) != 0)
       {
     if (read(fd, &reply_options, sizeof(int)) != sizeof(int)) goto DISASTER;
     if ((reply_options & REPLY_EXISTS) != 0)
       {
-      addr->reply = store_get(sizeof(reply_item), FALSE);
+      addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
 
       addr->reply->file_expand = (reply_options & REPLY_EXPAND) != 0;
       addr->reply->return_message = (reply_options & REPLY_RETURN) != 0;
 
       addr->reply->file_expand = (reply_options & REPLY_EXPAND) != 0;
       addr->reply->return_message = (reply_options & REPLY_RETURN) != 0;
@@ -964,11 +976,9 @@ if (had_disaster)
   log_write(0, LOG_MAIN|LOG_PANIC, "%s", *error);
   }
 else if (status != 0)
   log_write(0, LOG_MAIN|LOG_PANIC, "%s", *error);
   }
 else if (status != 0)
-  {
   log_write(0, LOG_MAIN|LOG_PANIC, "internal problem in %s: unexpected status "
     "%04x from redirect subprocess (but data correctly received)", rname,
     status);
   log_write(0, LOG_MAIN|LOG_PANIC, "internal problem in %s: unexpected status "
     "%04x from redirect subprocess (but data correctly received)", rname,
     status);
-  }
 
 FINAL_EXIT:
 (void)close(fd);
 
 FINAL_EXIT:
 (void)close(fd);