$local_part_verified
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 11 Jan 2020 18:07:10 +0000 (18:07 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 11 Jan 2020 20:45:29 +0000 (20:45 +0000)
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/acl.c
src/src/configure.default
src/src/expand.c
src/src/globals.c
src/src/globals.h
src/src/route.c
src/src/routers/rf_get_errors_address.c
test/confs/0005

index 241540cfd69246e66e10e269ff9753de6fb787f1..254ed69cc468f5b9f479dc3342741fa835108f98 100644 (file)
@@ -6362,7 +6362,7 @@ All other options are defaulted.
 .code
 local_delivery:
   driver = appendfile
 .code
 local_delivery:
   driver = appendfile
-  file = /var/mail/$home
+  file = /var/mail/$local_part_verified
   delivery_date_add
   envelope_to_add
   return_path_add
   delivery_date_add
   envelope_to_add
   return_path_add
@@ -6370,7 +6370,17 @@ local_delivery:
 # mode = 0660
 .endd
 This &(appendfile)& transport is used for local delivery to user mailboxes in
 # mode = 0660
 .endd
 This &(appendfile)& transport is used for local delivery to user mailboxes in
-traditional BSD mailbox format. By default it runs under the uid and gid of the
+traditional BSD mailbox format.
+
+.new
+We prefer to avoid using &$local_part$& directly to define the mailbox filename,
+as it is provided by a potential bad actor.
+Instead we use &$local_part_verified$&,
+the result of looking up &$local_part$& in the user database
+(done by using &%check_local_user%& in the the router).
+.wen
+
+By default &(appendfile)& runs under the uid and gid of the
 local user, which requires the sticky bit to be set on the &_/var/mail_&
 directory. Some systems use the alternative approach of running mail deliveries
 under a particular group instead of using the sticky bit. The commented options
 local user, which requires the sticky bit to be set on the &_/var/mail_&
 directory. Some systems use the alternative approach of running mail deliveries
 under a particular group instead of using the sticky bit. The commented options
@@ -12202,6 +12212,7 @@ the complete argument of the ETRN command (see section &<<SECTETRN>>&).
 .cindex "tainted data"
 If the origin of the data is an incoming message,
 the result of expanding this variable is tainted.
 .cindex "tainted data"
 If the origin of the data is an incoming message,
 the result of expanding this variable is tainted.
+See also &$domain_verified$&.
 .wen
 
 
 .wen
 
 
@@ -12402,15 +12413,18 @@ once.
 If the origin of the data is an incoming message,
 the result of expanding this variable is tainted.
 
 If the origin of the data is an incoming message,
 the result of expanding this variable is tainted.
 
-&*Warning*&: the content of this variable is usually provided by a potential attacker.
+&*Warning*&: the content of this variable is usually provided by a potential
+attacker.
 Consider carefully the implications of using it unvalidated as a name
 for file access.
 This presents issues for users' &_.forward_& and filter files.
 Consider carefully the implications of using it unvalidated as a name
 for file access.
 This presents issues for users' &_.forward_& and filter files.
-For traditional full user accounts, use &%check_local_users%& and the &$home$&
-variable rather than this one.
+For traditional full user accounts, use &%check_local_users%& and the
+&$local_part_verified$& variable rather than this one.
 For virtual users, store a suitable pathname component in the database
 which is used for account name validation, and use that retrieved value
 rather than this variable.
 For virtual users, store a suitable pathname component in the database
 which is used for account name validation, and use that retrieved value
 rather than this variable.
+If needed, use a router &%address_data%& or &%set%& option for
+the retrieved data.
 .wen
 
 .vindex "&$local_part_prefix$&"
 .wen
 
 .vindex "&$local_part_prefix$&"
@@ -12479,6 +12493,14 @@ When an address is being routed or delivered, and a
 specific suffix for the local part was recognized, it is available in this
 variable, having been removed from &$local_part$&.
 
 specific suffix for the local part was recognized, it is available in this
 variable, having been removed from &$local_part$&.
 
+.new
+.vitem &$local_part_verified$&
+.vindex "&$local_part_verified$&"
+If the router generic option &%check_local_part%& has run successfully,
+this variable has the user database version of &$local_part$&.
+Such values are not tainted and hence usable for building file names.
+.wen
+
 .vitem &$local_scan_data$&
 .vindex "&$local_scan_data$&"
 This variable contains the text returned by the &[local_scan()]& function when
 .vitem &$local_scan_data$&
 .vindex "&$local_scan_data$&"
 This variable contains the text returned by the &[local_scan()]& function when
index 6b163b8b2034d20f403996d83bf00086503bf967..8a00bfc671a63841bbbae316a749ae334f3742e7 100644 (file)
@@ -21,6 +21,9 @@ Version 4.94
     driver for PLAIN; only against itself for SCRAM-SHA-1 and SCRAM-SHA-1-PLUS
     methods.
 
     driver for PLAIN; only against itself for SCRAM-SHA-1 and SCRAM-SHA-1-PLUS
     methods.
 
+ 5. Variable $local_part_verified, set by the router check_local_part condition
+    with untainted data.
+
 
 Version 4.93
 ------------
 
 Version 4.93
 ------------
index 799af39c3e72fefa9570cfda5bd6282d186c3cda..7284831a6ef881952d4a1c184329b7d83d6157a7 100644 (file)
@@ -866,11 +866,10 @@ while ((s = (*func)()) != NULL)
     {
     uschar *endptr;
 
     {
     uschar *endptr;
 
-    if (Ustrncmp(s, "acl_c", 5) != 0 &&
-        Ustrncmp(s, "acl_m", 5) != 0)
+    if (Ustrncmp(s, "acl_c", 5) != 0 && Ustrncmp(s, "acl_m", 5) != 0)
       {
       *error = string_sprintf("invalid variable name after \"set\" in ACL "
       {
       *error = string_sprintf("invalid variable name after \"set\" in ACL "
-        "modifier \"set %s\" (must start \"acl_c\" or \"acl_m\")", s);
+       "modifier \"set %s\" (must start \"acl_c\" or \"acl_m\")", s);
       return NULL;
       }
 
       return NULL;
       }
 
@@ -878,19 +877,19 @@ while ((s = (*func)()) != NULL)
     if (!isdigit(*endptr) && *endptr != '_')
       {
       *error = string_sprintf("invalid variable name after \"set\" in ACL "
     if (!isdigit(*endptr) && *endptr != '_')
       {
       *error = string_sprintf("invalid variable name after \"set\" in ACL "
-        "modifier \"set %s\" (digit or underscore must follow acl_c or acl_m)",
-        s);
+       "modifier \"set %s\" (digit or underscore must follow acl_c or acl_m)",
+       s);
       return NULL;
       }
 
       return NULL;
       }
 
-    while (*endptr != 0 && *endptr != '=' && !isspace(*endptr))
+    while (*endptr && *endptr != '=' && !isspace(*endptr))
       {
       if (!isalnum(*endptr) && *endptr != '_')
       {
       if (!isalnum(*endptr) && *endptr != '_')
-        {
-        *error = string_sprintf("invalid character \"%c\" in variable name "
-          "in ACL modifier \"set %s\"", *endptr, s);
-        return NULL;
-        }
+       {
+       *error = string_sprintf("invalid character \"%c\" in variable name "
+         "in ACL modifier \"set %s\"", *endptr, s);
+       return NULL;
+       }
       endptr++;
       }
 
       endptr++;
       }
 
@@ -3634,15 +3633,12 @@ for (; cb; cb = cb->next)
       sender_address_cache, -1, 0, CUSS &sender_data);
     break;
 
       sender_address_cache, -1, 0, CUSS &sender_data);
     break;
 
-    /* Connection variables must persist forever */
+    /* Connection variables must persist forever; message variables not */
 
     case ACLC_SET:
       {
       int old_pool = store_pool;
 
     case ACLC_SET:
       {
       int old_pool = store_pool;
-      if (  cb->u.varname[0] == 'c'
-#ifndef DISABLE_DKIM
-         || cb->u.varname[0] == 'd'
-#endif
+      if (  cb->u.varname[0] != 'm'
 #ifndef DISABLE_EVENT
         || event_name          /* An event is being delivered */
 #endif
 #ifndef DISABLE_EVENT
         || event_name          /* An event is being delivered */
 #endif
index 08f5a9d10962a4e3bb8cecf490c6c3bf15b498b8..93aa1678d5e13285a6d2e94e1f70cd98d8a42fcf 100644 (file)
@@ -863,7 +863,7 @@ smarthost_smtp:
 
 local_delivery:
   driver = appendfile
 
 local_delivery:
   driver = appendfile
-  file = /var/mail/$home
+  file = /var/mail/$local_part_verified
   delivery_date_add
   envelope_to_add
   return_path_add
   delivery_date_add
   envelope_to_add
   return_path_add
index 366cd737a0ee29d7f03036e28da36f08ac6f87ea..be6cd616250957aa60bee30cab69d70fcb2cb216 100644 (file)
@@ -587,6 +587,7 @@ static var_entry var_table[] = {
   { "local_part_data",     vtype_stringptr,   &deliver_localpart_data },
   { "local_part_prefix",   vtype_stringptr,   &deliver_localpart_prefix },
   { "local_part_suffix",   vtype_stringptr,   &deliver_localpart_suffix },
   { "local_part_data",     vtype_stringptr,   &deliver_localpart_data },
   { "local_part_prefix",   vtype_stringptr,   &deliver_localpart_prefix },
   { "local_part_suffix",   vtype_stringptr,   &deliver_localpart_suffix },
+  { "local_part_verified", vtype_stringptr,   &deliver_localpart_verified },
 #ifdef HAVE_LOCAL_SCAN
   { "local_scan_data",     vtype_stringptr,   &local_scan_data },
 #endif
 #ifdef HAVE_LOCAL_SCAN
   { "local_scan_data",     vtype_stringptr,   &local_scan_data },
 #endif
index 15ad4e9328988cfe17b3dfd8e3b4a2c641ea1d7d..edd1edbbc9eb40fe78a6b19403bd48136c75d78c 100644 (file)
@@ -817,6 +817,7 @@ uschar *deliver_localpart_orig = NULL;
 uschar *deliver_localpart_parent = NULL;
 uschar *deliver_localpart_prefix = NULL;
 uschar *deliver_localpart_suffix = NULL;
 uschar *deliver_localpart_parent = NULL;
 uschar *deliver_localpart_prefix = NULL;
 uschar *deliver_localpart_suffix = NULL;
+uschar *deliver_localpart_verified = NULL;
 uschar *deliver_out_buffer     = NULL;
 int     deliver_queue_load_max = -1;
 address_item  *deliver_recipients = NULL;
 uschar *deliver_out_buffer     = NULL;
 int     deliver_queue_load_max = -1;
 address_item  *deliver_recipients = NULL;
index bb66cb2392adf2f79a180368067c08133c094fd0..9dfa4a7689e6af2f9d4a98f4d82b35c7e224edd9 100644 (file)
@@ -488,6 +488,7 @@ extern uschar *deliver_localpart_orig; /* The original local part for delivery *
 extern uschar *deliver_localpart_parent; /* The parent local part for delivery */
 extern uschar *deliver_localpart_prefix; /* The stripped prefix, if any */
 extern uschar *deliver_localpart_suffix; /* The stripped suffix, if any */
 extern uschar *deliver_localpart_parent; /* The parent local part for delivery */
 extern uschar *deliver_localpart_prefix; /* The stripped prefix, if any */
 extern uschar *deliver_localpart_suffix; /* The stripped suffix, if any */
+extern uschar *deliver_localpart_verified; /* de-tainted by check_local_part */
 extern uschar *deliver_out_buffer;     /* Buffer for copying file */
 extern int     deliver_queue_load_max; /* Different value for queue running */
 extern address_item *deliver_recipients; /* Current set of addresses */
 extern uschar *deliver_out_buffer;     /* Buffer for copying file */
 extern int     deliver_queue_load_max; /* Different value for queue running */
 extern address_item *deliver_recipients; /* Current set of addresses */
index c6119eed0e68c1bfbd93723f2b73be1b1a3f7379..16ce72c2b1588bac41bb4b0f83d4ff05d3de20bc 100644 (file)
@@ -927,7 +927,7 @@ if ((rc = route_check_dls(r->name, US"local_parts", r->local_parts,
 login of a local user. Note: the third argument to route_finduser() must be
 NULL here, to prevent a numeric string being taken as a numeric uid. If the
 user is found, set deliver_home to the home directory, and also set
 login of a local user. Note: the third argument to route_finduser() must be
 NULL here, to prevent a numeric string being taken as a numeric uid. If the
 user is found, set deliver_home to the home directory, and also set
-local_user_{uid,gid}.  */
+local_user_{uid,gid} and local_part_verified.  */
 
 if (r->check_local_user)
   {
 
 if (r->check_local_user)
   {
@@ -938,6 +938,7 @@ if (r->check_local_user)
       r->name, addr->local_part);
     return SKIP;
     }
       r->name, addr->local_part);
     return SKIP;
     }
+  deliver_localpart_verified = string_copy(US (*pw)->pw_name);
   deliver_home = string_copy(US (*pw)->pw_dir);
   local_user_gid = (*pw)->pw_gid;
   local_user_uid = (*pw)->pw_uid;
   deliver_home = string_copy(US (*pw)->pw_dir);
   local_user_gid = (*pw)->pw_gid;
   local_user_uid = (*pw)->pw_uid;
@@ -1670,6 +1671,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
   the local part sorted. */
 
   router_name = r->name;
   the local part sorted. */
 
   router_name = r->name;
+  deliver_localpart_verified = NULL;
   deliver_set_expansions(addr);
 
   /* For convenience, the pre-router checks are in a separate function, which
   deliver_set_expansions(addr);
 
   /* For convenience, the pre-router checks are in a separate function, which
index 858c806f1d018e694b8d55d58eb233682701a5a3..9ef46801e9418ae4ad1b7eb2d486d050fd25a1b7 100644 (file)
@@ -88,13 +88,13 @@ else
   const uschar *address_expansions_save[ADDRESS_EXPANSIONS_COUNT];
   address_item *snew = deliver_make_addr(s, FALSE);
 
   const uschar *address_expansions_save[ADDRESS_EXPANSIONS_COUNT];
   address_item *snew = deliver_make_addr(s, FALSE);
 
-  if (sender_address != NULL)
+  if (sender_address)
     {
     save1 = sender_address[0];
     sender_address[0] = 0;
     }
 
     {
     save1 = sender_address[0];
     sender_address[0] = 0;
     }
 
-  for (i = 0, p = address_expansions; *p != NULL;)
+  for (i = 0, p = address_expansions; *p;)
     address_expansions_save[i++] = **p++;
   f.address_test_mode = FALSE;
 
     address_expansions_save[i++] = **p++;
   f.address_test_mode = FALSE;
 
@@ -119,10 +119,10 @@ else
     debug_printf("------ End verifying errors address %s ------\n", s);
 
   f.address_test_mode = save_address_test_mode;
     debug_printf("------ End verifying errors address %s ------\n", s);
 
   f.address_test_mode = save_address_test_mode;
-  for (i = 0, p = address_expansions; *p != NULL;)
+  for (i = 0, p = address_expansions; *p)
     **p++ = address_expansions_save[i++];
 
     **p++ = address_expansions_save[i++];
 
-  if (sender_address != NULL) sender_address[0] = save1;
+  if (sender_address) sender_address[0] = save1;
   }
 
 return OK;
   }
 
 return OK;
index 7c0689c1675945292129a9bbcdcd9c0bee167ea2..77b79100cc2a97903db3126aadaca439d8ec40cd 100644 (file)
@@ -52,7 +52,7 @@ local_delivery:
   driver = appendfile
   delivery_date_add
   envelope_to_add
   driver = appendfile
   delivery_date_add
   envelope_to_add
-  file = DIR/test-mail/$local_part
+  file = DIR/test-mail/$local_part_verified
   headers_add = "X-body-linecount: $body_linecount\n\
                  X-message-linecount: $message_linecount\n\
                  X-received-count: $received_count"
   headers_add = "X-body-linecount: $body_linecount\n\
                  X-message-linecount: $message_linecount\n\
                  X-received-count: $received_count"