Fix $regex<n> use-after-free. Bug 2915
[exim.git] / src / src / expand.c
index acde8d5164ba731c9a082b6a49770b0a88d06845..89de56255c9b694ccac7adb77a4247ff421e81a8 100644 (file)
@@ -1860,7 +1860,7 @@ else if (Ustrncmp(name, "r_", 2) == 0)
   return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
   }
 
-/* Handle $auth<n> variables. */
+/* Handle $auth<n>, $regex<n> variables. */
 
 if (Ustrncmp(name, "auth", 4) == 0)
   {
@@ -6958,68 +6958,73 @@ while (*s)
         case 3: goto EXPAND_FAILED;
         }
 
-      g = string_catn(g, US"SRS0=", 5);
-
-      /* ${l_4:${hmac{md5}{SRS_SECRET}{${lc:$return_path}}}}= */
-      hmac_md5(sub[0], string_copylc(sub[1]), cksum, sizeof(cksum));
-      g = string_catn(g, cksum, sizeof(cksum));
-      g = string_catn(g, US"=", 1);
-
-      /* ${base32:${eval:$tod_epoch/86400&0x3ff}}= */
+      if (sub[1] && *(sub[1]))
        {
-       struct timeval now;
-       unsigned long i;
-       gstring * h = NULL;
-
-       gettimeofday(&now, NULL);
-       for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5)
-         h = string_catn(h, &base32_chars[i & 0x1f], 1);
-       if (h) while (h->ptr > 0)
-         g = string_catn(g, &h->s[--h->ptr], 1);
-       }
-      g = string_catn(g, US"=", 1);
+       g = string_catn(g, US"SRS0=", 5);
 
-      /* ${domain:$return_path}=${local_part:$return_path} */
-       {
-        int start, end, domain;
-        uschar * t = parse_extract_address(sub[1], &expand_string_message,
-                                         &start, &end, &domain, FALSE);
-       uschar * s;
+       /* ${l_4:${hmac{md5}{SRS_SECRET}{${lc:$return_path}}}}= */
+       hmac_md5(sub[0], string_copylc(sub[1]), cksum, sizeof(cksum));
+       g = string_catn(g, cksum, sizeof(cksum));
+       g = string_catn(g, US"=", 1);
 
-        if (!t)
-         goto EXPAND_FAILED;
+       /* ${base32:${eval:$tod_epoch/86400&0x3ff}}= */
+         {
+         struct timeval now;
+         unsigned long i;
+         gstring * h = NULL;
 
-       if (domain > 0) g = string_cat(g, t + domain);
+         gettimeofday(&now, NULL);
+         for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5)
+           h = string_catn(h, &base32_chars[i & 0x1f], 1);
+         if (h) while (h->ptr > 0)
+           g = string_catn(g, &h->s[--h->ptr], 1);
+         }
        g = string_catn(g, US"=", 1);
 
-       s = domain > 0 ? string_copyn(t, domain - 1) : t;
-       if ((quoted = Ustrchr(s, '"') != NULL))
+       /* ${domain:$return_path}=${local_part:$return_path} */
          {
-         gstring * h = NULL;
-         DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n");
-         while (*s)            /* de-quote */
+         int start, end, domain;
+         uschar * t = parse_extract_address(sub[1], &expand_string_message,
+                                           &start, &end, &domain, FALSE);
+         uschar * s;
+
+         if (!t)
+           goto EXPAND_FAILED;
+
+         if (domain > 0) g = string_cat(g, t + domain);
+         g = string_catn(g, US"=", 1);
+
+         s = domain > 0 ? string_copyn(t, domain - 1) : t;
+         if ((quoted = Ustrchr(s, '"') != NULL))
            {
-           while (*s && *s != '"') h = string_catn(h, s++, 1);
-           if (*s) s++;
-           while (*s && *s != '"') h = string_catn(h, s++, 1);
-           if (*s) s++;
+           gstring * h = NULL;
+           DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n");
+           while (*s)          /* de-quote */
+             {
+             while (*s && *s != '"') h = string_catn(h, s++, 1);
+             if (*s) s++;
+             while (*s && *s != '"') h = string_catn(h, s++, 1);
+             if (*s) s++;
+             }
+           gstring_release_unused(h);
+           s = string_from_gstring(h);
            }
-         gstring_release_unused(h);
-         s = string_from_gstring(h);
+         g = string_cat(g, s);
          }
-       g = string_cat(g, s);
-        }
 
-      /* Assume that if the original local_part had quotes
-      it was for good reason */
+       /* Assume that if the original local_part had quotes
+       it was for good reason */
 
-      if (quoted) yield = string_catn(yield, US"\"", 1);
-      yield = string_catn(yield, g->s, g->ptr);
-      if (quoted) yield = string_catn(yield, US"\"", 1);
+       if (quoted) yield = string_catn(yield, US"\"", 1);
+       yield = string_catn(yield, g->s, g->ptr);
+       if (quoted) yield = string_catn(yield, US"\"", 1);
 
-      /* @$original_domain */
-      yield = string_catn(yield, US"@", 1);
-      yield = string_cat(yield, sub[2]);
+       /* @$original_domain */
+       yield = string_catn(yield, US"@", 1);
+       yield = string_cat(yield, sub[2]);
+       }
+      else
+       DEBUG(D_expand) debug_printf_indent("null return_path for srs-encode\n");
 
       break;
       }