Enable operator md5 and sha1 use on certificate variables. Bug 1170
[exim.git] / src / src / expand.c
index 34fb0346effe91d7160ed7ceecad80a2a91b2429..9532d9d3364f2987e9bfaf6ce816932307138df3 100644 (file)
@@ -671,6 +671,7 @@ 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 },
@@ -680,6 +681,7 @@ static var_entry var_table[] = {
   { "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 },
@@ -1185,26 +1187,28 @@ return string_nextinlist(&list, &sep, NULL, 0);
 
 
 /* Certificate fields, by name.  Worry about by-OID later */
+/* Names are chosen to not have common prefixes */
 
 #ifdef SUPPORT_TLS
 typedef struct
 {
 uschar * name;
-uschar * (*getfn)(void * cert);
+int      namelen;
+uschar * (*getfn)(void * cert, uschar * mod);
 } certfield;
 static certfield certfields[] =
 {                      /* linear search; no special order */
-  { US"version",       &tls_cert_version },
-  { US"serial_number", &tls_cert_serial_number },
-  { US"subject",       &tls_cert_subject },
-  { US"notbefore",     &tls_cert_not_before },
-  { US"notafter",      &tls_cert_not_after },
-  { US"issuer",                &tls_cert_issuer },
-  { US"signature",     &tls_cert_signature },
-  { US"signature_algorithm",   &tls_cert_signature_algorithm },
-  { US"subject_altname",       &tls_cert_subject_altname },
-  { US"ocsp_uri",      &tls_cert_ocsp_uri },
-  { US"crl_uri",       &tls_cert_crl_uri },
+  { US"version",        7,  &tls_cert_version },
+  { US"serial_number",  13, &tls_cert_serial_number },
+  { US"subject",        7,  &tls_cert_subject },
+  { US"notbefore",      9,  &tls_cert_not_before },
+  { US"notafter",       8,  &tls_cert_not_after },
+  { US"issuer",                 6,  &tls_cert_issuer },
+  { US"signature",      9,  &tls_cert_signature },
+  { US"sig_algorithm",  13, &tls_cert_signature_algorithm },
+  { US"subj_altname",    12, &tls_cert_subject_altname },
+  { US"ocsp_uri",       8,  &tls_cert_ocsp_uri },
+  { US"crl_uri",        7,  &tls_cert_crl_uri },
 };
 
 static uschar *
@@ -1236,8 +1240,12 @@ if (*field >= '0' && *field <= '9')
 for(cp = certfields;
     cp < certfields + nelements(certfields);
     cp++)
-  if (Ustrcmp(cp->name, field) == 0)
-    return (*cp->getfn)( *(void **)vp->value );
+  if (Ustrncmp(cp->name, field, cp->namelen) == 0)
+    {
+    uschar * modifier = *(field += cp->namelen) == ','
+      ? ++field : NULL;
+    return (*cp->getfn)( *(void **)vp->value, modifier );
+    }
 
 expand_string_message = 
   string_sprintf("bad field selector \"%s\" for certextract", field);
@@ -3949,6 +3957,8 @@ while (*s != 0)
        {
        case OK:
        case FAIL:
+         DEBUG(D_expand)
+           debug_printf("acl expansion yield: %s\n", user_msg);
          if (user_msg)
             yield = string_cat(yield, &size, &ptr, user_msg, Ustrlen(user_msg));
          continue;
@@ -5714,19 +5724,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;
 
     /* 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;
@@ -5736,6 +5743,34 @@ 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)
+      {
+      case EOP_SHA1:
+      case EOP_MD5:
+       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*/
+      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
@@ -5820,30 +5855,42 @@ 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));
+       if (vp && *(void **)vp->value)
+         {
+         uschar * cp = tls_cert_fprt_md5(*(void **)vp->value);
+         yield = string_cat(yield, &size, &ptr, cp, (int)strlen(cp));
+         }
+       else
+         {
+         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));
+       if (vp && *(void **)vp->value)
+         {
+         uschar * cp = tls_cert_fprt_sha1(*(void **)vp->value);
+         yield = string_cat(yield, &size, &ptr, cp, (int)strlen(cp));
+         }
+       else
+         {
+         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;
-        }
 
       /* Convert hex encoding to base64 encoding */
 
@@ -7005,7 +7052,6 @@ return 0;
 
 #endif
 
-/*
- vi: aw ai sw=2
+/* vi: aw ai sw=2
 */
 /* End of expand.c */