static uschar *op_table_main[] = {
US"address",
US"addresses",
+ US"base32",
+ US"base32d",
US"base62",
US"base62d",
US"base64",
US"s",
US"sha1",
US"sha256",
+ US"sha3",
US"stat",
US"str2b64",
US"strlen",
enum {
EOP_ADDRESS = nelem(op_table_underscore),
EOP_ADDRESSES,
+ EOP_BASE32,
+ EOP_BASE32D,
EOP_BASE62,
EOP_BASE62D,
EOP_BASE64,
EOP_S,
EOP_SHA1,
EOP_SHA256,
+ EOP_SHA3,
EOP_STAT,
EOP_STR2B64,
EOP_STRLEN,
{ "prvscheck_result", vtype_stringptr, &prvscheck_result },
{ "qualify_domain", vtype_stringptr, &qualify_domain_sender },
{ "qualify_recipient", vtype_stringptr, &qualify_domain_recipient },
+ { "queue_name", vtype_stringptr, &queue_name },
{ "rcpt_count", vtype_int, &rcpt_count },
{ "rcpt_defer_count", vtype_int, &rcpt_defer_count },
{ "rcpt_fail_count", vtype_int, &rcpt_fail_count },
}
+
+static uschar * base32_chars = US"abcdefghijklmnopqrstuvwxyz234567";
+
/*************************************************
* Binary chop search on a table *
*************************************************/
checking for them individually. */
if (!isalpha(name[0]) && yield != NULL)
- {
if (sub[i][0] == 0)
{
num[i] = 0;
num[i] = expanded_string_integer(sub[i], FALSE);
if (expand_string_message != NULL) return NULL;
}
- }
}
/* Result not required */
uschar digest[16];
md5_start(&base);
- md5_end(&base, (uschar *)sub[0], Ustrlen(sub[0]), digest);
+ md5_end(&base, sub[0], Ustrlen(sub[0]), digest);
/* If the length that we are comparing against is 24, the MD5 digest
is expressed as a base64 string. This is the way LDAP does it. However,
if (sublen == 24)
{
- uschar *coded = b64encode((uschar *)digest, 16);
+ uschar *coded = b64encode(digest, 16);
DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n"
" subject=%s\n crypted=%s\n", coded, sub[1]+5);
tempcond = (Ustrcmp(coded, sub[1]+5) == 0);
else if (strncmpic(sub[1], US"{sha1}", 6) == 0)
{
int sublen = Ustrlen(sub[1]+6);
- sha1 base;
+ hctx h;
uschar digest[20];
- sha1_start(&base);
- sha1_end(&base, (uschar *)sub[0], Ustrlen(sub[0]), digest);
+ sha1_start(&h);
+ sha1_end(&h, sub[0], Ustrlen(sub[0]), digest);
/* If the length that we are comparing against is 28, assume the SHA1
digest is expressed as a base64 string. If the length is 40, assume a
if (sublen == 28)
{
- uschar *coded = b64encode((uschar *)digest, 20);
+ uschar *coded = b64encode(digest, 20);
DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n"
" subject=%s\n crypted=%s\n", coded, sub[1]+6);
tempcond = (Ustrcmp(coded, sub[1]+6) == 0);
if (type == HMAC_MD5)
md5_start((md5 *)base);
else
- sha1_start((sha1 *)base);
+ sha1_start((hctx *)base);
}
static void
if (type == HMAC_MD5)
md5_mid((md5 *)base, string);
else
- sha1_mid((sha1 *)base, string);
+ sha1_mid((hctx *)base, string);
}
static void
if (type == HMAC_MD5)
md5_end((md5 *)base, string, length, digest);
else
- sha1_end((sha1 *)base, string, length, digest);
+ sha1_end((hctx *)base, string, length, digest);
}
{
uschar *hash_source, *p;
int size = 0,offset = 0,i;
-sha1 sha1_base;
-void *use_base = &sha1_base;
+hctx h;
uschar innerhash[20];
uschar finalhash[20];
uschar innerkey[64];
outerkey[i] ^= key[i];
}
-chash_start(HMAC_SHA1, use_base);
-chash_mid(HMAC_SHA1, use_base, innerkey);
-chash_end(HMAC_SHA1, use_base, hash_source, offset, innerhash);
+chash_start(HMAC_SHA1, &h);
+chash_mid(HMAC_SHA1, &h, innerkey);
+chash_end(HMAC_SHA1, &h, hash_source, offset, innerhash);
-chash_start(HMAC_SHA1, use_base);
-chash_mid(HMAC_SHA1, use_base, outerkey);
-chash_end(HMAC_SHA1, use_base, innerhash, 20, finalhash);
+chash_start(HMAC_SHA1, &h);
+chash_mid(HMAC_SHA1, &h, outerkey);
+chash_end(HMAC_SHA1, &h, innerhash, 20, finalhash);
p = finalhash_hex;
for (i = 0; i < 3; i++)
{
int ptr = 0;
int size = Ustrlen(string)+ 64;
-int item_type;
uschar *yield = store_get(size);
+int item_type;
const uschar *s = string;
uschar *save_expand_nstring[EXPAND_MAXN+1];
int save_expand_nlength[EXPAND_MAXN+1];
if (next_s == NULL) goto EXPAND_FAILED; /* message already set */
DEBUG(D_expand)
- debug_printf("condition: %.*s\n result: %s\n", (int)(next_s - s), s,
- cond? "true" : "false");
+ debug_printf(" condition: %.*s\n result: %s\n",
+ (int)(next_s - s), s,
+ cond ? "true" : "false");
s = next_s;
{
uschar *sub[3];
md5 md5_base;
- sha1 sha1_base;
+ hctx sha1_ctx;
void *use_base;
int type, i;
int hashlen; /* Number of octets for the hash algorithm's output */
case 3: goto EXPAND_FAILED;
}
- if (Ustrcmp(sub[0], "md5") == 0)
- {
- type = HMAC_MD5;
- use_base = &md5_base;
- hashlen = 16;
- hashblocklen = 64;
- }
- else if (Ustrcmp(sub[0], "sha1") == 0)
- {
- type = HMAC_SHA1;
- use_base = &sha1_base;
- hashlen = 20;
- hashblocklen = 64;
- }
- else
- {
- expand_string_message =
- string_sprintf("hmac algorithm \"%s\" is not recognised", sub[0]);
- goto EXPAND_FAILED;
- }
+ if (!skipping)
+ {
+ if (Ustrcmp(sub[0], "md5") == 0)
+ {
+ type = HMAC_MD5;
+ use_base = &md5_base;
+ hashlen = 16;
+ hashblocklen = 64;
+ }
+ else if (Ustrcmp(sub[0], "sha1") == 0)
+ {
+ type = HMAC_SHA1;
+ use_base = &sha1_ctx;
+ hashlen = 20;
+ hashblocklen = 64;
+ }
+ else
+ {
+ expand_string_message =
+ string_sprintf("hmac algorithm \"%s\" is not recognised", sub[0]);
+ goto EXPAND_FAILED;
+ }
- keyptr = sub[1];
- keylen = Ustrlen(keyptr);
+ keyptr = sub[1];
+ keylen = Ustrlen(keyptr);
- /* If the key is longer than the hash block length, then hash the key
- first */
+ /* If the key is longer than the hash block length, then hash the key
+ first */
- if (keylen > hashblocklen)
- {
- chash_start(type, use_base);
- chash_end(type, use_base, keyptr, keylen, keyhash);
- keyptr = keyhash;
- keylen = hashlen;
- }
+ if (keylen > hashblocklen)
+ {
+ chash_start(type, use_base);
+ chash_end(type, use_base, keyptr, keylen, keyhash);
+ keyptr = keyhash;
+ keylen = hashlen;
+ }
- /* Now make the inner and outer key values */
+ /* Now make the inner and outer key values */
- memset(innerkey, 0x36, hashblocklen);
- memset(outerkey, 0x5c, hashblocklen);
+ memset(innerkey, 0x36, hashblocklen);
+ memset(outerkey, 0x5c, hashblocklen);
- for (i = 0; i < keylen; i++)
- {
- innerkey[i] ^= keyptr[i];
- outerkey[i] ^= keyptr[i];
- }
+ for (i = 0; i < keylen; i++)
+ {
+ innerkey[i] ^= keyptr[i];
+ outerkey[i] ^= keyptr[i];
+ }
- /* Now do the hashes */
+ /* Now do the hashes */
- chash_start(type, use_base);
- chash_mid(type, use_base, innerkey);
- chash_end(type, use_base, sub[2], Ustrlen(sub[2]), innerhash);
+ chash_start(type, use_base);
+ chash_mid(type, use_base, innerkey);
+ chash_end(type, use_base, sub[2], Ustrlen(sub[2]), innerhash);
- chash_start(type, use_base);
- chash_mid(type, use_base, outerkey);
- chash_end(type, use_base, innerhash, hashlen, finalhash);
+ chash_start(type, use_base);
+ chash_mid(type, use_base, outerkey);
+ chash_end(type, use_base, innerhash, hashlen, finalhash);
- /* Encode the final hash as a hex string */
+ /* Encode the final hash as a hex string */
- p = finalhash_hex;
- for (i = 0; i < hashlen; i++)
- {
- *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
- *p++ = hex_digits[finalhash[i] & 0x0f];
- }
+ p = finalhash_hex;
+ for (i = 0; i < hashlen; i++)
+ {
+ *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
+ *p++ = hex_digits[finalhash[i] & 0x0f];
+ }
- DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%.*s)=%.*s\n", sub[0],
- (int)keylen, keyptr, Ustrlen(sub[2]), sub[2], hashlen*2, finalhash_hex);
+ DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n",
+ sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex);
- yield = string_catn(yield, &size, &ptr, finalhash_hex, hashlen*2);
+ yield = string_catn(yield, &size, &ptr, finalhash_hex, hashlen*2);
+ }
+ continue;
}
- continue;
-
/* Handle global substitution for "sg" - like Perl's s/xxx/yyy/g operator.
We have to save the numerical variables and restore them afterwards. */
if (*s++ != '}')
{
expand_string_message = string_sprintf(
- US"missing '}' closing arg %d of extract", i+1);
+ "missing '}' closing arg %d of extract", i+1);
goto EXPAND_FAILED_CURLY;
}
else
{
expand_string_message = string_sprintf(
- US"missing '{' for arg %d of extract", i+1);
+ "missing '{' for arg %d of extract", i+1);
goto EXPAND_FAILED_CURLY;
}
}
if (*s != '{') /*}*/
{
expand_string_message = string_sprintf(
- US"missing '{' for arg %d of listextract", i+1);
+ "missing '{' for arg %d of listextract", i+1);
goto EXPAND_FAILED_CURLY;
}
if (*s++ != '}')
{
expand_string_message = string_sprintf(
- US"missing '}' closing arg %d of listextract", i+1);
+ "missing '}' closing arg %d of listextract", i+1);
goto EXPAND_FAILED_CURLY;
}
switch(c)
{
+ case EOP_BASE32:
+ {
+ uschar *t;
+ unsigned long int n = Ustrtoul(sub, &t, 10);
+ uschar * s = NULL;
+ int sz = 0, i = 0;
+
+ if (*t != 0)
+ {
+ expand_string_message = string_sprintf("argument for base32 "
+ "operator is \"%s\", which is not a decimal number", sub);
+ goto EXPAND_FAILED;
+ }
+ for ( ; n; n >>= 5)
+ s = string_catn(s, &sz, &i, &base32_chars[n & 0x1f], 1);
+
+ while (i > 0) yield = string_catn(yield, &size, &ptr, &s[--i], 1);
+ continue;
+ }
+
+ case EOP_BASE32D:
+ {
+ uschar *tt = sub;
+ unsigned long int n = 0;
+ uschar * s;
+ while (*tt)
+ {
+ uschar * t = Ustrchr(base32_chars, *tt++);
+ if (t == NULL)
+ {
+ expand_string_message = string_sprintf("argument for base32d "
+ "operator is \"%s\", which is not a base 32 number", sub);
+ goto EXPAND_FAILED;
+ }
+ n = n * 32 + (t - base32_chars);
+ }
+ s = string_sprintf("%ld", n);
+ yield = string_cat(yield, &size, &ptr, s);
+ continue;
+ }
+
case EOP_BASE62:
{
uschar *t;
else
#endif
{
- sha1 base;
+ hctx h;
uschar digest[20];
int j;
char st[41];
- sha1_start(&base);
- sha1_end(&base, sub, Ustrlen(sub), digest);
+ sha1_start(&h);
+ sha1_end(&h, 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);
+ yield = string_catn(yield, &size, &ptr, US st, 40);
}
continue;
case EOP_SHA256:
-#ifdef SUPPORT_TLS
+#ifdef EXIM_HAVE_SHA2
if (vp && *(void **)vp->value)
{
uschar * cp = tls_cert_fprt_sha256(*(void **)vp->value);
yield = string_cat(yield, &size, &ptr, cp);
}
else
+ {
+ hctx h;
+ blob b;
+ char st[3];
+
+ exim_sha_init(&h, HASH_SHA256);
+ exim_sha_update(&h, sub, Ustrlen(sub));
+ exim_sha_finish(&h, &b);
+ while (b.len-- > 0)
+ {
+ sprintf(st, "%02X", *b.data++);
+ yield = string_catn(yield, &size, &ptr, US st, 2);
+ }
+ }
+#else
+ expand_string_message = US"sha256 only supported with TLS";
#endif
- expand_string_message = US"sha256 only supported for certificates";
continue;
+ case EOP_SHA3:
+#ifdef EXIM_HAVE_SHA3
+ {
+ hctx h;
+ blob b;
+ char st[3];
+ hashmethod m = !arg ? HASH_SHA3_256
+ : Ustrcmp(arg, "224") == 0 ? HASH_SHA3_224
+ : Ustrcmp(arg, "256") == 0 ? HASH_SHA3_256
+ : Ustrcmp(arg, "384") == 0 ? HASH_SHA3_384
+ : Ustrcmp(arg, "512") == 0 ? HASH_SHA3_512
+ : HASH_BADTYPE;
+
+ if (m == HASH_BADTYPE)
+ {
+ expand_string_message = US"unrecognised sha3 variant";
+ goto EXPAND_FAILED;
+ }
+
+ exim_sha_init(&h, m);
+ exim_sha_update(&h, sub, Ustrlen(sub));
+ exim_sha_finish(&h, &b);
+ while (b.len-- > 0)
+ {
+ sprintf(st, "%02X", *b.data++);
+ yield = string_catn(yield, &size, &ptr, US st, 2);
+ }
+ }
+ continue;
+#else
+ expand_string_message = US"sha3 only supported with GnuTLS 3.5.0 +";
+ goto EXPAND_FAILED;
+#endif
+
/* Convert hex encoding to base64 encoding */
case EOP_HEX2B64:
+/* Avoid potentially exposing a password in a string about to be logged */
+
+uschar *
+expand_hide_passwords(uschar * s)
+{
+return ( ( Ustrstr(s, "failed to expand") != NULL
+ || Ustrstr(s, "expansion of ") != NULL
+ )
+ && ( Ustrstr(s, "mysql") != NULL
+ || Ustrstr(s, "pgsql") != NULL
+ || Ustrstr(s, "redis") != NULL
+ || Ustrstr(s, "sqlite") != NULL
+ || Ustrstr(s, "ldap:") != NULL
+ || Ustrstr(s, "ldaps:") != NULL
+ || Ustrstr(s, "ldapi:") != NULL
+ || Ustrstr(s, "ldapdn:") != NULL
+ || Ustrstr(s, "ldapm:") != NULL
+ ) )
+ ? US"Temporary internal error" : s;
+}
+
+
+
/*************************************************
**************************************************