Use Ustrlen() on a uschar
[exim.git] / src / src / expand.c
index 05b714a7f8debd643208d4b14dd9007b9732b474..88a5ee399db9c15c2a94cd95aae6f364afab3249 100644 (file)
@@ -205,6 +205,7 @@ static uschar *op_table_main[] = {
   US"rxquote",
   US"s",
   US"sha1",
+  US"sha256",
   US"stat",
   US"str2b64",
   US"strlen",
@@ -242,6 +243,7 @@ enum {
   EOP_RXQUOTE,
   EOP_S,
   EOP_SHA1,
+  EOP_SHA256,
   EOP_STAT,
   EOP_STR2B64,
   EOP_STRLEN,
@@ -346,25 +348,9 @@ enum {
 };
 
 
-/* Type for main variable table */
-
-typedef struct {
-  const char *name;
-  int         type;
-  void       *value;
-} var_entry;
-
-/* Type for entries pointing to address/length pairs. Not currently
-in use. */
-
-typedef struct {
-  uschar **address;
-  int  *length;
-} alblock;
-
 /* Types of table entry */
 
-enum {
+enum vtypes {
   vtype_int,            /* value is address of int */
   vtype_filter_int,     /* ditto, but recognized only when filtering */
   vtype_ino,            /* value is address of ino_t (not always an int) */
@@ -397,7 +383,23 @@ enum {
   #ifndef DISABLE_DKIM
   ,vtype_dkim           /* Lookup of value in DKIM signature */
   #endif
-  };
+};
+
+/* Type for main variable table */
+
+typedef struct {
+  const char *name;
+  enum vtypes type;
+  void       *value;
+} var_entry;
+
+/* Type for entries pointing to address/length pairs. Not currently
+in use. */
+
+typedef struct {
+  uschar **address;
+  int  *length;
+} alblock;
 
 static uschar * fn_recipients(void);
 
@@ -671,24 +673,26 @@ static var_entry var_table[] = {
   { "tls_in_bits",         vtype_int,         &tls_in.bits },
   { "tls_in_certificate_verified", vtype_int, &tls_in.certificate_verified },
   { "tls_in_cipher",       vtype_stringptr,   &tls_in.cipher },
+  { "tls_in_ocsp",         vtype_int,         &tls_in.ocsp },
   { "tls_in_ourcert",      vtype_cert,        &tls_in.ourcert },
   { "tls_in_peercert",     vtype_cert,        &tls_in.peercert },
   { "tls_in_peerdn",       vtype_stringptr,   &tls_in.peerdn },
-#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS)
+#if defined(SUPPORT_TLS)
   { "tls_in_sni",          vtype_stringptr,   &tls_in.sni },
 #endif
   { "tls_out_bits",        vtype_int,         &tls_out.bits },
   { "tls_out_certificate_verified", vtype_int,&tls_out.certificate_verified },
   { "tls_out_cipher",      vtype_stringptr,   &tls_out.cipher },
+  { "tls_out_ocsp",        vtype_int,         &tls_out.ocsp },
   { "tls_out_ourcert",     vtype_cert,        &tls_out.ourcert },
   { "tls_out_peercert",    vtype_cert,        &tls_out.peercert },
   { "tls_out_peerdn",      vtype_stringptr,   &tls_out.peerdn },
-#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS)
+#if defined(SUPPORT_TLS)
   { "tls_out_sni",         vtype_stringptr,   &tls_out.sni },
 #endif
 
   { "tls_peerdn",          vtype_stringptr,   &tls_in.peerdn },        /* mind the alphabetical order! */
-#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS)
+#if defined(SUPPORT_TLS)
   { "tls_sni",             vtype_stringptr,   &tls_in.sni },   /* mind the alphabetical order! */
 #endif
 
@@ -4663,6 +4667,9 @@ while (*s != 0)
 
         DEBUG(D_expand) debug_printf("connected to socket %s\n", sub_arg[0]);
 
+       /* Allow sequencing of test actions */
+       if (running_in_test_harness) millisleep(100);
+
         /* Write the request string, if not empty */
 
         if (sub_arg[1][0] != 0)
@@ -4686,6 +4693,8 @@ while (*s != 0)
         shutdown(fd, SHUT_WR);
         #endif
 
+       if (running_in_test_harness) millisleep(100);
+
         /* Now we need to read from the socket, under a timeout. The function
         that reads a file can be used. */
 
@@ -5363,8 +5372,6 @@ while (*s != 0)
 #ifdef SUPPORT_TLS
     case EITEM_CERTEXTRACT:
       {
-      int i;
-      int field_number = 1;
       uschar *save_lookup_value = lookup_value;
       uschar *sub[2];
       int save_expand_nmax =
@@ -5380,7 +5387,6 @@ while (*s != 0)
       /* strip spaces fore & aft */
       {
       int len;
-      int x = 0;
       uschar *p = sub[0];
 
       while (isspace(*p)) p++;
@@ -5722,19 +5728,16 @@ while (*s != 0)
     {
     int c;
     uschar *arg = NULL;
-    uschar *sub = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
-    if (sub == NULL) goto EXPAND_FAILED;
-    s++;
+    uschar *sub;
+    var_entry *vp = NULL;
 
     /* Owing to an historical mis-design, an underscore may be part of the
     operator name, or it may introduce arguments.  We therefore first scan the
     table of names that contain underscores. If there is no match, we cut off
     the arguments and then scan the main table. */
 
-    c = chop_match(name, op_table_underscore,
-      sizeof(op_table_underscore)/sizeof(uschar *));
-
-    if (c < 0)
+    if ((c = chop_match(name, op_table_underscore,
+       sizeof(op_table_underscore)/sizeof(uschar *))) < 0)
       {
       arg = Ustrchr(name, '_');
       if (arg != NULL) *arg = 0;
@@ -5744,6 +5747,37 @@ while (*s != 0)
       if (arg != NULL) *arg++ = '_';   /* Put back for error messages */
       }
 
+    /* Deal specially with operators that might take a certificate variable
+    as we do not want to do the usual expansion. For most, expand the string.*/
+    switch(c)
+      {
+#ifdef SUPPORT_TLS
+      case EOP_MD5:
+      case EOP_SHA1:
+      case EOP_SHA256:
+       if (s[1] == '$')
+         {
+         uschar * s1 = s;
+         sub = expand_string_internal(s+2, TRUE, &s1, skipping,
+                 FALSE, &resetok);
+         if (!sub)       goto EXPAND_FAILED;           /*{*/
+         if (*s1 != '}') goto EXPAND_FAILED_CURLY;
+         if ((vp = find_var_ent(sub)) && vp->type == vtype_cert)
+           {
+           s = s1+1;
+           break;
+           }
+         vp = NULL;
+         }
+        /*FALLTHROUGH*/
+#endif
+      default:
+       sub = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+       if (!sub) goto EXPAND_FAILED;
+       s++;
+       break;
+      }
+
     /* If we are skipping, we don't need to perform the operation at all.
     This matters for operations like "mask", because the data may not be
     in the correct format when skipping. For example, the expression may test
@@ -5828,30 +5862,58 @@ while (*s != 0)
         }
 
       case EOP_MD5:
-        {
-        md5 base;
-        uschar digest[16];
-        int j;
-        char st[33];
-        md5_start(&base);
-        md5_end(&base, sub, Ustrlen(sub), digest);
-        for(j = 0; j < 16; j++) sprintf(st+2*j, "%02x", digest[j]);
-        yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st));
+#ifdef SUPPORT_TLS
+       if (vp && *(void **)vp->value)
+         {
+         uschar * cp = tls_cert_fprt_md5(*(void **)vp->value);
+         yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp));
+         }
+       else
+#endif
+         {
+         md5 base;
+         uschar digest[16];
+         int j;
+         char st[33];
+         md5_start(&base);
+         md5_end(&base, sub, Ustrlen(sub), digest);
+         for(j = 0; j < 16; j++) sprintf(st+2*j, "%02x", digest[j]);
+         yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st));
+         }
         continue;
-        }
 
       case EOP_SHA1:
-        {
-        sha1 base;
-        uschar digest[20];
-        int j;
-        char st[41];
-        sha1_start(&base);
-        sha1_end(&base, sub, Ustrlen(sub), digest);
-        for(j = 0; j < 20; j++) sprintf(st+2*j, "%02X", digest[j]);
-        yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st));
+#ifdef SUPPORT_TLS
+       if (vp && *(void **)vp->value)
+         {
+         uschar * cp = tls_cert_fprt_sha1(*(void **)vp->value);
+         yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp));
+         }
+       else
+#endif
+         {
+         sha1 base;
+         uschar digest[20];
+         int j;
+         char st[41];
+         sha1_start(&base);
+         sha1_end(&base, sub, Ustrlen(sub), digest);
+         for(j = 0; j < 20; j++) sprintf(st+2*j, "%02X", digest[j]);
+         yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st));
+         }
+        continue;
+
+      case EOP_SHA256:
+#ifdef SUPPORT_TLS
+       if (vp && *(void **)vp->value)
+         {
+         uschar * cp = tls_cert_fprt_sha256(*(void **)vp->value);
+         yield = string_cat(yield, &size, &ptr, cp, (int)Ustrlen(cp));
+         }
+       else
+#endif
+         expand_string_message = US"sha256 only supported for certificates";
         continue;
-        }
 
       /* Convert hex encoding to base64 encoding */
 
@@ -6304,7 +6366,7 @@ while (*s != 0)
       case EOP_UTF8CLEAN:
         {
         int seq_len, index = 0;
-        int bytes_left  = 0;
+        int bytes_left = 0;
         uschar seq_buff[4];                    /* accumulate utf-8 here */
         
         while (*sub != 0)
@@ -6315,7 +6377,7 @@ while (*s != 0)
 
          complete = 0;
          c = *sub++;
-         if(bytes_left)
+         if (bytes_left)
            {
            if ((c & 0xc0) != 0x80)
              {