|
Lines 2-9
Link Here
|
| 2 |
* Exim - an Internet mail transport agent * |
2 |
* Exim - an Internet mail transport agent * |
| 3 |
*************************************************/ |
3 |
*************************************************/ |
| 4 |
|
4 |
|
|
|
5 |
/* Copyright (c) The Exim Maintainers 2020 - 2022 */ |
| 5 |
/* Copyright (c) University of Cambridge 1995 - 2018 */ |
6 |
/* Copyright (c) University of Cambridge 1995 - 2018 */ |
| 6 |
/* Copyright (c) The Exim Maintainers 2020 */ |
|
|
| 7 |
/* See the file NOTICE for conditions of use and distribution. */ |
7 |
/* See the file NOTICE for conditions of use and distribution. */ |
| 8 |
|
8 |
|
| 9 |
|
9 |
|
|
Lines 131-137
Link Here
|
| 131 |
US"run", |
131 |
US"run", |
| 132 |
US"sg", |
132 |
US"sg", |
| 133 |
US"sort", |
133 |
US"sort", |
| 134 |
#ifdef EXPERIMENTAL_SRS_NATIVE |
134 |
#ifdef SUPPORT_SRS |
| 135 |
US"srs_encode", |
135 |
US"srs_encode", |
| 136 |
#endif |
136 |
#endif |
| 137 |
US"substr", |
137 |
US"substr", |
|
Lines 166-172
Link Here
|
| 166 |
EITEM_RUN, |
166 |
EITEM_RUN, |
| 167 |
EITEM_SG, |
167 |
EITEM_SG, |
| 168 |
EITEM_SORT, |
168 |
EITEM_SORT, |
| 169 |
#ifdef EXPERIMENTAL_SRS_NATIVE |
169 |
#ifdef SUPPORT_SRS |
| 170 |
EITEM_SRS_ENCODE, |
170 |
EITEM_SRS_ENCODE, |
| 171 |
#endif |
171 |
#endif |
| 172 |
EITEM_SUBSTR, |
172 |
EITEM_SUBSTR, |
|
Lines 177-183
Link Here
|
| 177 |
cases to introduce arguments, whereas for other it is part of the name. This is |
177 |
cases to introduce arguments, whereas for other it is part of the name. This is |
| 178 |
an historical mis-design. */ |
178 |
an historical mis-design. */ |
| 179 |
|
179 |
|
| 180 |
static uschar *op_table_underscore[] = { |
180 |
static uschar * op_table_underscore[] = { |
| 181 |
US"from_utf8", |
181 |
US"from_utf8", |
| 182 |
US"local_part", |
182 |
US"local_part", |
| 183 |
US"quote_local_part", |
183 |
US"quote_local_part", |
|
Lines 216-222
Link Here
|
| 216 |
US"base62d", |
216 |
US"base62d", |
| 217 |
US"base64", |
217 |
US"base64", |
| 218 |
US"base64d", |
218 |
US"base64d", |
| 219 |
US"bless", |
|
|
| 220 |
US"domain", |
219 |
US"domain", |
| 221 |
US"escape", |
220 |
US"escape", |
| 222 |
US"escape8bit", |
221 |
US"escape8bit", |
|
Lines 264-270
Link Here
|
| 264 |
EOP_BASE62D, |
263 |
EOP_BASE62D, |
| 265 |
EOP_BASE64, |
264 |
EOP_BASE64, |
| 266 |
EOP_BASE64D, |
265 |
EOP_BASE64D, |
| 267 |
EOP_BLESS, |
|
|
| 268 |
EOP_DOMAIN, |
266 |
EOP_DOMAIN, |
| 269 |
EOP_ESCAPE, |
267 |
EOP_ESCAPE, |
| 270 |
EOP_ESCAPE8BIT, |
268 |
EOP_ESCAPE8BIT, |
|
Lines 334-340
Link Here
|
| 334 |
US"gei", |
332 |
US"gei", |
| 335 |
US"gt", |
333 |
US"gt", |
| 336 |
US"gti", |
334 |
US"gti", |
| 337 |
#ifdef EXPERIMENTAL_SRS_NATIVE |
335 |
#ifdef SUPPORT_SRS |
| 338 |
US"inbound_srs", |
336 |
US"inbound_srs", |
| 339 |
#endif |
337 |
#endif |
| 340 |
US"inlist", |
338 |
US"inlist", |
|
Lines 387-393
Link Here
|
| 387 |
ECOND_STR_GEI, |
385 |
ECOND_STR_GEI, |
| 388 |
ECOND_STR_GT, |
386 |
ECOND_STR_GT, |
| 389 |
ECOND_STR_GTI, |
387 |
ECOND_STR_GTI, |
| 390 |
#ifdef EXPERIMENTAL_SRS_NATIVE |
388 |
#ifdef SUPPORT_SRS |
| 391 |
ECOND_INBOUND_SRS, |
389 |
ECOND_INBOUND_SRS, |
| 392 |
#endif |
390 |
#endif |
| 393 |
ECOND_INLIST, |
391 |
ECOND_INLIST, |
|
Lines 446-454
Link Here
|
| 446 |
vtype_pspace, /* partition space; value is T/F for spool/log */ |
444 |
vtype_pspace, /* partition space; value is T/F for spool/log */ |
| 447 |
vtype_pinodes, /* partition inodes; value is T/F for spool/log */ |
445 |
vtype_pinodes, /* partition inodes; value is T/F for spool/log */ |
| 448 |
vtype_cert /* SSL certificate */ |
446 |
vtype_cert /* SSL certificate */ |
| 449 |
#ifndef DISABLE_DKIM |
447 |
#ifndef DISABLE_DKIM |
| 450 |
,vtype_dkim /* Lookup of value in DKIM signature */ |
448 |
,vtype_dkim /* Lookup of value in DKIM signature */ |
| 451 |
#endif |
449 |
#endif |
| 452 |
}; |
450 |
}; |
| 453 |
|
451 |
|
| 454 |
/* Type for main variable table */ |
452 |
/* Type for main variable table */ |
|
Lines 585-593
Link Here
|
| 585 |
{ "interface_address", vtype_stringptr, &interface_address }, |
583 |
{ "interface_address", vtype_stringptr, &interface_address }, |
| 586 |
{ "interface_port", vtype_int, &interface_port }, |
584 |
{ "interface_port", vtype_int, &interface_port }, |
| 587 |
{ "item", vtype_stringptr, &iterate_item }, |
585 |
{ "item", vtype_stringptr, &iterate_item }, |
| 588 |
#ifdef LOOKUP_LDAP |
586 |
#ifdef LOOKUP_LDAP |
| 589 |
{ "ldap_dn", vtype_stringptr, &eldap_dn }, |
587 |
{ "ldap_dn", vtype_stringptr, &eldap_dn }, |
| 590 |
#endif |
588 |
#endif |
| 591 |
{ "load_average", vtype_load_avg, NULL }, |
589 |
{ "load_average", vtype_load_avg, NULL }, |
| 592 |
{ "local_part", vtype_stringptr, &deliver_localpart }, |
590 |
{ "local_part", vtype_stringptr, &deliver_localpart }, |
| 593 |
{ "local_part_data", vtype_stringptr, &deliver_localpart_data }, |
591 |
{ "local_part_data", vtype_stringptr, &deliver_localpart_data }, |
|
Lines 752-769
Link Here
|
| 752 |
{ "spool_directory", vtype_stringptr, &spool_directory }, |
750 |
{ "spool_directory", vtype_stringptr, &spool_directory }, |
| 753 |
{ "spool_inodes", vtype_pinodes, (void *)TRUE }, |
751 |
{ "spool_inodes", vtype_pinodes, (void *)TRUE }, |
| 754 |
{ "spool_space", vtype_pspace, (void *)TRUE }, |
752 |
{ "spool_space", vtype_pspace, (void *)TRUE }, |
| 755 |
#ifdef EXPERIMENTAL_SRS |
753 |
#ifdef SUPPORT_SRS |
| 756 |
{ "srs_db_address", vtype_stringptr, &srs_db_address }, |
|
|
| 757 |
{ "srs_db_key", vtype_stringptr, &srs_db_key }, |
| 758 |
{ "srs_orig_recipient", vtype_stringptr, &srs_orig_recipient }, |
| 759 |
{ "srs_orig_sender", vtype_stringptr, &srs_orig_sender }, |
| 760 |
#endif |
| 761 |
#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE) |
| 762 |
{ "srs_recipient", vtype_stringptr, &srs_recipient }, |
754 |
{ "srs_recipient", vtype_stringptr, &srs_recipient }, |
| 763 |
#endif |
755 |
#endif |
| 764 |
#ifdef EXPERIMENTAL_SRS |
|
|
| 765 |
{ "srs_status", vtype_stringptr, &srs_status }, |
| 766 |
#endif |
| 767 |
{ "thisaddress", vtype_stringptr, &filter_thisaddress }, |
756 |
{ "thisaddress", vtype_stringptr, &filter_thisaddress }, |
| 768 |
|
757 |
|
| 769 |
/* The non-(in,out) variables are now deprecated */ |
758 |
/* The non-(in,out) variables are now deprecated */ |
|
Lines 779-785
Link Here
|
| 779 |
{ "tls_in_ourcert", vtype_cert, &tls_in.ourcert }, |
768 |
{ "tls_in_ourcert", vtype_cert, &tls_in.ourcert }, |
| 780 |
{ "tls_in_peercert", vtype_cert, &tls_in.peercert }, |
769 |
{ "tls_in_peercert", vtype_cert, &tls_in.peercert }, |
| 781 |
{ "tls_in_peerdn", vtype_stringptr, &tls_in.peerdn }, |
770 |
{ "tls_in_peerdn", vtype_stringptr, &tls_in.peerdn }, |
| 782 |
#ifdef EXPERIMENTAL_TLS_RESUME |
771 |
#ifndef DISABLE_TLS_RESUME |
| 783 |
{ "tls_in_resumption", vtype_int, &tls_in.resumption }, |
772 |
{ "tls_in_resumption", vtype_int, &tls_in.resumption }, |
| 784 |
#endif |
773 |
#endif |
| 785 |
#ifndef DISABLE_TLS |
774 |
#ifndef DISABLE_TLS |
|
Lines 797-803
Link Here
|
| 797 |
{ "tls_out_ourcert", vtype_cert, &tls_out.ourcert }, |
786 |
{ "tls_out_ourcert", vtype_cert, &tls_out.ourcert }, |
| 798 |
{ "tls_out_peercert", vtype_cert, &tls_out.peercert }, |
787 |
{ "tls_out_peercert", vtype_cert, &tls_out.peercert }, |
| 799 |
{ "tls_out_peerdn", vtype_stringptr, &tls_out.peerdn }, |
788 |
{ "tls_out_peerdn", vtype_stringptr, &tls_out.peerdn }, |
| 800 |
#ifdef EXPERIMENTAL_TLS_RESUME |
789 |
#ifndef DISABLE_TLS_RESUME |
| 801 |
{ "tls_out_resumption", vtype_int, &tls_out.resumption }, |
790 |
{ "tls_out_resumption", vtype_int, &tls_out.resumption }, |
| 802 |
#endif |
791 |
#endif |
| 803 |
#ifndef DISABLE_TLS |
792 |
#ifndef DISABLE_TLS |
|
Lines 1299-1305
Link Here
|
| 1299 |
const uschar * tlist = list; |
1288 |
const uschar * tlist = list; |
| 1300 |
int sep = 0; |
1289 |
int sep = 0; |
| 1301 |
/* Tainted mem for the throwaway element copies */ |
1290 |
/* Tainted mem for the throwaway element copies */ |
| 1302 |
uschar * dummy = store_get(2, TRUE); |
1291 |
uschar * dummy = store_get(2, GET_TAINTED); |
| 1303 |
|
1292 |
|
| 1304 |
if (field < 0) |
1293 |
if (field < 0) |
| 1305 |
{ |
1294 |
{ |
|
Lines 1595-1601
Link Here
|
| 1595 |
*/ |
1584 |
*/ |
| 1596 |
|
1585 |
|
| 1597 |
static uschar * |
1586 |
static uschar * |
| 1598 |
find_header(uschar *name, int *newsize, unsigned flags, uschar *charset) |
1587 |
find_header(uschar *name, int *newsize, unsigned flags, const uschar *charset) |
| 1599 |
{ |
1588 |
{ |
| 1600 |
BOOL found = !name; |
1589 |
BOOL found = !name; |
| 1601 |
int len = name ? Ustrlen(name) : 0; |
1590 |
int len = name ? Ustrlen(name) : 0; |
|
Lines 1709-1717
Link Here
|
| 1709 |
if (sender_host_name) |
1698 |
if (sender_host_name) |
| 1710 |
g = string_append(g, 3, US";\n\tiprev=pass (", sender_host_name, US")"); |
1699 |
g = string_append(g, 3, US";\n\tiprev=pass (", sender_host_name, US")"); |
| 1711 |
else if (host_lookup_deferred) |
1700 |
else if (host_lookup_deferred) |
| 1712 |
g = string_catn(g, US";\n\tiprev=temperror", 19); |
1701 |
g = string_cat(g, US";\n\tiprev=temperror"); |
| 1713 |
else if (host_lookup_failed) |
1702 |
else if (host_lookup_failed) |
| 1714 |
g = string_catn(g, US";\n\tiprev=fail", 13); |
1703 |
g = string_cat(g, US";\n\tiprev=fail"); |
| 1715 |
else |
1704 |
else |
| 1716 |
return g; |
1705 |
return g; |
| 1717 |
|
1706 |
|
|
Lines 1762-1769
Link Here
|
| 1762 |
#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS |
1751 |
#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS |
| 1763 |
uschar * sname; |
1752 |
uschar * sname; |
| 1764 |
#endif |
1753 |
#endif |
| 1765 |
fd_set fds; |
|
|
| 1766 |
struct timeval tv; |
| 1767 |
|
1754 |
|
| 1768 |
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) |
1755 |
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) |
| 1769 |
{ |
1756 |
{ |
|
Lines 1807-1815
Link Here
|
| 1807 |
buf[0] = NOTIFY_QUEUE_SIZE_REQ; |
1794 |
buf[0] = NOTIFY_QUEUE_SIZE_REQ; |
| 1808 |
if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; } |
1795 |
if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; } |
| 1809 |
|
1796 |
|
| 1810 |
FD_ZERO(&fds); FD_SET(fd, &fds); |
1797 |
if (poll_one_fd(fd, POLLIN, 2 * 1000) != 1) |
| 1811 |
tv.tv_sec = 2; tv.tv_usec = 0; |
|
|
| 1812 |
if (select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv) != 1) |
| 1813 |
{ |
1798 |
{ |
| 1814 |
DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n"); |
1799 |
DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n"); |
| 1815 |
len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached()); |
1800 |
len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached()); |
|
Lines 1856-1862
Link Here
|
| 1856 |
something non-NULL if exists_only is TRUE |
1841 |
something non-NULL if exists_only is TRUE |
| 1857 |
*/ |
1842 |
*/ |
| 1858 |
|
1843 |
|
| 1859 |
static uschar * |
1844 |
static const uschar * |
| 1860 |
find_variable(uschar *name, BOOL exists_only, BOOL skipping, int *newsize) |
1845 |
find_variable(uschar *name, BOOL exists_only, BOOL skipping, int *newsize) |
| 1861 |
{ |
1846 |
{ |
| 1862 |
var_entry * vp; |
1847 |
var_entry * vp; |
|
Lines 1894-1908
Link Here
|
| 1894 |
{ |
1879 |
{ |
| 1895 |
uschar *endptr; |
1880 |
uschar *endptr; |
| 1896 |
int n = Ustrtoul(name + 4, &endptr, 10); |
1881 |
int n = Ustrtoul(name + 4, &endptr, 10); |
| 1897 |
if (*endptr == 0 && n != 0 && n <= AUTH_VARS) |
1882 |
if (!*endptr && n != 0 && n <= AUTH_VARS) |
| 1898 |
return !auth_vars[n-1] ? US"" : auth_vars[n-1]; |
1883 |
return auth_vars[n-1] ? auth_vars[n-1] : US""; |
| 1899 |
} |
1884 |
} |
| 1900 |
else if (Ustrncmp(name, "regex", 5) == 0) |
1885 |
else if (Ustrncmp(name, "regex", 5) == 0) |
| 1901 |
{ |
1886 |
{ |
| 1902 |
uschar *endptr; |
1887 |
uschar *endptr; |
| 1903 |
int n = Ustrtoul(name + 5, &endptr, 10); |
1888 |
int n = Ustrtoul(name + 5, &endptr, 10); |
| 1904 |
if (*endptr == 0 && n != 0 && n <= REGEX_VARS) |
1889 |
if (!*endptr && n != 0 && n <= REGEX_VARS) |
| 1905 |
return !regex_vars[n-1] ? US"" : regex_vars[n-1]; |
1890 |
return regex_vars[n-1] ? regex_vars[n-1] : US""; |
| 1906 |
} |
1891 |
} |
| 1907 |
|
1892 |
|
| 1908 |
/* For all other variables, search the table */ |
1893 |
/* For all other variables, search the table */ |
|
Lines 1985-1995
Link Here
|
| 1985 |
ss = (uschar **)(val); |
1970 |
ss = (uschar **)(val); |
| 1986 |
if (!*ss && deliver_datafile >= 0) /* Read body when needed */ |
1971 |
if (!*ss && deliver_datafile >= 0) /* Read body when needed */ |
| 1987 |
{ |
1972 |
{ |
| 1988 |
uschar *body; |
1973 |
uschar * body; |
| 1989 |
off_t start_offset = SPOOL_DATA_START_OFFSET; |
1974 |
off_t start_offset = SPOOL_DATA_START_OFFSET; |
| 1990 |
int len = message_body_visible; |
1975 |
int len = message_body_visible; |
|
|
1976 |
|
| 1991 |
if (len > message_size) len = message_size; |
1977 |
if (len > message_size) len = message_size; |
| 1992 |
*ss = body = store_malloc(len+1); |
1978 |
*ss = body = store_get(len+1, GET_TAINTED); |
| 1993 |
body[0] = 0; |
1979 |
body[0] = 0; |
| 1994 |
if (vp->type == vtype_msgbody_end) |
1980 |
if (vp->type == vtype_msgbody_end) |
| 1995 |
{ |
1981 |
{ |
|
Lines 2004-2011
Link Here
|
| 2004 |
if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0) |
1990 |
if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0) |
| 2005 |
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "deliver_datafile lseek: %s", |
1991 |
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "deliver_datafile lseek: %s", |
| 2006 |
strerror(errno)); |
1992 |
strerror(errno)); |
| 2007 |
len = read(deliver_datafile, body, len); |
1993 |
if ((len = read(deliver_datafile, body, len)) > 0) |
| 2008 |
if (len > 0) |
|
|
| 2009 |
{ |
1994 |
{ |
| 2010 |
body[len] = 0; |
1995 |
body[len] = 0; |
| 2011 |
if (message_body_newlines) /* Separate loops for efficiency */ |
1996 |
if (message_body_newlines) /* Separate loops for efficiency */ |
|
Lines 2440-2446
Link Here
|
| 2440 |
|
2425 |
|
| 2441 |
|
2426 |
|
| 2442 |
|
2427 |
|
| 2443 |
#ifdef EXPERIMENTAL_SRS_NATIVE |
2428 |
#ifdef SUPPORT_SRS |
| 2444 |
/* Do an hmac_md5. The result is _not_ nul-terminated, and is sized as |
2429 |
/* Do an hmac_md5. The result is _not_ nul-terminated, and is sized as |
| 2445 |
the smaller of a full hmac_md5 result (16 bytes) or the supplied output buffer. |
2430 |
the smaller of a full hmac_md5 result (16 bytes) or the supplied output buffer. |
| 2446 |
|
2431 |
|
|
Lines 2515-2521
Link Here
|
| 2515 |
} |
2500 |
} |
| 2516 |
return; |
2501 |
return; |
| 2517 |
} |
2502 |
} |
| 2518 |
#endif /*EXPERIMENTAL_SRS_NATIVE*/ |
2503 |
#endif /*SUPPORT_SRS*/ |
| 2519 |
|
2504 |
|
| 2520 |
|
2505 |
|
| 2521 |
/************************************************* |
2506 |
/************************************************* |
|
Lines 2545-2560
Link Here
|
| 2545 |
BOOL *subcondptr; |
2530 |
BOOL *subcondptr; |
| 2546 |
BOOL sub2_honour_dollar = TRUE; |
2531 |
BOOL sub2_honour_dollar = TRUE; |
| 2547 |
BOOL is_forany, is_json, is_jsons; |
2532 |
BOOL is_forany, is_json, is_jsons; |
| 2548 |
int rc, cond_type, roffset; |
2533 |
int rc, cond_type; |
| 2549 |
int_eximarith_t num[2]; |
2534 |
int_eximarith_t num[2]; |
| 2550 |
struct stat statbuf; |
2535 |
struct stat statbuf; |
| 2551 |
uschar * opname; |
2536 |
uschar * opname; |
| 2552 |
uschar name[256]; |
2537 |
uschar name[256]; |
| 2553 |
const uschar *sub[10]; |
2538 |
const uschar *sub[10]; |
| 2554 |
|
2539 |
|
| 2555 |
const pcre *re; |
|
|
| 2556 |
const uschar *rerror; |
| 2557 |
|
| 2558 |
for (;;) |
2540 |
for (;;) |
| 2559 |
if (Uskip_whitespace(&s) == '!') { testfor = !testfor; s++; } else break; |
2541 |
if (Uskip_whitespace(&s) == '!') { testfor = !testfor; s++; } else break; |
| 2560 |
|
2542 |
|
|
Lines 2565-2571
Link Here
|
| 2565 |
|
2547 |
|
| 2566 |
case ECOND_DEF: |
2548 |
case ECOND_DEF: |
| 2567 |
{ |
2549 |
{ |
| 2568 |
uschar * t; |
2550 |
const uschar * t; |
| 2569 |
|
2551 |
|
| 2570 |
if (*s != ':') |
2552 |
if (*s != ':') |
| 2571 |
{ |
2553 |
{ |
|
Lines 2916-3058
Link Here
|
| 2916 |
{ |
2898 |
{ |
| 2917 |
case ECOND_NUM_E: |
2899 |
case ECOND_NUM_E: |
| 2918 |
case ECOND_NUM_EE: |
2900 |
case ECOND_NUM_EE: |
| 2919 |
tempcond = (num[0] == num[1]); |
2901 |
tempcond = (num[0] == num[1]); break; |
| 2920 |
break; |
|
|
| 2921 |
|
2902 |
|
| 2922 |
case ECOND_NUM_G: |
2903 |
case ECOND_NUM_G: |
| 2923 |
tempcond = (num[0] > num[1]); |
2904 |
tempcond = (num[0] > num[1]); break; |
| 2924 |
break; |
|
|
| 2925 |
|
2905 |
|
| 2926 |
case ECOND_NUM_GE: |
2906 |
case ECOND_NUM_GE: |
| 2927 |
tempcond = (num[0] >= num[1]); |
2907 |
tempcond = (num[0] >= num[1]); break; |
| 2928 |
break; |
|
|
| 2929 |
|
2908 |
|
| 2930 |
case ECOND_NUM_L: |
2909 |
case ECOND_NUM_L: |
| 2931 |
tempcond = (num[0] < num[1]); |
2910 |
tempcond = (num[0] < num[1]); break; |
| 2932 |
break; |
|
|
| 2933 |
|
2911 |
|
| 2934 |
case ECOND_NUM_LE: |
2912 |
case ECOND_NUM_LE: |
| 2935 |
tempcond = (num[0] <= num[1]); |
2913 |
tempcond = (num[0] <= num[1]); break; |
| 2936 |
break; |
|
|
| 2937 |
|
2914 |
|
| 2938 |
case ECOND_STR_LT: |
2915 |
case ECOND_STR_LT: |
| 2939 |
tempcond = (Ustrcmp(sub[0], sub[1]) < 0); |
2916 |
tempcond = (Ustrcmp(sub[0], sub[1]) < 0); break; |
| 2940 |
break; |
|
|
| 2941 |
|
2917 |
|
| 2942 |
case ECOND_STR_LTI: |
2918 |
case ECOND_STR_LTI: |
| 2943 |
tempcond = (strcmpic(sub[0], sub[1]) < 0); |
2919 |
tempcond = (strcmpic(sub[0], sub[1]) < 0); break; |
| 2944 |
break; |
|
|
| 2945 |
|
2920 |
|
| 2946 |
case ECOND_STR_LE: |
2921 |
case ECOND_STR_LE: |
| 2947 |
tempcond = (Ustrcmp(sub[0], sub[1]) <= 0); |
2922 |
tempcond = (Ustrcmp(sub[0], sub[1]) <= 0); break; |
| 2948 |
break; |
|
|
| 2949 |
|
2923 |
|
| 2950 |
case ECOND_STR_LEI: |
2924 |
case ECOND_STR_LEI: |
| 2951 |
tempcond = (strcmpic(sub[0], sub[1]) <= 0); |
2925 |
tempcond = (strcmpic(sub[0], sub[1]) <= 0); break; |
| 2952 |
break; |
|
|
| 2953 |
|
2926 |
|
| 2954 |
case ECOND_STR_EQ: |
2927 |
case ECOND_STR_EQ: |
| 2955 |
tempcond = (Ustrcmp(sub[0], sub[1]) == 0); |
2928 |
tempcond = (Ustrcmp(sub[0], sub[1]) == 0); break; |
| 2956 |
break; |
|
|
| 2957 |
|
2929 |
|
| 2958 |
case ECOND_STR_EQI: |
2930 |
case ECOND_STR_EQI: |
| 2959 |
tempcond = (strcmpic(sub[0], sub[1]) == 0); |
2931 |
tempcond = (strcmpic(sub[0], sub[1]) == 0); break; |
| 2960 |
break; |
|
|
| 2961 |
|
2932 |
|
| 2962 |
case ECOND_STR_GT: |
2933 |
case ECOND_STR_GT: |
| 2963 |
tempcond = (Ustrcmp(sub[0], sub[1]) > 0); |
2934 |
tempcond = (Ustrcmp(sub[0], sub[1]) > 0); break; |
| 2964 |
break; |
|
|
| 2965 |
|
2935 |
|
| 2966 |
case ECOND_STR_GTI: |
2936 |
case ECOND_STR_GTI: |
| 2967 |
tempcond = (strcmpic(sub[0], sub[1]) > 0); |
2937 |
tempcond = (strcmpic(sub[0], sub[1]) > 0); break; |
| 2968 |
break; |
|
|
| 2969 |
|
2938 |
|
| 2970 |
case ECOND_STR_GE: |
2939 |
case ECOND_STR_GE: |
| 2971 |
tempcond = (Ustrcmp(sub[0], sub[1]) >= 0); |
2940 |
tempcond = (Ustrcmp(sub[0], sub[1]) >= 0); break; |
| 2972 |
break; |
|
|
| 2973 |
|
2941 |
|
| 2974 |
case ECOND_STR_GEI: |
2942 |
case ECOND_STR_GEI: |
| 2975 |
tempcond = (strcmpic(sub[0], sub[1]) >= 0); |
2943 |
tempcond = (strcmpic(sub[0], sub[1]) >= 0); break; |
| 2976 |
break; |
|
|
| 2977 |
|
2944 |
|
| 2978 |
case ECOND_MATCH: /* Regular expression match */ |
2945 |
case ECOND_MATCH: /* Regular expression match */ |
| 2979 |
if (!(re = pcre_compile(CS sub[1], PCRE_COPT, CCSS &rerror, |
|
|
| 2980 |
&roffset, NULL))) |
| 2981 |
{ |
2946 |
{ |
| 2982 |
expand_string_message = string_sprintf("regular expression error in " |
2947 |
const pcre2_code * re; |
| 2983 |
"\"%s\": %s at offset %d", sub[1], rerror, roffset); |
2948 |
PCRE2_SIZE offset; |
| 2984 |
return NULL; |
2949 |
int err; |
|
|
2950 |
|
| 2951 |
if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED, |
| 2952 |
PCRE_COPT, &err, &offset, pcre_cmp_ctx))) |
| 2953 |
{ |
| 2954 |
uschar errbuf[128]; |
| 2955 |
pcre2_get_error_message(err, errbuf, sizeof(errbuf)); |
| 2956 |
expand_string_message = string_sprintf("regular expression error in " |
| 2957 |
"\"%s\": %s at offset %ld", sub[1], errbuf, (long)offset); |
| 2958 |
return NULL; |
| 2959 |
} |
| 2960 |
|
| 2961 |
tempcond = regex_match_and_setup(re, sub[0], 0, -1); |
| 2962 |
break; |
| 2985 |
} |
2963 |
} |
| 2986 |
tempcond = regex_match_and_setup(re, sub[0], 0, -1); |
|
|
| 2987 |
break; |
| 2988 |
|
2964 |
|
| 2989 |
case ECOND_MATCH_ADDRESS: /* Match in an address list */ |
2965 |
case ECOND_MATCH_ADDRESS: /* Match in an address list */ |
| 2990 |
rc = match_address_list(sub[0], TRUE, FALSE, &(sub[1]), NULL, -1, 0, NULL); |
2966 |
rc = match_address_list(sub[0], TRUE, FALSE, &(sub[1]), NULL, -1, 0, |
| 2991 |
goto MATCHED_SOMETHING; |
2967 |
CUSS &lookup_value); |
|
|
2968 |
goto MATCHED_SOMETHING; |
| 2992 |
|
2969 |
|
| 2993 |
case ECOND_MATCH_DOMAIN: /* Match in a domain list */ |
2970 |
case ECOND_MATCH_DOMAIN: /* Match in a domain list */ |
| 2994 |
rc = match_isinlist(sub[0], &(sub[1]), 0, &domainlist_anchor, NULL, |
2971 |
rc = match_isinlist(sub[0], &(sub[1]), 0, &domainlist_anchor, NULL, |
| 2995 |
MCL_DOMAIN + MCL_NOEXPAND, TRUE, NULL); |
2972 |
MCL_DOMAIN + MCL_NOEXPAND, TRUE, CUSS &lookup_value); |
| 2996 |
goto MATCHED_SOMETHING; |
2973 |
goto MATCHED_SOMETHING; |
| 2997 |
|
2974 |
|
| 2998 |
case ECOND_MATCH_IP: /* Match IP address in a host list */ |
2975 |
case ECOND_MATCH_IP: /* Match IP address in a host list */ |
| 2999 |
if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) == 0) |
2976 |
if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) == 0) |
| 3000 |
{ |
2977 |
{ |
| 3001 |
expand_string_message = string_sprintf("\"%s\" is not an IP address", |
2978 |
expand_string_message = string_sprintf("\"%s\" is not an IP address", |
| 3002 |
sub[0]); |
2979 |
sub[0]); |
| 3003 |
return NULL; |
2980 |
return NULL; |
| 3004 |
} |
2981 |
} |
| 3005 |
else |
2982 |
else |
| 3006 |
{ |
2983 |
{ |
| 3007 |
unsigned int *nullcache = NULL; |
2984 |
unsigned int *nullcache = NULL; |
| 3008 |
check_host_block cb; |
2985 |
check_host_block cb; |
| 3009 |
|
2986 |
|
| 3010 |
cb.host_name = US""; |
2987 |
cb.host_name = US""; |
| 3011 |
cb.host_address = sub[0]; |
2988 |
cb.host_address = sub[0]; |
| 3012 |
|
2989 |
|
| 3013 |
/* If the host address starts off ::ffff: it is an IPv6 address in |
2990 |
/* If the host address starts off ::ffff: it is an IPv6 address in |
| 3014 |
IPv4-compatible mode. Find the IPv4 part for checking against IPv4 |
2991 |
IPv4-compatible mode. Find the IPv4 part for checking against IPv4 |
| 3015 |
addresses. */ |
2992 |
addresses. */ |
| 3016 |
|
2993 |
|
| 3017 |
cb.host_ipv4 = (Ustrncmp(cb.host_address, "::ffff:", 7) == 0)? |
2994 |
cb.host_ipv4 = (Ustrncmp(cb.host_address, "::ffff:", 7) == 0)? |
| 3018 |
cb.host_address + 7 : cb.host_address; |
2995 |
cb.host_address + 7 : cb.host_address; |
| 3019 |
|
2996 |
|
| 3020 |
rc = match_check_list( |
2997 |
rc = match_check_list( |
| 3021 |
&sub[1], /* the list */ |
2998 |
&sub[1], /* the list */ |
| 3022 |
0, /* separator character */ |
2999 |
0, /* separator character */ |
| 3023 |
&hostlist_anchor, /* anchor pointer */ |
3000 |
&hostlist_anchor, /* anchor pointer */ |
| 3024 |
&nullcache, /* cache pointer */ |
3001 |
&nullcache, /* cache pointer */ |
| 3025 |
check_host, /* function for testing */ |
3002 |
check_host, /* function for testing */ |
| 3026 |
&cb, /* argument for function */ |
3003 |
&cb, /* argument for function */ |
| 3027 |
MCL_HOST, /* type of check */ |
3004 |
MCL_HOST, /* type of check */ |
| 3028 |
sub[0], /* text for debugging */ |
3005 |
sub[0], /* text for debugging */ |
| 3029 |
NULL); /* where to pass back data */ |
3006 |
CUSS &lookup_value); /* where to pass back data */ |
| 3030 |
} |
3007 |
} |
| 3031 |
goto MATCHED_SOMETHING; |
3008 |
goto MATCHED_SOMETHING; |
| 3032 |
|
3009 |
|
| 3033 |
case ECOND_MATCH_LOCAL_PART: |
3010 |
case ECOND_MATCH_LOCAL_PART: |
| 3034 |
rc = match_isinlist(sub[0], &(sub[1]), 0, &localpartlist_anchor, NULL, |
3011 |
rc = match_isinlist(sub[0], &(sub[1]), 0, &localpartlist_anchor, NULL, |
| 3035 |
MCL_LOCALPART + MCL_NOEXPAND, TRUE, NULL); |
3012 |
MCL_LOCALPART + MCL_NOEXPAND, TRUE, CUSS &lookup_value); |
| 3036 |
/* Fall through */ |
3013 |
/* Fall through */ |
| 3037 |
/* VVVVVVVVVVVV */ |
3014 |
/* VVVVVVVVVVVV */ |
| 3038 |
MATCHED_SOMETHING: |
3015 |
MATCHED_SOMETHING: |
| 3039 |
switch(rc) |
3016 |
switch(rc) |
| 3040 |
{ |
3017 |
{ |
| 3041 |
case OK: |
3018 |
case OK: tempcond = TRUE; break; |
| 3042 |
tempcond = TRUE; |
3019 |
case FAIL: tempcond = FALSE; break; |
| 3043 |
break; |
|
|
| 3044 |
|
| 3045 |
case FAIL: |
| 3046 |
tempcond = FALSE; |
| 3047 |
break; |
| 3048 |
|
3020 |
|
| 3049 |
case DEFER: |
3021 |
case DEFER: |
| 3050 |
expand_string_message = string_sprintf("unable to complete match " |
3022 |
expand_string_message = string_sprintf("unable to complete match " |
| 3051 |
"against \"%s\": %s", sub[1], search_error_message); |
3023 |
"against \"%s\": %s", sub[1], search_error_message); |
| 3052 |
return NULL; |
3024 |
return NULL; |
| 3053 |
} |
3025 |
} |
| 3054 |
|
3026 |
|
| 3055 |
break; |
3027 |
break; |
| 3056 |
|
3028 |
|
| 3057 |
/* Various "encrypted" comparisons. If the second string starts with |
3029 |
/* Various "encrypted" comparisons. If the second string starts with |
| 3058 |
"{" then an encryption type is given. Default to crypt() or crypt16() |
3030 |
"{" then an encryption type is given. Default to crypt() or crypt16() |
|
Lines 3061-3198
Link Here
|
| 3061 |
|
3033 |
|
| 3062 |
case ECOND_CRYPTEQ: |
3034 |
case ECOND_CRYPTEQ: |
| 3063 |
#ifndef SUPPORT_CRYPTEQ |
3035 |
#ifndef SUPPORT_CRYPTEQ |
| 3064 |
goto COND_FAILED_NOT_COMPILED; |
3036 |
goto COND_FAILED_NOT_COMPILED; |
| 3065 |
#else |
3037 |
#else |
| 3066 |
if (strncmpic(sub[1], US"{md5}", 5) == 0) |
3038 |
if (strncmpic(sub[1], US"{md5}", 5) == 0) |
| 3067 |
{ |
3039 |
{ |
| 3068 |
int sublen = Ustrlen(sub[1]+5); |
3040 |
int sublen = Ustrlen(sub[1]+5); |
| 3069 |
md5 base; |
3041 |
md5 base; |
| 3070 |
uschar digest[16]; |
3042 |
uschar digest[16]; |
| 3071 |
|
3043 |
|
| 3072 |
md5_start(&base); |
3044 |
md5_start(&base); |
| 3073 |
md5_end(&base, sub[0], Ustrlen(sub[0]), digest); |
3045 |
md5_end(&base, sub[0], Ustrlen(sub[0]), digest); |
| 3074 |
|
3046 |
|
| 3075 |
/* If the length that we are comparing against is 24, the MD5 digest |
3047 |
/* If the length that we are comparing against is 24, the MD5 digest |
| 3076 |
is expressed as a base64 string. This is the way LDAP does it. However, |
3048 |
is expressed as a base64 string. This is the way LDAP does it. However, |
| 3077 |
some other software uses a straightforward hex representation. We assume |
3049 |
some other software uses a straightforward hex representation. We assume |
| 3078 |
this if the length is 32. Other lengths fail. */ |
3050 |
this if the length is 32. Other lengths fail. */ |
| 3079 |
|
3051 |
|
| 3080 |
if (sublen == 24) |
3052 |
if (sublen == 24) |
| 3081 |
{ |
3053 |
{ |
| 3082 |
uschar *coded = b64encode(CUS digest, 16); |
3054 |
uschar *coded = b64encode(CUS digest, 16); |
| 3083 |
DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n" |
3055 |
DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n" |
| 3084 |
" subject=%s\n crypted=%s\n", coded, sub[1]+5); |
3056 |
" subject=%s\n crypted=%s\n", coded, sub[1]+5); |
| 3085 |
tempcond = (Ustrcmp(coded, sub[1]+5) == 0); |
3057 |
tempcond = (Ustrcmp(coded, sub[1]+5) == 0); |
| 3086 |
} |
3058 |
} |
| 3087 |
else if (sublen == 32) |
3059 |
else if (sublen == 32) |
| 3088 |
{ |
3060 |
{ |
| 3089 |
uschar coded[36]; |
3061 |
uschar coded[36]; |
| 3090 |
for (int i = 0; i < 16; i++) sprintf(CS (coded+2*i), "%02X", digest[i]); |
3062 |
for (int i = 0; i < 16; i++) sprintf(CS (coded+2*i), "%02X", digest[i]); |
| 3091 |
coded[32] = 0; |
3063 |
coded[32] = 0; |
| 3092 |
DEBUG(D_auth) debug_printf("crypteq: using MD5+hex hashing\n" |
3064 |
DEBUG(D_auth) debug_printf("crypteq: using MD5+hex hashing\n" |
| 3093 |
" subject=%s\n crypted=%s\n", coded, sub[1]+5); |
3065 |
" subject=%s\n crypted=%s\n", coded, sub[1]+5); |
| 3094 |
tempcond = (strcmpic(coded, sub[1]+5) == 0); |
3066 |
tempcond = (strcmpic(coded, sub[1]+5) == 0); |
| 3095 |
} |
3067 |
} |
| 3096 |
else |
3068 |
else |
| 3097 |
{ |
3069 |
{ |
| 3098 |
DEBUG(D_auth) debug_printf("crypteq: length for MD5 not 24 or 32: " |
3070 |
DEBUG(D_auth) debug_printf("crypteq: length for MD5 not 24 or 32: " |
| 3099 |
"fail\n crypted=%s\n", sub[1]+5); |
3071 |
"fail\n crypted=%s\n", sub[1]+5); |
| 3100 |
tempcond = FALSE; |
3072 |
tempcond = FALSE; |
| 3101 |
} |
3073 |
} |
| 3102 |
} |
3074 |
} |
| 3103 |
|
|
|
| 3104 |
else if (strncmpic(sub[1], US"{sha1}", 6) == 0) |
| 3105 |
{ |
| 3106 |
int sublen = Ustrlen(sub[1]+6); |
| 3107 |
hctx h; |
| 3108 |
uschar digest[20]; |
| 3109 |
|
3075 |
|
| 3110 |
sha1_start(&h); |
3076 |
else if (strncmpic(sub[1], US"{sha1}", 6) == 0) |
| 3111 |
sha1_end(&h, sub[0], Ustrlen(sub[0]), digest); |
3077 |
{ |
|
|
3078 |
int sublen = Ustrlen(sub[1]+6); |
| 3079 |
hctx h; |
| 3080 |
uschar digest[20]; |
| 3112 |
|
3081 |
|
| 3113 |
/* If the length that we are comparing against is 28, assume the SHA1 |
3082 |
sha1_start(&h); |
| 3114 |
digest is expressed as a base64 string. If the length is 40, assume a |
3083 |
sha1_end(&h, sub[0], Ustrlen(sub[0]), digest); |
| 3115 |
straightforward hex representation. Other lengths fail. */ |
|
|
| 3116 |
|
3084 |
|
| 3117 |
if (sublen == 28) |
3085 |
/* If the length that we are comparing against is 28, assume the SHA1 |
| 3118 |
{ |
3086 |
digest is expressed as a base64 string. If the length is 40, assume a |
| 3119 |
uschar *coded = b64encode(CUS digest, 20); |
3087 |
straightforward hex representation. Other lengths fail. */ |
| 3120 |
DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n" |
3088 |
|
| 3121 |
" subject=%s\n crypted=%s\n", coded, sub[1]+6); |
3089 |
if (sublen == 28) |
| 3122 |
tempcond = (Ustrcmp(coded, sub[1]+6) == 0); |
3090 |
{ |
| 3123 |
} |
3091 |
uschar *coded = b64encode(CUS digest, 20); |
| 3124 |
else if (sublen == 40) |
3092 |
DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n" |
| 3125 |
{ |
3093 |
" subject=%s\n crypted=%s\n", coded, sub[1]+6); |
| 3126 |
uschar coded[44]; |
3094 |
tempcond = (Ustrcmp(coded, sub[1]+6) == 0); |
| 3127 |
for (int i = 0; i < 20; i++) sprintf(CS (coded+2*i), "%02X", digest[i]); |
3095 |
} |
| 3128 |
coded[40] = 0; |
3096 |
else if (sublen == 40) |
| 3129 |
DEBUG(D_auth) debug_printf("crypteq: using SHA1+hex hashing\n" |
3097 |
{ |
| 3130 |
" subject=%s\n crypted=%s\n", coded, sub[1]+6); |
3098 |
uschar coded[44]; |
| 3131 |
tempcond = (strcmpic(coded, sub[1]+6) == 0); |
3099 |
for (int i = 0; i < 20; i++) sprintf(CS (coded+2*i), "%02X", digest[i]); |
| 3132 |
} |
3100 |
coded[40] = 0; |
| 3133 |
else |
3101 |
DEBUG(D_auth) debug_printf("crypteq: using SHA1+hex hashing\n" |
| 3134 |
{ |
3102 |
" subject=%s\n crypted=%s\n", coded, sub[1]+6); |
| 3135 |
DEBUG(D_auth) debug_printf("crypteq: length for SHA-1 not 28 or 40: " |
3103 |
tempcond = (strcmpic(coded, sub[1]+6) == 0); |
| 3136 |
"fail\n crypted=%s\n", sub[1]+6); |
3104 |
} |
| 3137 |
tempcond = FALSE; |
3105 |
else |
| 3138 |
} |
3106 |
{ |
| 3139 |
} |
3107 |
DEBUG(D_auth) debug_printf("crypteq: length for SHA-1 not 28 or 40: " |
|
|
3108 |
"fail\n crypted=%s\n", sub[1]+6); |
| 3109 |
tempcond = FALSE; |
| 3110 |
} |
| 3111 |
} |
| 3140 |
|
3112 |
|
| 3141 |
else /* {crypt} or {crypt16} and non-{ at start */ |
3113 |
else /* {crypt} or {crypt16} and non-{ at start */ |
| 3142 |
/* }-for-text-editors */ |
3114 |
/* }-for-text-editors */ |
| 3143 |
{ |
3115 |
{ |
| 3144 |
int which = 0; |
3116 |
int which = 0; |
| 3145 |
uschar *coded; |
3117 |
uschar *coded; |
| 3146 |
|
3118 |
|
| 3147 |
if (strncmpic(sub[1], US"{crypt}", 7) == 0) |
3119 |
if (strncmpic(sub[1], US"{crypt}", 7) == 0) |
| 3148 |
{ |
3120 |
{ |
| 3149 |
sub[1] += 7; |
3121 |
sub[1] += 7; |
| 3150 |
which = 1; |
3122 |
which = 1; |
| 3151 |
} |
3123 |
} |
| 3152 |
else if (strncmpic(sub[1], US"{crypt16}", 9) == 0) |
3124 |
else if (strncmpic(sub[1], US"{crypt16}", 9) == 0) |
| 3153 |
{ |
3125 |
{ |
| 3154 |
sub[1] += 9; |
3126 |
sub[1] += 9; |
| 3155 |
which = 2; |
3127 |
which = 2; |
| 3156 |
} |
3128 |
} |
| 3157 |
else if (sub[1][0] == '{') /* }-for-text-editors */ |
3129 |
else if (sub[1][0] == '{') /* }-for-text-editors */ |
| 3158 |
{ |
3130 |
{ |
| 3159 |
expand_string_message = string_sprintf("unknown encryption mechanism " |
3131 |
expand_string_message = string_sprintf("unknown encryption mechanism " |
| 3160 |
"in \"%s\"", sub[1]); |
3132 |
"in \"%s\"", sub[1]); |
| 3161 |
return NULL; |
3133 |
return NULL; |
| 3162 |
} |
3134 |
} |
| 3163 |
|
3135 |
|
| 3164 |
switch(which) |
3136 |
switch(which) |
| 3165 |
{ |
3137 |
{ |
| 3166 |
case 0: coded = US DEFAULT_CRYPT(CS sub[0], CS sub[1]); break; |
3138 |
case 0: coded = US DEFAULT_CRYPT(CS sub[0], CS sub[1]); break; |
| 3167 |
case 1: coded = US crypt(CS sub[0], CS sub[1]); break; |
3139 |
case 1: coded = US crypt(CS sub[0], CS sub[1]); break; |
| 3168 |
default: coded = US crypt16(CS sub[0], CS sub[1]); break; |
3140 |
default: coded = US crypt16(CS sub[0], CS sub[1]); break; |
| 3169 |
} |
3141 |
} |
| 3170 |
|
3142 |
|
| 3171 |
#define STR(s) # s |
3143 |
#define STR(s) # s |
| 3172 |
#define XSTR(s) STR(s) |
3144 |
#define XSTR(s) STR(s) |
| 3173 |
DEBUG(D_auth) debug_printf("crypteq: using %s()\n" |
3145 |
DEBUG(D_auth) debug_printf("crypteq: using %s()\n" |
| 3174 |
" subject=%s\n crypted=%s\n", |
3146 |
" subject=%s\n crypted=%s\n", |
| 3175 |
which == 0 ? XSTR(DEFAULT_CRYPT) : which == 1 ? "crypt" : "crypt16", |
3147 |
which == 0 ? XSTR(DEFAULT_CRYPT) : which == 1 ? "crypt" : "crypt16", |
| 3176 |
coded, sub[1]); |
3148 |
coded, sub[1]); |
| 3177 |
#undef STR |
3149 |
#undef STR |
| 3178 |
#undef XSTR |
3150 |
#undef XSTR |
| 3179 |
|
3151 |
|
| 3180 |
/* If the encrypted string contains fewer than two characters (for the |
3152 |
/* If the encrypted string contains fewer than two characters (for the |
| 3181 |
salt), force failure. Otherwise we get false positives: with an empty |
3153 |
salt), force failure. Otherwise we get false positives: with an empty |
| 3182 |
string the yield of crypt() is an empty string! */ |
3154 |
string the yield of crypt() is an empty string! */ |
| 3183 |
|
3155 |
|
| 3184 |
if (coded) |
3156 |
if (coded) |
| 3185 |
tempcond = Ustrlen(sub[1]) < 2 ? FALSE : Ustrcmp(coded, sub[1]) == 0; |
3157 |
tempcond = Ustrlen(sub[1]) < 2 ? FALSE : Ustrcmp(coded, sub[1]) == 0; |
| 3186 |
else if (errno == EINVAL) |
3158 |
else if (errno == EINVAL) |
| 3187 |
tempcond = FALSE; |
3159 |
tempcond = FALSE; |
| 3188 |
else |
3160 |
else |
| 3189 |
{ |
3161 |
{ |
| 3190 |
expand_string_message = string_sprintf("crypt error: %s\n", |
3162 |
expand_string_message = string_sprintf("crypt error: %s\n", |
| 3191 |
US strerror(errno)); |
3163 |
US strerror(errno)); |
| 3192 |
return NULL; |
3164 |
return NULL; |
|
|
3165 |
} |
| 3193 |
} |
3166 |
} |
| 3194 |
} |
3167 |
break; |
| 3195 |
break; |
|
|
| 3196 |
#endif /* SUPPORT_CRYPTEQ */ |
3168 |
#endif /* SUPPORT_CRYPTEQ */ |
| 3197 |
|
3169 |
|
| 3198 |
case ECOND_INLIST: |
3170 |
case ECOND_INLIST: |
|
Lines 3215-3220
Link Here
|
| 3215 |
if (compare(sub[0], iterate_item) == 0) |
3187 |
if (compare(sub[0], iterate_item) == 0) |
| 3216 |
{ |
3188 |
{ |
| 3217 |
tempcond = TRUE; |
3189 |
tempcond = TRUE; |
|
|
3190 |
lookup_value = iterate_item; |
| 3218 |
break; |
3191 |
break; |
| 3219 |
} |
3192 |
} |
| 3220 |
} |
3193 |
} |
|
Lines 3445-3458
Link Here
|
| 3445 |
return s; |
3418 |
return s; |
| 3446 |
} |
3419 |
} |
| 3447 |
|
3420 |
|
| 3448 |
#ifdef EXPERIMENTAL_SRS_NATIVE |
3421 |
#ifdef SUPPORT_SRS |
| 3449 |
case ECOND_INBOUND_SRS: |
3422 |
case ECOND_INBOUND_SRS: |
| 3450 |
/* ${if inbound_srs {local_part}{secret} {yes}{no}} */ |
3423 |
/* ${if inbound_srs {local_part}{secret} {yes}{no}} */ |
| 3451 |
{ |
3424 |
{ |
| 3452 |
uschar * sub[2]; |
3425 |
uschar * sub[2]; |
| 3453 |
const pcre * re; |
3426 |
const pcre2_code * re; |
| 3454 |
int ovec[3*(4+1)]; |
3427 |
pcre2_match_data * md; |
| 3455 |
int n; |
3428 |
PCRE2_SIZE * ovec; |
|
|
3429 |
int quoting = 0; |
| 3456 |
uschar cksum[4]; |
3430 |
uschar cksum[4]; |
| 3457 |
BOOL boolvalue = FALSE; |
3431 |
BOOL boolvalue = FALSE; |
| 3458 |
|
3432 |
|
|
Lines 3468-3485
Link Here
|
| 3468 |
|
3442 |
|
| 3469 |
re = regex_must_compile(US"^(?i)SRS0=([^=]+)=([A-Z2-7]+)=([^=]*)=(.*)$", |
3443 |
re = regex_must_compile(US"^(?i)SRS0=([^=]+)=([A-Z2-7]+)=([^=]*)=(.*)$", |
| 3470 |
TRUE, FALSE); |
3444 |
TRUE, FALSE); |
| 3471 |
if (pcre_exec(re, NULL, CS sub[0], Ustrlen(sub[0]), 0, PCRE_EOPT, |
3445 |
md = pcre2_match_data_create(4+1, pcre_gen_ctx); |
| 3472 |
ovec, nelem(ovec)) < 0) |
3446 |
if (pcre2_match(re, sub[0], PCRE2_ZERO_TERMINATED, 0, PCRE_EOPT, |
|
|
3447 |
md, pcre_mtc_ctx) < 0) |
| 3473 |
{ |
3448 |
{ |
| 3474 |
DEBUG(D_expand) debug_printf("no match for SRS'd local-part pattern\n"); |
3449 |
DEBUG(D_expand) debug_printf("no match for SRS'd local-part pattern\n"); |
| 3475 |
goto srs_result; |
3450 |
goto srs_result; |
| 3476 |
} |
3451 |
} |
|
|
3452 |
ovec = pcre2_get_ovector_pointer(md); |
| 3477 |
|
3453 |
|
| 3478 |
/* Side-effect: record the decoded recipient */ |
3454 |
if (sub[0][0] == '"') |
| 3479 |
|
3455 |
quoting = 1; |
| 3480 |
srs_recipient = string_sprintf("%.*S@%.*S", /* lowercased */ |
3456 |
else for (uschar * s = sub[0]; *s; s++) |
| 3481 |
ovec[9]-ovec[8], sub[0] + ovec[8], /* substring 4 */ |
3457 |
if (!isalnum(*s) && Ustrchr(".!#$%&'*+-/=?^_`{|}~", *s) == NULL) |
| 3482 |
ovec[7]-ovec[6], sub[0] + ovec[6]); /* substring 3 */ |
3458 |
{ quoting = 1; break; } |
|
|
3459 |
if (quoting) |
| 3460 |
DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n"); |
| 3461 |
|
| 3462 |
/* Record the (quoted, if needed) decoded recipient as $srs_recipient */ |
| 3463 |
|
| 3464 |
srs_recipient = string_sprintf("%.*s%.*S%.*s@%.*S", /* lowercased */ |
| 3465 |
quoting, "\"", |
| 3466 |
(int) (ovec[9]-ovec[8]), sub[0] + ovec[8], /* substr 4 */ |
| 3467 |
quoting, "\"", |
| 3468 |
(int) (ovec[7]-ovec[6]), sub[0] + ovec[6]); /* substr 3 */ |
| 3483 |
|
3469 |
|
| 3484 |
/* If a zero-length secret was given, we're done. Otherwise carry on |
3470 |
/* If a zero-length secret was given, we're done. Otherwise carry on |
| 3485 |
and validate the given SRS local_part againt our secret. */ |
3471 |
and validate the given SRS local_part againt our secret. */ |
|
Lines 3495-3500
Link Here
|
| 3495 |
struct timeval now; |
3481 |
struct timeval now; |
| 3496 |
uschar * ss = sub[0] + ovec[4]; /* substring 2, the timestamp */ |
3482 |
uschar * ss = sub[0] + ovec[4]; /* substring 2, the timestamp */ |
| 3497 |
long d; |
3483 |
long d; |
|
|
3484 |
int n; |
| 3498 |
|
3485 |
|
| 3499 |
gettimeofday(&now, NULL); |
3486 |
gettimeofday(&now, NULL); |
| 3500 |
now.tv_sec /= 86400; /* days since epoch */ |
3487 |
now.tv_sec /= 86400; /* days since epoch */ |
|
Lines 3537-3543
Link Here
|
| 3537 |
if (yield) *yield = (boolvalue == testfor); |
3524 |
if (yield) *yield = (boolvalue == testfor); |
| 3538 |
return s; |
3525 |
return s; |
| 3539 |
} |
3526 |
} |
| 3540 |
#endif /*EXPERIMENTAL_SRS_NATIVE*/ |
3527 |
#endif /*SUPPORT_SRS*/ |
| 3541 |
|
3528 |
|
| 3542 |
/* Unknown condition */ |
3529 |
/* Unknown condition */ |
| 3543 |
|
3530 |
|
|
Lines 3588-3594
Link Here
|
| 3588 |
*/ |
3575 |
*/ |
| 3589 |
|
3576 |
|
| 3590 |
static int |
3577 |
static int |
| 3591 |
save_expand_strings(uschar **save_expand_nstring, int *save_expand_nlength) |
3578 |
save_expand_strings(const uschar **save_expand_nstring, int *save_expand_nlength) |
| 3592 |
{ |
3579 |
{ |
| 3593 |
for (int i = 0; i <= expand_nmax; i++) |
3580 |
for (int i = 0; i <= expand_nmax; i++) |
| 3594 |
{ |
3581 |
{ |
|
Lines 3615-3621
Link Here
|
| 3615 |
*/ |
3602 |
*/ |
| 3616 |
|
3603 |
|
| 3617 |
static void |
3604 |
static void |
| 3618 |
restore_expand_strings(int save_expand_nmax, uschar **save_expand_nstring, |
3605 |
restore_expand_strings(int save_expand_nmax, const uschar **save_expand_nstring, |
| 3619 |
int *save_expand_nlength) |
3606 |
int *save_expand_nlength) |
| 3620 |
{ |
3607 |
{ |
| 3621 |
expand_nmax = save_expand_nmax; |
3608 |
expand_nmax = save_expand_nmax; |
|
Lines 3829-3836
Link Here
|
| 3829 |
static uschar * |
3816 |
static uschar * |
| 3830 |
prvs_daystamp(int day_offset) |
3817 |
prvs_daystamp(int day_offset) |
| 3831 |
{ |
3818 |
{ |
| 3832 |
uschar *days = store_get(32, FALSE); /* Need at least 24 for cases */ |
3819 |
uschar * days = store_get(32, GET_UNTAINTED); /* Need at least 24 for cases */ |
| 3833 |
(void)string_format(days, 32, TIME_T_FMT, /* where TIME_T_FMT is %lld */ |
3820 |
(void)string_format(days, 32, TIME_T_FMT, /* where TIME_T_FMT is %lld */ |
| 3834 |
(time(NULL) + day_offset*86400)/86400); |
3821 |
(time(NULL) + day_offset*86400)/86400); |
| 3835 |
return (Ustrlen(days) >= 3) ? &days[Ustrlen(days)-3] : US"100"; |
3822 |
return (Ustrlen(days) >= 3) ? &days[Ustrlen(days)-3] : US"100"; |
| 3836 |
} |
3823 |
} |
|
Lines 3901-3907
Link Here
|
| 3901 |
|
3888 |
|
| 3902 |
/* Hashing is deemed sufficient to de-taint any input data */ |
3889 |
/* Hashing is deemed sufficient to de-taint any input data */ |
| 3903 |
|
3890 |
|
| 3904 |
p = finalhash_hex = store_get(40, FALSE); |
3891 |
p = finalhash_hex = store_get(40, GET_UNTAINTED); |
| 3905 |
for (int i = 0; i < 3; i++) |
3892 |
for (int i = 0; i < 3; i++) |
| 3906 |
{ |
3893 |
{ |
| 3907 |
*p++ = hex_digits[(finalhash[i] & 0xf0) >> 4]; |
3894 |
*p++ = hex_digits[(finalhash[i] & 0xf0) >> 4]; |
|
Lines 3932-3938
Link Here
|
| 3932 |
*/ |
3919 |
*/ |
| 3933 |
|
3920 |
|
| 3934 |
gstring * |
3921 |
gstring * |
| 3935 |
cat_file(FILE *f, gstring *yield, uschar *eol) |
3922 |
cat_file(FILE * f, gstring * yield, uschar * eol) |
| 3936 |
{ |
3923 |
{ |
| 3937 |
uschar buffer[1024]; |
3924 |
uschar buffer[1024]; |
| 3938 |
|
3925 |
|
|
Lines 3944-3951
Link Here
|
| 3944 |
if (eol && buffer[len]) |
3931 |
if (eol && buffer[len]) |
| 3945 |
yield = string_cat(yield, eol); |
3932 |
yield = string_cat(yield, eol); |
| 3946 |
} |
3933 |
} |
| 3947 |
|
|
|
| 3948 |
(void) string_from_gstring(yield); |
| 3949 |
return yield; |
3934 |
return yield; |
| 3950 |
} |
3935 |
} |
| 3951 |
|
3936 |
|
|
Lines 3967-3973
Link Here
|
| 3967 |
/* We assume that all errors, and any returns of zero bytes, |
3952 |
/* We assume that all errors, and any returns of zero bytes, |
| 3968 |
are actually EOF. */ |
3953 |
are actually EOF. */ |
| 3969 |
|
3954 |
|
| 3970 |
(void) string_from_gstring(yield); |
|
|
| 3971 |
return yield; |
3955 |
return yield; |
| 3972 |
} |
3956 |
} |
| 3973 |
#endif |
3957 |
#endif |
|
Lines 4293-4298
Link Here
|
| 4293 |
} |
4277 |
} |
| 4294 |
|
4278 |
|
| 4295 |
|
4279 |
|
|
|
4280 |
/* Expand a named list. Return false on failure. */ |
| 4281 |
static gstring * |
| 4282 |
expand_listnamed(gstring * yield, const uschar * name, const uschar * listtype) |
| 4283 |
{ |
| 4284 |
tree_node *t = NULL; |
| 4285 |
const uschar * list; |
| 4286 |
int sep = 0; |
| 4287 |
uschar * item; |
| 4288 |
BOOL needsep = FALSE; |
| 4289 |
#define LISTNAMED_BUF_SIZE 256 |
| 4290 |
uschar b[LISTNAMED_BUF_SIZE]; |
| 4291 |
uschar * buffer = b; |
| 4292 |
|
| 4293 |
if (*name == '+') name++; |
| 4294 |
if (!listtype) /* no-argument version */ |
| 4295 |
{ |
| 4296 |
if ( !(t = tree_search(addresslist_anchor, name)) |
| 4297 |
&& !(t = tree_search(domainlist_anchor, name)) |
| 4298 |
&& !(t = tree_search(hostlist_anchor, name))) |
| 4299 |
t = tree_search(localpartlist_anchor, name); |
| 4300 |
} |
| 4301 |
else switch(*listtype) /* specific list-type version */ |
| 4302 |
{ |
| 4303 |
case 'a': t = tree_search(addresslist_anchor, name); break; |
| 4304 |
case 'd': t = tree_search(domainlist_anchor, name); break; |
| 4305 |
case 'h': t = tree_search(hostlist_anchor, name); break; |
| 4306 |
case 'l': t = tree_search(localpartlist_anchor, name); break; |
| 4307 |
default: |
| 4308 |
expand_string_message = US"bad suffix on \"list\" operator"; |
| 4309 |
return yield; |
| 4310 |
} |
| 4311 |
|
| 4312 |
if(!t) |
| 4313 |
{ |
| 4314 |
expand_string_message = string_sprintf("\"%s\" is not a %snamed list", |
| 4315 |
name, !listtype?"" |
| 4316 |
: *listtype=='a'?"address " |
| 4317 |
: *listtype=='d'?"domain " |
| 4318 |
: *listtype=='h'?"host " |
| 4319 |
: *listtype=='l'?"localpart " |
| 4320 |
: 0); |
| 4321 |
return yield; |
| 4322 |
} |
| 4323 |
|
| 4324 |
list = ((namedlist_block *)(t->data.ptr))->string; |
| 4325 |
|
| 4326 |
/* The list could be quite long so we (re)use a buffer for each element |
| 4327 |
rather than getting each in new memory */ |
| 4328 |
|
| 4329 |
if (is_tainted(list)) buffer = store_get(LISTNAMED_BUF_SIZE, GET_TAINTED); |
| 4330 |
while ((item = string_nextinlist(&list, &sep, buffer, LISTNAMED_BUF_SIZE))) |
| 4331 |
{ |
| 4332 |
uschar * buf = US" : "; |
| 4333 |
if (needsep) |
| 4334 |
yield = string_catn(yield, buf, 3); |
| 4335 |
else |
| 4336 |
needsep = TRUE; |
| 4337 |
|
| 4338 |
if (*item == '+') /* list item is itself a named list */ |
| 4339 |
{ |
| 4340 |
yield = expand_listnamed(yield, item, listtype); |
| 4341 |
if (expand_string_message) |
| 4342 |
return yield; |
| 4343 |
} |
| 4344 |
|
| 4345 |
else if (sep != ':') /* item from non-colon-sep list, re-quote for colon list-separator */ |
| 4346 |
{ |
| 4347 |
char tok[3]; |
| 4348 |
tok[0] = sep; tok[1] = ':'; tok[2] = 0; |
| 4349 |
|
| 4350 |
for(char * cp; cp = strpbrk(CCS item, tok); item = US cp) |
| 4351 |
{ |
| 4352 |
yield = string_catn(yield, item, cp - CS item); |
| 4353 |
if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */ |
| 4354 |
yield = string_catn(yield, US"::", 2); |
| 4355 |
else /* sep in item; should already be doubled; emit once */ |
| 4356 |
{ |
| 4357 |
yield = string_catn(yield, US tok, 1); |
| 4358 |
if (*cp == sep) cp++; |
| 4359 |
} |
| 4360 |
} |
| 4361 |
yield = string_cat(yield, item); |
| 4362 |
} |
| 4363 |
else |
| 4364 |
yield = string_cat(yield, item); |
| 4365 |
} |
| 4366 |
return yield; |
| 4367 |
} |
| 4368 |
|
| 4369 |
|
| 4370 |
|
| 4371 |
/************************************************/ |
| 4372 |
static void |
| 4373 |
debug_expansion_interim(const uschar * what, const uschar * value, int nchar, |
| 4374 |
BOOL skipping) |
| 4375 |
{ |
| 4376 |
DEBUG(D_noutf8) |
| 4377 |
debug_printf_indent("|"); |
| 4378 |
else |
| 4379 |
debug_printf_indent(UTF8_VERT_RIGHT); |
| 4380 |
|
| 4381 |
for (int fill = 11 - Ustrlen(what); fill > 0; fill--) |
| 4382 |
DEBUG(D_noutf8) |
| 4383 |
debug_printf("-"); |
| 4384 |
else |
| 4385 |
debug_printf(UTF8_HORIZ); |
| 4386 |
|
| 4387 |
debug_printf("%s: %.*s\n", what, nchar, value); |
| 4388 |
if (is_tainted(value)) |
| 4389 |
{ |
| 4390 |
DEBUG(D_noutf8) |
| 4391 |
debug_printf_indent("%s \\__", skipping ? "| " : " "); |
| 4392 |
else |
| 4393 |
debug_printf_indent("%s", |
| 4394 |
skipping |
| 4395 |
? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ); |
| 4396 |
debug_printf("(tainted)\n"); |
| 4397 |
} |
| 4398 |
} |
| 4399 |
|
| 4400 |
|
| 4296 |
/************************************************* |
4401 |
/************************************************* |
| 4297 |
* Expand string * |
4402 |
* Expand string * |
| 4298 |
*************************************************/ |
4403 |
*************************************************/ |
|
Lines 4363-4385
Link Here
|
| 4363 |
rmark reset_point = store_mark(); |
4468 |
rmark reset_point = store_mark(); |
| 4364 |
gstring * yield = string_get(Ustrlen(string) + 64); |
4469 |
gstring * yield = string_get(Ustrlen(string) + 64); |
| 4365 |
int item_type; |
4470 |
int item_type; |
| 4366 |
const uschar *s = string; |
4471 |
const uschar * s = string; |
| 4367 |
uschar *save_expand_nstring[EXPAND_MAXN+1]; |
4472 |
const uschar * save_expand_nstring[EXPAND_MAXN+1]; |
| 4368 |
int save_expand_nlength[EXPAND_MAXN+1]; |
4473 |
int save_expand_nlength[EXPAND_MAXN+1]; |
| 4369 |
BOOL resetok = TRUE; |
4474 |
BOOL resetok = TRUE, first = TRUE; |
| 4370 |
|
4475 |
|
| 4371 |
expand_level++; |
4476 |
expand_level++; |
| 4372 |
DEBUG(D_expand) |
|
|
| 4373 |
DEBUG(D_noutf8) |
| 4374 |
debug_printf_indent("/%s: %s\n", |
| 4375 |
skipping ? "---scanning" : "considering", string); |
| 4376 |
else |
| 4377 |
debug_printf_indent(UTF8_DOWN_RIGHT "%s: %s\n", |
| 4378 |
skipping |
| 4379 |
? UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ "scanning" |
| 4380 |
: "considering", |
| 4381 |
string); |
| 4382 |
|
| 4383 |
f.expand_string_forcedfail = FALSE; |
4477 |
f.expand_string_forcedfail = FALSE; |
| 4384 |
expand_string_message = US""; |
4478 |
expand_string_message = US""; |
| 4385 |
|
4479 |
|
|
Lines 4391-4401
Link Here
|
| 4391 |
goto EXPAND_FAILED; |
4485 |
goto EXPAND_FAILED; |
| 4392 |
} |
4486 |
} |
| 4393 |
|
4487 |
|
| 4394 |
while (*s != 0) |
4488 |
while (*s) |
| 4395 |
{ |
4489 |
{ |
| 4396 |
uschar *value; |
|
|
| 4397 |
uschar name[256]; |
4490 |
uschar name[256]; |
| 4398 |
|
4491 |
|
|
|
4492 |
DEBUG(D_expand) |
| 4493 |
{ |
| 4494 |
DEBUG(D_noutf8) |
| 4495 |
debug_printf_indent("%c%s: %s\n", |
| 4496 |
first ? '/' : '|', |
| 4497 |
skipping ? "---scanning" : "considering", s); |
| 4498 |
else |
| 4499 |
debug_printf_indent("%s%s: %s\n", |
| 4500 |
first ? UTF8_DOWN_RIGHT : UTF8_VERT_RIGHT, |
| 4501 |
skipping |
| 4502 |
? UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ "scanning" |
| 4503 |
: "considering", |
| 4504 |
s); |
| 4505 |
first = FALSE; |
| 4506 |
} |
| 4507 |
|
| 4399 |
/* \ escapes the next character, which must exist, or else |
4508 |
/* \ escapes the next character, which must exist, or else |
| 4400 |
the expansion fails. There's a special escape, \N, which causes |
4509 |
the expansion fails. There's a special escape, \N, which causes |
| 4401 |
copying of the subject verbatim up to the next \N. Otherwise, |
4510 |
copying of the subject verbatim up to the next \N. Otherwise, |
|
Lines 4412-4443
Link Here
|
| 4412 |
if (s[1] == 'N') |
4521 |
if (s[1] == 'N') |
| 4413 |
{ |
4522 |
{ |
| 4414 |
const uschar * t = s + 2; |
4523 |
const uschar * t = s + 2; |
| 4415 |
for (s = t; *s != 0; s++) if (*s == '\\' && s[1] == 'N') break; |
4524 |
for (s = t; *s ; s++) if (*s == '\\' && s[1] == 'N') break; |
|
|
4525 |
|
| 4526 |
DEBUG(D_expand) |
| 4527 |
debug_expansion_interim(US"protected", t, (int)(s - t), skipping); |
| 4416 |
yield = string_catn(yield, t, s - t); |
4528 |
yield = string_catn(yield, t, s - t); |
| 4417 |
if (*s != 0) s += 2; |
4529 |
if (*s) s += 2; |
| 4418 |
} |
4530 |
} |
| 4419 |
|
|
|
| 4420 |
else |
4531 |
else |
| 4421 |
{ |
4532 |
{ |
| 4422 |
uschar ch[1]; |
4533 |
uschar ch[1]; |
|
|
4534 |
DEBUG(D_expand) |
| 4535 |
DEBUG(D_noutf8) |
| 4536 |
debug_printf_indent("|backslashed: '\\%c'\n", s[1]); |
| 4537 |
else |
| 4538 |
debug_printf_indent(UTF8_VERT_RIGHT "backslashed: '\\%c'\n", s[1]); |
| 4423 |
ch[0] = string_interpret_escape(&s); |
4539 |
ch[0] = string_interpret_escape(&s); |
| 4424 |
s++; |
4540 |
s++; |
| 4425 |
yield = string_catn(yield, ch, 1); |
4541 |
yield = string_catn(yield, ch, 1); |
| 4426 |
} |
4542 |
} |
| 4427 |
|
|
|
| 4428 |
continue; |
4543 |
continue; |
| 4429 |
} |
4544 |
} |
| 4430 |
|
4545 |
|
| 4431 |
/*{*/ |
4546 |
/*{{*/ |
| 4432 |
/* Anything other than $ is just copied verbatim, unless we are |
4547 |
/* Anything other than $ is just copied verbatim, unless we are |
| 4433 |
looking for a terminating } character. */ |
4548 |
looking for a terminating } character. */ |
| 4434 |
|
4549 |
|
| 4435 |
/*{*/ |
|
|
| 4436 |
if (ket_ends && *s == '}') break; |
4550 |
if (ket_ends && *s == '}') break; |
| 4437 |
|
4551 |
|
| 4438 |
if (*s != '$' || !honour_dollar) |
4552 |
if (*s != '$' || !honour_dollar) |
| 4439 |
{ |
4553 |
{ |
| 4440 |
yield = string_catn(yield, s++, 1); |
4554 |
int i = 1; /*{*/ |
|
|
4555 |
for (const uschar * t = s+1; |
| 4556 |
*t && *t != '$' && *t != '}' && *t != '\\'; t++) i++; |
| 4557 |
|
| 4558 |
DEBUG(D_expand) debug_expansion_interim(US"text", s, i, skipping); |
| 4559 |
|
| 4560 |
yield = string_catn(yield, s, i); |
| 4561 |
s += i; |
| 4441 |
continue; |
4562 |
continue; |
| 4442 |
} |
4563 |
} |
| 4443 |
|
4564 |
|
|
Lines 4449-4458
Link Here
|
| 4449 |
"$header_". A non-existent header yields a NULL value; nothing is |
4570 |
"$header_". A non-existent header yields a NULL value; nothing is |
| 4450 |
inserted. */ /*}*/ |
4571 |
inserted. */ /*}*/ |
| 4451 |
|
4572 |
|
| 4452 |
if (isalpha((*(++s)))) |
4573 |
if (isalpha(*++s)) |
| 4453 |
{ |
4574 |
{ |
| 4454 |
int len; |
4575 |
const uschar * value; |
| 4455 |
int newsize = 0; |
4576 |
int newsize = 0, len; |
| 4456 |
gstring * g = NULL; |
4577 |
gstring * g = NULL; |
| 4457 |
uschar * t; |
4578 |
uschar * t; |
| 4458 |
|
4579 |
|
|
Lines 4462-4474
Link Here
|
| 4462 |
buffer. */ |
4583 |
buffer. */ |
| 4463 |
|
4584 |
|
| 4464 |
if (!yield) |
4585 |
if (!yield) |
| 4465 |
g = store_get(sizeof(gstring), FALSE); |
4586 |
g = store_get(sizeof(gstring), GET_UNTAINTED); |
| 4466 |
else if (yield->ptr == 0) |
4587 |
else if (yield->ptr == 0) |
| 4467 |
{ |
4588 |
{ |
| 4468 |
if (resetok) reset_point = store_reset(reset_point); |
4589 |
if (resetok) reset_point = store_reset(reset_point); |
| 4469 |
yield = NULL; |
4590 |
yield = NULL; |
| 4470 |
reset_point = store_mark(); |
4591 |
reset_point = store_mark(); |
| 4471 |
g = store_get(sizeof(gstring), FALSE); /* alloc _before_ calling find_variable() */ |
4592 |
g = store_get(sizeof(gstring), GET_UNTAINTED); /* alloc _before_ calling find_variable() */ |
| 4472 |
} |
4593 |
} |
| 4473 |
|
4594 |
|
| 4474 |
/* Header */ |
4595 |
/* Header */ |
|
Lines 4482-4488
Link Here
|
| 4482 |
unsigned flags = *name == 'r' ? FH_WANT_RAW |
4603 |
unsigned flags = *name == 'r' ? FH_WANT_RAW |
| 4483 |
: *name == 'l' ? FH_WANT_RAW|FH_WANT_LIST |
4604 |
: *name == 'l' ? FH_WANT_RAW|FH_WANT_LIST |
| 4484 |
: 0; |
4605 |
: 0; |
| 4485 |
uschar * charset = *name == 'b' ? NULL : headers_charset; |
4606 |
const uschar * charset = *name == 'b' ? NULL : headers_charset; |
| 4486 |
|
4607 |
|
| 4487 |
s = read_header_name(name, sizeof(name), s); |
4608 |
s = read_header_name(name, sizeof(name), s); |
| 4488 |
value = find_header(name, &newsize, flags, charset); |
4609 |
value = find_header(name, &newsize, flags, charset); |
|
Lines 4493-4499
Link Here
|
| 4493 |
But there is no error here - nothing gets inserted. */ |
4614 |
But there is no error here - nothing gets inserted. */ |
| 4494 |
|
4615 |
|
| 4495 |
if (!value) |
4616 |
if (!value) |
| 4496 |
{ |
4617 |
{ /*{*/ |
| 4497 |
if (Ustrchr(name, '}')) malformed_header = TRUE; |
4618 |
if (Ustrchr(name, '}')) malformed_header = TRUE; |
| 4498 |
continue; |
4619 |
continue; |
| 4499 |
} |
4620 |
} |
|
Lines 4523-4529
Link Here
|
| 4523 |
yield = g; |
4644 |
yield = g; |
| 4524 |
yield->size = newsize; |
4645 |
yield->size = newsize; |
| 4525 |
yield->ptr = len; |
4646 |
yield->ptr = len; |
| 4526 |
yield->s = value; |
4647 |
yield->s = US value; /* known to be in new store i.e. a copy, so deconst safe */ |
| 4527 |
} |
4648 |
} |
| 4528 |
else |
4649 |
else |
| 4529 |
yield = string_catn(yield, value, len); |
4650 |
yield = string_catn(yield, value, len); |
|
Lines 4549-4562
Link Here
|
| 4549 |
} |
4670 |
} |
| 4550 |
|
4671 |
|
| 4551 |
/* After { there can be various things, but they all start with |
4672 |
/* After { there can be various things, but they all start with |
| 4552 |
an initial word, except for a number for a string match variable. */ |
4673 |
an initial word, except for a number for a string match variable. */ /*}*/ |
| 4553 |
|
4674 |
|
| 4554 |
if (isdigit((*(++s)))) |
4675 |
if (isdigit(*++s)) |
| 4555 |
{ |
4676 |
{ |
| 4556 |
int n; |
4677 |
int n; |
| 4557 |
s = read_cnumber(&n, s); /*{*/ |
4678 |
s = read_cnumber(&n, s); /*{{*/ |
| 4558 |
if (*s++ != '}') |
4679 |
if (*s++ != '}') |
| 4559 |
{ /*{*/ |
4680 |
{ |
| 4560 |
expand_string_message = US"} expected after number"; |
4681 |
expand_string_message = US"} expected after number"; |
| 4561 |
goto EXPAND_FAILED; |
4682 |
goto EXPAND_FAILED; |
| 4562 |
} |
4683 |
} |
|
Lines 4573-4583
Link Here
|
| 4573 |
|
4694 |
|
| 4574 |
/* Allow "-" in names to cater for substrings with negative |
4695 |
/* Allow "-" in names to cater for substrings with negative |
| 4575 |
arguments. Since we are checking for known names after { this is |
4696 |
arguments. Since we are checking for known names after { this is |
| 4576 |
OK. */ |
4697 |
OK. */ /*}*/ |
| 4577 |
|
4698 |
|
| 4578 |
s = read_name(name, sizeof(name), s, US"_-"); |
4699 |
s = read_name(name, sizeof(name), s, US"_-"); |
| 4579 |
item_type = chop_match(name, item_table, nelem(item_table)); |
4700 |
item_type = chop_match(name, item_table, nelem(item_table)); |
| 4580 |
|
4701 |
|
|
|
4702 |
/* Switch on item type. All nondefault choices should "continue* when |
| 4703 |
skipping, but "break" otherwise so we get debug output for the item |
| 4704 |
expansion. */ |
| 4705 |
{ |
| 4706 |
int start = gstring_length(yield); |
| 4581 |
switch(item_type) |
4707 |
switch(item_type) |
| 4582 |
{ |
4708 |
{ |
| 4583 |
/* Call an ACL from an expansion. We feed data in via $acl_arg1 - $acl_arg9. |
4709 |
/* Call an ACL from an expansion. We feed data in via $acl_arg1 - $acl_arg9. |
|
Lines 4592-4599
Link Here
|
| 4592 |
case EITEM_ACL: |
4718 |
case EITEM_ACL: |
| 4593 |
/* ${acl {name} {arg1}{arg2}...} */ |
4719 |
/* ${acl {name} {arg1}{arg2}...} */ |
| 4594 |
{ |
4720 |
{ |
| 4595 |
uschar *sub[10]; /* name + arg1-arg9 (which must match number of acl_arg[]) */ |
4721 |
uschar * sub[10]; /* name + arg1-arg9 (which must match number of acl_arg[]) */ |
| 4596 |
uschar *user_msg; |
4722 |
uschar * user_msg; |
| 4597 |
int rc; |
4723 |
int rc; |
| 4598 |
|
4724 |
|
| 4599 |
switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, name, |
4725 |
switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, name, |
|
Lines 4614-4620
Link Here
|
| 4614 |
debug_printf_indent("acl expansion yield: %s\n", user_msg); |
4740 |
debug_printf_indent("acl expansion yield: %s\n", user_msg); |
| 4615 |
if (user_msg) |
4741 |
if (user_msg) |
| 4616 |
yield = string_cat(yield, user_msg); |
4742 |
yield = string_cat(yield, user_msg); |
| 4617 |
continue; |
4743 |
break; |
| 4618 |
|
4744 |
|
| 4619 |
case DEFER: |
4745 |
case DEFER: |
| 4620 |
f.expand_string_forcedfail = TRUE; |
4746 |
f.expand_string_forcedfail = TRUE; |
|
Lines 4624-4635
Link Here
|
| 4624 |
rc_names[rc], sub[0]); |
4750 |
rc_names[rc], sub[0]); |
| 4625 |
goto EXPAND_FAILED; |
4751 |
goto EXPAND_FAILED; |
| 4626 |
} |
4752 |
} |
|
|
4753 |
break; |
| 4627 |
} |
4754 |
} |
| 4628 |
|
4755 |
|
| 4629 |
case EITEM_AUTHRESULTS: |
4756 |
case EITEM_AUTHRESULTS: |
| 4630 |
/* ${authresults {mysystemname}} */ |
4757 |
/* ${authresults {mysystemname}} */ |
| 4631 |
{ |
4758 |
{ |
| 4632 |
uschar *sub_arg[1]; |
4759 |
uschar * sub_arg[1]; |
| 4633 |
|
4760 |
|
| 4634 |
switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, skipping, TRUE, name, |
4761 |
switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, skipping, TRUE, name, |
| 4635 |
&resetok)) |
4762 |
&resetok)) |
|
Lines 4658-4664
Link Here
|
| 4658 |
#ifdef EXPERIMENTAL_ARC |
4785 |
#ifdef EXPERIMENTAL_ARC |
| 4659 |
yield = authres_arc(yield); |
4786 |
yield = authres_arc(yield); |
| 4660 |
#endif |
4787 |
#endif |
| 4661 |
continue; |
4788 |
break; |
| 4662 |
} |
4789 |
} |
| 4663 |
|
4790 |
|
| 4664 |
/* Handle conditionals - preserve the values of the numerical expansion |
4791 |
/* Handle conditionals - preserve the values of the numerical expansion |
|
Lines 4672-4698
Link Here
|
| 4672 |
const uschar *next_s; |
4799 |
const uschar *next_s; |
| 4673 |
int save_expand_nmax = |
4800 |
int save_expand_nmax = |
| 4674 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
4801 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
|
|
4802 |
uschar * save_lookup_value = lookup_value; |
| 4675 |
|
4803 |
|
| 4676 |
Uskip_whitespace(&s); |
4804 |
Uskip_whitespace(&s); |
| 4677 |
if (!(next_s = eval_condition(s, &resetok, skipping ? NULL : &cond))) |
4805 |
if (!(next_s = eval_condition(s, &resetok, skipping ? NULL : &cond))) |
| 4678 |
goto EXPAND_FAILED; /* message already set */ |
4806 |
goto EXPAND_FAILED; /* message already set */ |
| 4679 |
|
4807 |
|
| 4680 |
DEBUG(D_expand) |
4808 |
DEBUG(D_expand) |
| 4681 |
DEBUG(D_noutf8) |
4809 |
{ |
| 4682 |
{ |
4810 |
debug_expansion_interim(US"condition", s, (int)(next_s - s), skipping); |
| 4683 |
debug_printf_indent("|--condition: %.*s\n", (int)(next_s - s), s); |
4811 |
debug_expansion_interim(US"result", |
| 4684 |
debug_printf_indent("|-----result: %s\n", cond ? "true" : "false"); |
4812 |
cond ? US"true" : US"false", cond ? 4 : 5, skipping); |
| 4685 |
} |
4813 |
} |
| 4686 |
else |
|
|
| 4687 |
{ |
| 4688 |
debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ |
| 4689 |
"condition: %.*s\n", |
| 4690 |
(int)(next_s - s), s); |
| 4691 |
debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ |
| 4692 |
UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ |
| 4693 |
"result: %s\n", |
| 4694 |
cond ? "true" : "false"); |
| 4695 |
} |
| 4696 |
|
4814 |
|
| 4697 |
s = next_s; |
4815 |
s = next_s; |
| 4698 |
|
4816 |
|
|
Lines 4715-4728
Link Here
|
| 4715 |
/* Restore external setting of expansion variables for continuation |
4833 |
/* Restore external setting of expansion variables for continuation |
| 4716 |
at this level. */ |
4834 |
at this level. */ |
| 4717 |
|
4835 |
|
|
|
4836 |
lookup_value = save_lookup_value; |
| 4718 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
4837 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
| 4719 |
save_expand_nlength); |
4838 |
save_expand_nlength); |
| 4720 |
continue; |
4839 |
break; |
| 4721 |
} |
4840 |
} |
| 4722 |
|
4841 |
|
| 4723 |
#ifdef SUPPORT_I18N |
4842 |
#ifdef SUPPORT_I18N |
| 4724 |
case EITEM_IMAPFOLDER: |
4843 |
case EITEM_IMAPFOLDER: |
| 4725 |
{ /* ${imapfolder {name}{sep]{specials}} */ |
4844 |
{ /* ${imapfolder {name}{sep}{specials}} */ |
| 4726 |
uschar *sub_arg[3]; |
4845 |
uschar *sub_arg[3]; |
| 4727 |
uschar *encoded; |
4846 |
uschar *encoded; |
| 4728 |
|
4847 |
|
|
Lines 4748-4761
Link Here
|
| 4748 |
goto EXPAND_FAILED; |
4867 |
goto EXPAND_FAILED; |
| 4749 |
} |
4868 |
} |
| 4750 |
|
4869 |
|
| 4751 |
if (!skipping) |
4870 |
if (skipping) continue; |
| 4752 |
{ |
4871 |
|
| 4753 |
if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset, |
4872 |
if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset, |
| 4754 |
sub_arg[1][0], sub_arg[2], &expand_string_message))) |
4873 |
sub_arg[1][0], sub_arg[2], &expand_string_message))) |
| 4755 |
goto EXPAND_FAILED; |
4874 |
goto EXPAND_FAILED; |
| 4756 |
yield = string_cat(yield, encoded); |
4875 |
yield = string_cat(yield, encoded); |
| 4757 |
} |
4876 |
break; |
| 4758 |
continue; |
|
|
| 4759 |
} |
4877 |
} |
| 4760 |
#endif |
4878 |
#endif |
| 4761 |
|
4879 |
|
|
Lines 4771-4783
Link Here
|
| 4771 |
int stype, partial, affixlen, starflags; |
4889 |
int stype, partial, affixlen, starflags; |
| 4772 |
int expand_setup = 0; |
4890 |
int expand_setup = 0; |
| 4773 |
int nameptr = 0; |
4891 |
int nameptr = 0; |
| 4774 |
uschar *key, *filename; |
4892 |
uschar * key, * filename; |
| 4775 |
const uschar * affix, * opts; |
4893 |
const uschar * affix, * opts; |
| 4776 |
uschar *save_lookup_value = lookup_value; |
4894 |
uschar * save_lookup_value = lookup_value; |
| 4777 |
int save_expand_nmax = |
4895 |
int save_expand_nmax = |
| 4778 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
4896 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
| 4779 |
|
4897 |
|
| 4780 |
if ((expand_forbid & RDO_LOOKUP) != 0) |
4898 |
if (expand_forbid & RDO_LOOKUP) |
| 4781 |
{ |
4899 |
{ |
| 4782 |
expand_string_message = US"lookup expansions are not permitted"; |
4900 |
expand_string_message = US"lookup expansions are not permitted"; |
| 4783 |
goto EXPAND_FAILED; |
4901 |
goto EXPAND_FAILED; |
|
Lines 4841-4855
Link Here
|
| 4841 |
goto EXPAND_FAILED; |
4959 |
goto EXPAND_FAILED; |
| 4842 |
} |
4960 |
} |
| 4843 |
} |
4961 |
} |
| 4844 |
else |
4962 |
else if (key) |
| 4845 |
{ |
4963 |
{ |
| 4846 |
if (key) |
4964 |
expand_string_message = string_sprintf("a single key was given for " |
| 4847 |
{ |
4965 |
"lookup type \"%s\", which is not a single-key lookup type", name); |
| 4848 |
expand_string_message = string_sprintf("a single key was given for " |
4966 |
goto EXPAND_FAILED; |
| 4849 |
"lookup type \"%s\", which is not a single-key lookup type", name); |
4967 |
} |
| 4850 |
goto EXPAND_FAILED; |
|
|
| 4851 |
} |
| 4852 |
} |
| 4853 |
|
4968 |
|
| 4854 |
/* Get the next string in brackets and expand it. It is the file name for |
4969 |
/* Get the next string in brackets and expand it. It is the file name for |
| 4855 |
single-key+file lookups, and the whole query otherwise. In the case of |
4970 |
single-key+file lookups, and the whole query otherwise. In the case of |
|
Lines 4859-4868
Link Here
|
| 4859 |
if (*s != '{') |
4974 |
if (*s != '{') |
| 4860 |
{ |
4975 |
{ |
| 4861 |
expand_string_message = US"missing '{' for lookup file-or-query arg"; |
4976 |
expand_string_message = US"missing '{' for lookup file-or-query arg"; |
| 4862 |
goto EXPAND_FAILED_CURLY; |
4977 |
goto EXPAND_FAILED_CURLY; /*}}*/ |
| 4863 |
} |
4978 |
} |
| 4864 |
if (!(filename = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))) |
4979 |
if (!(filename = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))) |
| 4865 |
goto EXPAND_FAILED; |
4980 |
goto EXPAND_FAILED; |
|
|
4981 |
/*{{*/ |
| 4866 |
if (*s++ != '}') |
4982 |
if (*s++ != '}') |
| 4867 |
{ |
4983 |
{ |
| 4868 |
expand_string_message = US"missing '}' closing lookup file-or-query arg"; |
4984 |
expand_string_message = US"missing '}' closing lookup file-or-query arg"; |
|
Lines 4876-4896
Link Here
|
| 4876 |
file types, the query (i.e. "key") starts with a file name. */ |
4992 |
file types, the query (i.e. "key") starts with a file name. */ |
| 4877 |
|
4993 |
|
| 4878 |
if (!key) |
4994 |
if (!key) |
| 4879 |
{ |
4995 |
key = search_args(stype, name, filename, &filename, opts); |
| 4880 |
Uskip_whitespace(&filename); |
|
|
| 4881 |
key = filename; |
| 4882 |
|
| 4883 |
if (mac_islookup(stype, lookup_querystyle)) |
| 4884 |
filename = NULL; |
| 4885 |
else |
| 4886 |
if (*filename == '/') |
| 4887 |
{ |
| 4888 |
while (*key && !isspace(*key)) key++; |
| 4889 |
if (*key) *key++ = '\0'; |
| 4890 |
} |
| 4891 |
else |
| 4892 |
filename = NULL; |
| 4893 |
} |
| 4894 |
|
4996 |
|
| 4895 |
/* If skipping, don't do the next bit - just lookup_value == NULL, as if |
4997 |
/* If skipping, don't do the next bit - just lookup_value == NULL, as if |
| 4896 |
the entry was not found. Note that there is no search_close() function. |
4998 |
the entry was not found. Note that there is no search_close() function. |
|
Lines 4909-4915
Link Here
|
| 4909 |
lookup_value = NULL; |
5011 |
lookup_value = NULL; |
| 4910 |
else |
5012 |
else |
| 4911 |
{ |
5013 |
{ |
| 4912 |
void *handle = search_open(filename, stype, 0, NULL, NULL); |
5014 |
void * handle = search_open(filename, stype, 0, NULL, NULL); |
| 4913 |
if (!handle) |
5015 |
if (!handle) |
| 4914 |
{ |
5016 |
{ |
| 4915 |
expand_string_message = search_error_message; |
5017 |
expand_string_message = search_error_message; |
|
Lines 4948-4954
Link Here
|
| 4948 |
|
5050 |
|
| 4949 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
5051 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
| 4950 |
save_expand_nlength); |
5052 |
save_expand_nlength); |
| 4951 |
continue; |
5053 |
|
|
|
5054 |
if (skipping) continue; |
| 5055 |
break; |
| 4952 |
} |
5056 |
} |
| 4953 |
|
5057 |
|
| 4954 |
/* If Perl support is configured, handle calling embedded perl subroutines, |
5058 |
/* If Perl support is configured, handle calling embedded perl subroutines, |
|
Lines 4956-4975
Link Here
|
| 4956 |
or ${perl{sub}{arg1}{arg2}} or up to a maximum of EXIM_PERL_MAX_ARGS |
5060 |
or ${perl{sub}{arg1}{arg2}} or up to a maximum of EXIM_PERL_MAX_ARGS |
| 4957 |
arguments (defined below). */ |
5061 |
arguments (defined below). */ |
| 4958 |
|
5062 |
|
| 4959 |
#define EXIM_PERL_MAX_ARGS 8 |
5063 |
#define EXIM_PERL_MAX_ARGS 8 |
| 4960 |
|
5064 |
|
| 4961 |
case EITEM_PERL: |
5065 |
case EITEM_PERL: |
| 4962 |
#ifndef EXIM_PERL |
5066 |
#ifndef EXIM_PERL |
| 4963 |
expand_string_message = US"\"${perl\" encountered, but this facility " /*}*/ |
5067 |
expand_string_message = US"\"${perl\" encountered, but this facility " /*}*/ |
| 4964 |
"is not included in this binary"; |
5068 |
"is not included in this binary"; |
| 4965 |
goto EXPAND_FAILED; |
5069 |
goto EXPAND_FAILED; |
| 4966 |
|
5070 |
|
| 4967 |
#else /* EXIM_PERL */ |
5071 |
#else /* EXIM_PERL */ |
| 4968 |
{ |
5072 |
{ |
| 4969 |
uschar *sub_arg[EXIM_PERL_MAX_ARGS + 2]; |
5073 |
uschar * sub_arg[EXIM_PERL_MAX_ARGS + 2]; |
| 4970 |
gstring *new_yield; |
5074 |
gstring * new_yield; |
| 4971 |
|
5075 |
|
| 4972 |
if ((expand_forbid & RDO_PERL) != 0) |
5076 |
if (expand_forbid & RDO_PERL) |
| 4973 |
{ |
5077 |
{ |
| 4974 |
expand_string_message = US"Perl calls are not permitted"; |
5078 |
expand_string_message = US"Perl calls are not permitted"; |
| 4975 |
goto EXPAND_FAILED; |
5079 |
goto EXPAND_FAILED; |
|
Lines 4991-4997
Link Here
|
| 4991 |
|
5095 |
|
| 4992 |
if (!opt_perl_started) |
5096 |
if (!opt_perl_started) |
| 4993 |
{ |
5097 |
{ |
| 4994 |
uschar *initerror; |
5098 |
uschar * initerror; |
| 4995 |
if (!opt_perl_startup) |
5099 |
if (!opt_perl_startup) |
| 4996 |
{ |
5100 |
{ |
| 4997 |
expand_string_message = US"A setting of perl_startup is needed when " |
5101 |
expand_string_message = US"A setting of perl_startup is needed when " |
|
Lines 5035-5051
Link Here
|
| 5035 |
|
5139 |
|
| 5036 |
f.expand_string_forcedfail = FALSE; |
5140 |
f.expand_string_forcedfail = FALSE; |
| 5037 |
yield = new_yield; |
5141 |
yield = new_yield; |
| 5038 |
continue; |
5142 |
break; |
| 5039 |
} |
5143 |
} |
| 5040 |
#endif /* EXIM_PERL */ |
5144 |
#endif /* EXIM_PERL */ |
| 5041 |
|
5145 |
|
| 5042 |
/* Transform email address to "prvs" scheme to use |
5146 |
/* Transform email address to "prvs" scheme to use |
| 5043 |
as BATV-signed return path */ |
5147 |
as BATV-signed return path */ |
| 5044 |
|
5148 |
|
| 5045 |
case EITEM_PRVS: |
5149 |
case EITEM_PRVS: |
| 5046 |
{ |
5150 |
{ |
| 5047 |
uschar *sub_arg[3]; |
5151 |
uschar * sub_arg[3], * p, * domain; |
| 5048 |
uschar *p,*domain; |
|
|
| 5049 |
|
5152 |
|
| 5050 |
switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok)) |
5153 |
switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok)) |
| 5051 |
{ |
5154 |
{ |
|
Lines 5094-5110
Link Here
|
| 5094 |
yield = string_catn(yield, US"@", 1); |
5197 |
yield = string_catn(yield, US"@", 1); |
| 5095 |
yield = string_cat (yield, domain); |
5198 |
yield = string_cat (yield, domain); |
| 5096 |
|
5199 |
|
| 5097 |
continue; |
5200 |
break; |
| 5098 |
} |
5201 |
} |
| 5099 |
|
5202 |
|
| 5100 |
/* Check a prvs-encoded address for validity */ |
5203 |
/* Check a prvs-encoded address for validity */ |
| 5101 |
|
5204 |
|
| 5102 |
case EITEM_PRVSCHECK: |
5205 |
case EITEM_PRVSCHECK: |
| 5103 |
{ |
5206 |
{ |
| 5104 |
uschar *sub_arg[3]; |
5207 |
uschar * sub_arg[3], * p; |
| 5105 |
gstring * g; |
5208 |
gstring * g; |
| 5106 |
const pcre *re; |
5209 |
const pcre2_code * re; |
| 5107 |
uschar *p; |
|
|
| 5108 |
|
5210 |
|
| 5109 |
/* TF: Ugliness: We want to expand parameter 1 first, then set |
5211 |
/* TF: Ugliness: We want to expand parameter 1 first, then set |
| 5110 |
up expansion variables that are used in the expansion of |
5212 |
up expansion variables that are used in the expansion of |
|
Lines 5114-5120
Link Here
|
| 5114 |
PH: Actually, that isn't necessary. The read_subs() function is |
5216 |
PH: Actually, that isn't necessary. The read_subs() function is |
| 5115 |
designed to work this way for the ${if and ${lookup expansions. I've |
5217 |
designed to work this way for the ${if and ${lookup expansions. I've |
| 5116 |
tidied the code. |
5218 |
tidied the code. |
| 5117 |
*/ |
5219 |
*/ /*}}*/ |
| 5118 |
|
5220 |
|
| 5119 |
/* Reset expansion variables */ |
5221 |
/* Reset expansion variables */ |
| 5120 |
prvscheck_result = NULL; |
5222 |
prvscheck_result = NULL; |
|
Lines 5133-5143
Link Here
|
| 5133 |
|
5235 |
|
| 5134 |
if (regex_match_and_setup(re,sub_arg[0],0,-1)) |
5236 |
if (regex_match_and_setup(re,sub_arg[0],0,-1)) |
| 5135 |
{ |
5237 |
{ |
| 5136 |
uschar *local_part = string_copyn(expand_nstring[4],expand_nlength[4]); |
5238 |
uschar * local_part = string_copyn(expand_nstring[4],expand_nlength[4]); |
| 5137 |
uschar *key_num = string_copyn(expand_nstring[1],expand_nlength[1]); |
5239 |
uschar * key_num = string_copyn(expand_nstring[1],expand_nlength[1]); |
| 5138 |
uschar *daystamp = string_copyn(expand_nstring[2],expand_nlength[2]); |
5240 |
uschar * daystamp = string_copyn(expand_nstring[2],expand_nlength[2]); |
| 5139 |
uschar *hash = string_copyn(expand_nstring[3],expand_nlength[3]); |
5241 |
uschar * hash = string_copyn(expand_nstring[3],expand_nlength[3]); |
| 5140 |
uschar *domain = string_copyn(expand_nstring[5],expand_nlength[5]); |
5242 |
uschar * domain = string_copyn(expand_nstring[5],expand_nlength[5]); |
| 5141 |
|
5243 |
|
| 5142 |
DEBUG(D_expand) debug_printf_indent("prvscheck localpart: %s\n", local_part); |
5244 |
DEBUG(D_expand) debug_printf_indent("prvscheck localpart: %s\n", local_part); |
| 5143 |
DEBUG(D_expand) debug_printf_indent("prvscheck key number: %s\n", key_num); |
5245 |
DEBUG(D_expand) debug_printf_indent("prvscheck key number: %s\n", key_num); |
|
Lines 5235-5249
Link Here
|
| 5235 |
case 3: goto EXPAND_FAILED; |
5337 |
case 3: goto EXPAND_FAILED; |
| 5236 |
} |
5338 |
} |
| 5237 |
|
5339 |
|
| 5238 |
continue; |
5340 |
if (skipping) continue; |
|
|
5341 |
break; |
| 5239 |
} |
5342 |
} |
| 5240 |
|
5343 |
|
| 5241 |
/* Handle "readfile" to insert an entire file */ |
5344 |
/* Handle "readfile" to insert an entire file */ |
| 5242 |
|
5345 |
|
| 5243 |
case EITEM_READFILE: |
5346 |
case EITEM_READFILE: |
| 5244 |
{ |
5347 |
{ |
| 5245 |
FILE *f; |
5348 |
FILE * f; |
| 5246 |
uschar *sub_arg[2]; |
5349 |
uschar * sub_arg[2]; |
| 5247 |
|
5350 |
|
| 5248 |
if ((expand_forbid & RDO_READFILE) != 0) |
5351 |
if ((expand_forbid & RDO_READFILE) != 0) |
| 5249 |
{ |
5352 |
{ |
|
Lines 5266-5278
Link Here
|
| 5266 |
|
5369 |
|
| 5267 |
if (!(f = Ufopen(sub_arg[0], "rb"))) |
5370 |
if (!(f = Ufopen(sub_arg[0], "rb"))) |
| 5268 |
{ |
5371 |
{ |
| 5269 |
expand_string_message = string_open_failed(errno, "%s", sub_arg[0]); |
5372 |
expand_string_message = string_open_failed("%s", sub_arg[0]); |
| 5270 |
goto EXPAND_FAILED; |
5373 |
goto EXPAND_FAILED; |
| 5271 |
} |
5374 |
} |
| 5272 |
|
5375 |
|
| 5273 |
yield = cat_file(f, yield, sub_arg[1]); |
5376 |
yield = cat_file(f, yield, sub_arg[1]); |
| 5274 |
(void)fclose(f); |
5377 |
(void)fclose(f); |
| 5275 |
continue; |
5378 |
break; |
| 5276 |
} |
5379 |
} |
| 5277 |
|
5380 |
|
| 5278 |
/* Handle "readsocket" to insert data from a socket, either |
5381 |
/* Handle "readsocket" to insert data from a socket, either |
|
Lines 5378-5415
Link Here
|
| 5378 |
/* The whole thing has worked (or we were skipping). If there is a |
5481 |
/* The whole thing has worked (or we were skipping). If there is a |
| 5379 |
failure string following, we need to skip it. */ |
5482 |
failure string following, we need to skip it. */ |
| 5380 |
|
5483 |
|
| 5381 |
if (*s == '{') |
5484 |
if (*s == '{') /*}*/ |
| 5382 |
{ |
5485 |
{ |
| 5383 |
if (!expand_string_internal(s+1, TRUE, &s, TRUE, TRUE, &resetok)) |
5486 |
if (!expand_string_internal(s+1, TRUE, &s, TRUE, TRUE, &resetok)) |
| 5384 |
goto EXPAND_FAILED; |
5487 |
goto EXPAND_FAILED; /*{*/ |
| 5385 |
if (*s++ != '}') |
5488 |
if (*s++ != '}') |
| 5386 |
{ |
5489 |
{ /*{*/ |
| 5387 |
expand_string_message = US"missing '}' closing failstring for readsocket"; |
5490 |
expand_string_message = US"missing '}' closing failstring for readsocket"; |
| 5388 |
goto EXPAND_FAILED_CURLY; |
5491 |
goto EXPAND_FAILED_CURLY; |
| 5389 |
} |
5492 |
} |
| 5390 |
Uskip_whitespace(&s); |
5493 |
Uskip_whitespace(&s); |
| 5391 |
} |
5494 |
} |
| 5392 |
|
5495 |
|
| 5393 |
READSOCK_DONE: |
5496 |
READSOCK_DONE: /*{*/ |
| 5394 |
if (*s++ != '}') |
5497 |
if (*s++ != '}') |
| 5395 |
{ |
5498 |
{ /*{*/ |
| 5396 |
expand_string_message = US"missing '}' closing readsocket"; |
5499 |
expand_string_message = US"missing '}' closing readsocket"; |
| 5397 |
goto EXPAND_FAILED_CURLY; |
5500 |
goto EXPAND_FAILED_CURLY; |
| 5398 |
} |
5501 |
} |
| 5399 |
continue; |
5502 |
if (skipping) continue; |
|
|
5503 |
break; |
| 5400 |
|
5504 |
|
| 5401 |
/* Come here on failure to create socket, connect socket, write to the |
5505 |
/* Come here on failure to create socket, connect socket, write to the |
| 5402 |
socket, or timeout on reading. If another substring follows, expand and |
5506 |
socket, or timeout on reading. If another substring follows, expand and |
| 5403 |
use it. Otherwise, those conditions give expand errors. */ |
5507 |
use it. Otherwise, those conditions give expand errors. */ |
| 5404 |
|
5508 |
|
| 5405 |
SOCK_FAIL: |
5509 |
SOCK_FAIL: |
| 5406 |
if (*s != '{') goto EXPAND_FAILED; |
5510 |
if (*s != '{') goto EXPAND_FAILED; /*}*/ |
| 5407 |
DEBUG(D_any) debug_printf("%s\n", expand_string_message); |
5511 |
DEBUG(D_any) debug_printf("%s\n", expand_string_message); |
| 5408 |
if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok))) |
5512 |
if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok))) |
| 5409 |
goto EXPAND_FAILED; |
5513 |
goto EXPAND_FAILED; |
| 5410 |
yield = string_cat(yield, arg); |
5514 |
yield = string_cat(yield, arg); /*{*/ |
| 5411 |
if (*s++ != '}') |
5515 |
if (*s++ != '}') |
| 5412 |
{ |
5516 |
{ /*{*/ |
| 5413 |
expand_string_message = US"missing '}' closing failstring for readsocket"; |
5517 |
expand_string_message = US"missing '}' closing failstring for readsocket"; |
| 5414 |
goto EXPAND_FAILED_CURLY; |
5518 |
goto EXPAND_FAILED_CURLY; |
| 5415 |
} |
5519 |
} |
|
Lines 5421-5431
Link Here
|
| 5421 |
|
5525 |
|
| 5422 |
case EITEM_RUN: |
5526 |
case EITEM_RUN: |
| 5423 |
{ |
5527 |
{ |
| 5424 |
FILE *f; |
5528 |
FILE * f; |
| 5425 |
uschar *arg; |
5529 |
const uschar * arg, ** argv; |
| 5426 |
const uschar **argv; |
5530 |
BOOL late_expand = TRUE; |
| 5427 |
pid_t pid; |
|
|
| 5428 |
int fd_in, fd_out; |
| 5429 |
|
5531 |
|
| 5430 |
if ((expand_forbid & RDO_RUN) != 0) |
5532 |
if ((expand_forbid & RDO_RUN) != 0) |
| 5431 |
{ |
5533 |
{ |
|
Lines 5433-5449
Link Here
|
| 5433 |
goto EXPAND_FAILED; |
5535 |
goto EXPAND_FAILED; |
| 5434 |
} |
5536 |
} |
| 5435 |
|
5537 |
|
|
|
5538 |
/* Handle options to the "run" */ |
| 5539 |
|
| 5540 |
while (*s == ',') |
| 5541 |
{ |
| 5542 |
if (Ustrncmp(++s, "preexpand", 9) == 0) |
| 5543 |
{ late_expand = FALSE; s += 9; } |
| 5544 |
else |
| 5545 |
{ |
| 5546 |
const uschar * t = s; |
| 5547 |
while (isalpha(*++t)) ; |
| 5548 |
expand_string_message = string_sprintf("bad option '%.*s' for run", |
| 5549 |
(int)(t-s), s); |
| 5550 |
goto EXPAND_FAILED; |
| 5551 |
} |
| 5552 |
} |
| 5436 |
Uskip_whitespace(&s); |
5553 |
Uskip_whitespace(&s); |
| 5437 |
if (*s != '{') |
5554 |
|
|
|
5555 |
if (*s != '{') /*}*/ |
| 5438 |
{ |
5556 |
{ |
| 5439 |
expand_string_message = US"missing '{' for command arg of run"; |
5557 |
expand_string_message = US"missing '{' for command arg of run"; |
| 5440 |
goto EXPAND_FAILED_CURLY; |
5558 |
goto EXPAND_FAILED_CURLY; /*"}*/ |
| 5441 |
} |
5559 |
} |
| 5442 |
if (!(arg = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))) |
5560 |
s++; |
| 5443 |
goto EXPAND_FAILED; |
5561 |
|
| 5444 |
Uskip_whitespace(&s); |
5562 |
if (late_expand) /* this is the default case */ |
|
|
5563 |
{ |
| 5564 |
int n = Ustrcspn(s, "}"); |
| 5565 |
arg = skipping ? NULL : string_copyn(s, n); |
| 5566 |
s += n; |
| 5567 |
} |
| 5568 |
else |
| 5569 |
{ |
| 5570 |
if (!(arg = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok))) |
| 5571 |
goto EXPAND_FAILED; |
| 5572 |
Uskip_whitespace(&s); |
| 5573 |
} |
| 5574 |
/*{*/ |
| 5445 |
if (*s++ != '}') |
5575 |
if (*s++ != '}') |
| 5446 |
{ |
5576 |
{ /*{*/ |
| 5447 |
expand_string_message = US"missing '}' closing command arg of run"; |
5577 |
expand_string_message = US"missing '}' closing command arg of run"; |
| 5448 |
goto EXPAND_FAILED_CURLY; |
5578 |
goto EXPAND_FAILED_CURLY; |
| 5449 |
} |
5579 |
} |
|
Lines 5455-5467
Link Here
|
| 5455 |
} |
5585 |
} |
| 5456 |
else |
5586 |
else |
| 5457 |
{ |
5587 |
{ |
|
|
5588 |
int fd_in, fd_out; |
| 5589 |
pid_t pid; |
| 5590 |
|
| 5458 |
if (!transport_set_up_command(&argv, /* anchor for arg list */ |
5591 |
if (!transport_set_up_command(&argv, /* anchor for arg list */ |
| 5459 |
arg, /* raw command */ |
5592 |
arg, /* raw command */ |
| 5460 |
FALSE, /* don't expand the arguments */ |
5593 |
late_expand, /* expand args if not already done */ |
| 5461 |
0, /* not relevant when... */ |
5594 |
0, /* not relevant when... */ |
| 5462 |
NULL, /* no transporting address */ |
5595 |
NULL, /* no transporting address */ |
| 5463 |
US"${run} expansion", /* for error messages */ |
5596 |
late_expand, /* allow tainted args, when expand-after-split */ |
| 5464 |
&expand_string_message)) /* where to put error message */ |
5597 |
US"${run} expansion", /* for error messages */ |
|
|
5598 |
&expand_string_message)) /* where to put error message */ |
| 5465 |
goto EXPAND_FAILED; |
5599 |
goto EXPAND_FAILED; |
| 5466 |
|
5600 |
|
| 5467 |
/* Create the child process, making it a group leader. */ |
5601 |
/* Create the child process, making it a group leader. */ |
|
Lines 5472-5478
Link Here
|
| 5472 |
expand_string_message = |
5606 |
expand_string_message = |
| 5473 |
string_sprintf("couldn't create child process: %s", strerror(errno)); |
5607 |
string_sprintf("couldn't create child process: %s", strerror(errno)); |
| 5474 |
goto EXPAND_FAILED; |
5608 |
goto EXPAND_FAILED; |
| 5475 |
} |
5609 |
} |
| 5476 |
|
5610 |
|
| 5477 |
/* Nothing is written to the standard input. */ |
5611 |
/* Nothing is written to the standard input. */ |
| 5478 |
|
5612 |
|
|
Lines 5530-5536
Link Here
|
| 5530 |
case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */ |
5664 |
case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */ |
| 5531 |
} |
5665 |
} |
| 5532 |
|
5666 |
|
| 5533 |
continue; |
5667 |
if (skipping) continue; |
|
|
5668 |
break; |
| 5534 |
} |
5669 |
} |
| 5535 |
|
5670 |
|
| 5536 |
/* Handle character translation for "tr" */ |
5671 |
/* Handle character translation for "tr" */ |
|
Lines 5539-5545
Link Here
|
| 5539 |
{ |
5674 |
{ |
| 5540 |
int oldptr = gstring_length(yield); |
5675 |
int oldptr = gstring_length(yield); |
| 5541 |
int o2m; |
5676 |
int o2m; |
| 5542 |
uschar *sub[3]; |
5677 |
uschar * sub[3]; |
| 5543 |
|
5678 |
|
| 5544 |
switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok)) |
5679 |
switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok)) |
| 5545 |
{ |
5680 |
{ |
|
Lines 5561-5567
Link Here
|
| 5561 |
} |
5696 |
} |
| 5562 |
} |
5697 |
} |
| 5563 |
|
5698 |
|
| 5564 |
continue; |
5699 |
if (skipping) continue; |
|
|
5700 |
break; |
| 5565 |
} |
5701 |
} |
| 5566 |
|
5702 |
|
| 5567 |
/* Handle "hash", "length", "nhash", and "substr" when they are given with |
5703 |
/* Handle "hash", "length", "nhash", and "substr" when they are given with |
|
Lines 5575-5581
Link Here
|
| 5575 |
int len; |
5711 |
int len; |
| 5576 |
uschar *ret; |
5712 |
uschar *ret; |
| 5577 |
int val[2] = { 0, -1 }; |
5713 |
int val[2] = { 0, -1 }; |
| 5578 |
uschar *sub[3]; |
5714 |
uschar * sub[3]; |
| 5579 |
|
5715 |
|
| 5580 |
/* "length" takes only 2 arguments whereas the others take 2 or 3. |
5716 |
/* "length" takes only 2 arguments whereas the others take 2 or 3. |
| 5581 |
Ensure that sub[2] is set in the ${length } case. */ |
5717 |
Ensure that sub[2] is set in the ${length } case. */ |
|
Lines 5624-5630
Link Here
|
| 5624 |
if (!ret) |
5760 |
if (!ret) |
| 5625 |
goto EXPAND_FAILED; |
5761 |
goto EXPAND_FAILED; |
| 5626 |
yield = string_catn(yield, ret, len); |
5762 |
yield = string_catn(yield, ret, len); |
| 5627 |
continue; |
5763 |
if (skipping) continue; |
|
|
5764 |
break; |
| 5628 |
} |
5765 |
} |
| 5629 |
|
5766 |
|
| 5630 |
/* Handle HMAC computation: ${hmac{<algorithm>}{<secret>}{<text>}} |
5767 |
/* Handle HMAC computation: ${hmac{<algorithm>}{<secret>}{<text>}} |
|
Lines 5639-5652
Link Here
|
| 5639 |
|
5776 |
|
| 5640 |
case EITEM_HMAC: |
5777 |
case EITEM_HMAC: |
| 5641 |
{ |
5778 |
{ |
| 5642 |
uschar *sub[3]; |
5779 |
uschar * sub[3]; |
| 5643 |
md5 md5_base; |
5780 |
md5 md5_base; |
| 5644 |
hctx sha1_ctx; |
5781 |
hctx sha1_ctx; |
| 5645 |
void *use_base; |
5782 |
void * use_base; |
| 5646 |
int type; |
5783 |
int type; |
| 5647 |
int hashlen; /* Number of octets for the hash algorithm's output */ |
5784 |
int hashlen; /* Number of octets for the hash algorithm's output */ |
| 5648 |
int hashblocklen; /* Number of octets the hash algorithm processes */ |
5785 |
int hashblocklen; /* Number of octets the hash algorithm processes */ |
| 5649 |
uschar *keyptr, *p; |
5786 |
uschar * keyptr, * p; |
| 5650 |
unsigned int keylen; |
5787 |
unsigned int keylen; |
| 5651 |
|
5788 |
|
| 5652 |
uschar keyhash[MAX_HASHLEN]; |
5789 |
uschar keyhash[MAX_HASHLEN]; |
|
Lines 5663-5741
Link Here
|
| 5663 |
case 3: goto EXPAND_FAILED; |
5800 |
case 3: goto EXPAND_FAILED; |
| 5664 |
} |
5801 |
} |
| 5665 |
|
5802 |
|
| 5666 |
if (!skipping) |
5803 |
if (skipping) continue; |
|
|
5804 |
|
| 5805 |
if (Ustrcmp(sub[0], "md5") == 0) |
| 5667 |
{ |
5806 |
{ |
| 5668 |
if (Ustrcmp(sub[0], "md5") == 0) |
5807 |
type = HMAC_MD5; |
| 5669 |
{ |
5808 |
use_base = &md5_base; |
| 5670 |
type = HMAC_MD5; |
5809 |
hashlen = 16; |
| 5671 |
use_base = &md5_base; |
5810 |
hashblocklen = 64; |
| 5672 |
hashlen = 16; |
5811 |
} |
| 5673 |
hashblocklen = 64; |
5812 |
else if (Ustrcmp(sub[0], "sha1") == 0) |
| 5674 |
} |
5813 |
{ |
| 5675 |
else if (Ustrcmp(sub[0], "sha1") == 0) |
5814 |
type = HMAC_SHA1; |
| 5676 |
{ |
5815 |
use_base = &sha1_ctx; |
| 5677 |
type = HMAC_SHA1; |
5816 |
hashlen = 20; |
| 5678 |
use_base = &sha1_ctx; |
5817 |
hashblocklen = 64; |
| 5679 |
hashlen = 20; |
5818 |
} |
| 5680 |
hashblocklen = 64; |
5819 |
else |
| 5681 |
} |
5820 |
{ |
| 5682 |
else |
5821 |
expand_string_message = |
| 5683 |
{ |
5822 |
string_sprintf("hmac algorithm \"%s\" is not recognised", sub[0]); |
| 5684 |
expand_string_message = |
5823 |
goto EXPAND_FAILED; |
| 5685 |
string_sprintf("hmac algorithm \"%s\" is not recognised", sub[0]); |
5824 |
} |
| 5686 |
goto EXPAND_FAILED; |
|
|
| 5687 |
} |
| 5688 |
|
5825 |
|
| 5689 |
keyptr = sub[1]; |
5826 |
keyptr = sub[1]; |
| 5690 |
keylen = Ustrlen(keyptr); |
5827 |
keylen = Ustrlen(keyptr); |
| 5691 |
|
5828 |
|
| 5692 |
/* If the key is longer than the hash block length, then hash the key |
5829 |
/* If the key is longer than the hash block length, then hash the key |
| 5693 |
first */ |
5830 |
first */ |
| 5694 |
|
5831 |
|
| 5695 |
if (keylen > hashblocklen) |
5832 |
if (keylen > hashblocklen) |
| 5696 |
{ |
5833 |
{ |
| 5697 |
chash_start(type, use_base); |
5834 |
chash_start(type, use_base); |
| 5698 |
chash_end(type, use_base, keyptr, keylen, keyhash); |
5835 |
chash_end(type, use_base, keyptr, keylen, keyhash); |
| 5699 |
keyptr = keyhash; |
5836 |
keyptr = keyhash; |
| 5700 |
keylen = hashlen; |
5837 |
keylen = hashlen; |
| 5701 |
} |
5838 |
} |
| 5702 |
|
5839 |
|
| 5703 |
/* Now make the inner and outer key values */ |
5840 |
/* Now make the inner and outer key values */ |
| 5704 |
|
5841 |
|
| 5705 |
memset(innerkey, 0x36, hashblocklen); |
5842 |
memset(innerkey, 0x36, hashblocklen); |
| 5706 |
memset(outerkey, 0x5c, hashblocklen); |
5843 |
memset(outerkey, 0x5c, hashblocklen); |
| 5707 |
|
5844 |
|
| 5708 |
for (int i = 0; i < keylen; i++) |
5845 |
for (int i = 0; i < keylen; i++) |
| 5709 |
{ |
5846 |
{ |
| 5710 |
innerkey[i] ^= keyptr[i]; |
5847 |
innerkey[i] ^= keyptr[i]; |
| 5711 |
outerkey[i] ^= keyptr[i]; |
5848 |
outerkey[i] ^= keyptr[i]; |
| 5712 |
} |
5849 |
} |
| 5713 |
|
5850 |
|
| 5714 |
/* Now do the hashes */ |
5851 |
/* Now do the hashes */ |
| 5715 |
|
5852 |
|
| 5716 |
chash_start(type, use_base); |
5853 |
chash_start(type, use_base); |
| 5717 |
chash_mid(type, use_base, innerkey); |
5854 |
chash_mid(type, use_base, innerkey); |
| 5718 |
chash_end(type, use_base, sub[2], Ustrlen(sub[2]), innerhash); |
5855 |
chash_end(type, use_base, sub[2], Ustrlen(sub[2]), innerhash); |
| 5719 |
|
5856 |
|
| 5720 |
chash_start(type, use_base); |
5857 |
chash_start(type, use_base); |
| 5721 |
chash_mid(type, use_base, outerkey); |
5858 |
chash_mid(type, use_base, outerkey); |
| 5722 |
chash_end(type, use_base, innerhash, hashlen, finalhash); |
5859 |
chash_end(type, use_base, innerhash, hashlen, finalhash); |
| 5723 |
|
5860 |
|
| 5724 |
/* Encode the final hash as a hex string */ |
5861 |
/* Encode the final hash as a hex string */ |
| 5725 |
|
5862 |
|
| 5726 |
p = finalhash_hex; |
5863 |
p = finalhash_hex; |
| 5727 |
for (int i = 0; i < hashlen; i++) |
5864 |
for (int i = 0; i < hashlen; i++) |
| 5728 |
{ |
5865 |
{ |
| 5729 |
*p++ = hex_digits[(finalhash[i] & 0xf0) >> 4]; |
5866 |
*p++ = hex_digits[(finalhash[i] & 0xf0) >> 4]; |
| 5730 |
*p++ = hex_digits[finalhash[i] & 0x0f]; |
5867 |
*p++ = hex_digits[finalhash[i] & 0x0f]; |
| 5731 |
} |
5868 |
} |
| 5732 |
|
5869 |
|
| 5733 |
DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n", |
5870 |
DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n", |
| 5734 |
sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex); |
5871 |
sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex); |
| 5735 |
|
5872 |
|
| 5736 |
yield = string_catn(yield, finalhash_hex, hashlen*2); |
5873 |
yield = string_catn(yield, finalhash_hex, hashlen*2); |
| 5737 |
} |
5874 |
break; |
| 5738 |
continue; |
|
|
| 5739 |
} |
5875 |
} |
| 5740 |
|
5876 |
|
| 5741 |
/* Handle global substitution for "sg" - like Perl's s/xxx/yyy/g operator. |
5877 |
/* Handle global substitution for "sg" - like Perl's s/xxx/yyy/g operator. |
|
Lines 5743-5755
Link Here
|
| 5743 |
|
5879 |
|
| 5744 |
case EITEM_SG: |
5880 |
case EITEM_SG: |
| 5745 |
{ |
5881 |
{ |
| 5746 |
const pcre *re; |
5882 |
const pcre2_code * re; |
| 5747 |
int moffset, moffsetextra, slen; |
5883 |
int moffset, moffsetextra, slen; |
| 5748 |
int roffset; |
5884 |
PCRE2_SIZE roffset; |
| 5749 |
int emptyopt; |
5885 |
pcre2_match_data * md; |
| 5750 |
const uschar *rerror; |
5886 |
int err, emptyopt; |
| 5751 |
uschar *subject; |
5887 |
uschar * subject, * sub[3]; |
| 5752 |
uschar *sub[3]; |
|
|
| 5753 |
int save_expand_nmax = |
5888 |
int save_expand_nmax = |
| 5754 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
5889 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
| 5755 |
|
5890 |
|
|
Lines 5760-5774
Link Here
|
| 5760 |
case 3: goto EXPAND_FAILED; |
5895 |
case 3: goto EXPAND_FAILED; |
| 5761 |
} |
5896 |
} |
| 5762 |
|
5897 |
|
|
|
5898 |
/*XXX no handling of skipping? */ |
| 5763 |
/* Compile the regular expression */ |
5899 |
/* Compile the regular expression */ |
| 5764 |
|
5900 |
|
| 5765 |
if (!(re = pcre_compile(CS sub[1], PCRE_COPT, CCSS &rerror, |
5901 |
if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED, |
| 5766 |
&roffset, NULL))) |
5902 |
PCRE_COPT, &err, &roffset, pcre_cmp_ctx))) |
| 5767 |
{ |
5903 |
{ |
|
|
5904 |
uschar errbuf[128]; |
| 5905 |
pcre2_get_error_message(err, errbuf, sizeof(errbuf)); |
| 5768 |
expand_string_message = string_sprintf("regular expression error in " |
5906 |
expand_string_message = string_sprintf("regular expression error in " |
| 5769 |
"\"%s\": %s at offset %d", sub[1], rerror, roffset); |
5907 |
"\"%s\": %s at offset %ld", sub[1], errbuf, (long)roffset); |
| 5770 |
goto EXPAND_FAILED; |
5908 |
goto EXPAND_FAILED; |
| 5771 |
} |
5909 |
} |
|
|
5910 |
md = pcre2_match_data_create(EXPAND_MAXN + 1, pcre_gen_ctx); |
| 5772 |
|
5911 |
|
| 5773 |
/* Now run a loop to do the substitutions as often as necessary. It ends |
5912 |
/* Now run a loop to do the substitutions as often as necessary. It ends |
| 5774 |
when there are no more matches. Take care over matches of the null string; |
5913 |
when there are no more matches. Take care over matches of the null string; |
|
Lines 5781-5790
Link Here
|
| 5781 |
|
5920 |
|
| 5782 |
for (;;) |
5921 |
for (;;) |
| 5783 |
{ |
5922 |
{ |
| 5784 |
int ovector[3*(EXPAND_MAXN+1)]; |
5923 |
PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md); |
| 5785 |
int n = pcre_exec(re, NULL, CS subject, slen, moffset + moffsetextra, |
5924 |
int n = pcre2_match(re, (PCRE2_SPTR)subject, slen, moffset + moffsetextra, |
| 5786 |
PCRE_EOPT | emptyopt, ovector, nelem(ovector)); |
5925 |
PCRE_EOPT | emptyopt, md, pcre_mtc_ctx); |
| 5787 |
uschar *insert; |
5926 |
uschar * insert; |
| 5788 |
|
5927 |
|
| 5789 |
/* No match - if we previously set PCRE_NOTEMPTY after a null match, this |
5928 |
/* No match - if we previously set PCRE_NOTEMPTY after a null match, this |
| 5790 |
is not necessarily the end. We want to repeat the match from one |
5929 |
is not necessarily the end. We want to repeat the match from one |
|
Lines 5806-5829
Link Here
|
| 5806 |
} |
5945 |
} |
| 5807 |
|
5946 |
|
| 5808 |
/* Match - set up for expanding the replacement. */ |
5947 |
/* Match - set up for expanding the replacement. */ |
|
|
5948 |
DEBUG(D_expand) debug_printf_indent("%s: match\n", name); |
| 5809 |
|
5949 |
|
| 5810 |
if (n == 0) n = EXPAND_MAXN + 1; |
5950 |
if (n == 0) n = EXPAND_MAXN + 1; |
| 5811 |
expand_nmax = 0; |
5951 |
expand_nmax = 0; |
| 5812 |
for (int nn = 0; nn < n*2; nn += 2) |
5952 |
for (int nn = 0; nn < n*2; nn += 2) |
| 5813 |
{ |
5953 |
{ |
| 5814 |
expand_nstring[expand_nmax] = subject + ovector[nn]; |
5954 |
expand_nstring[expand_nmax] = subject + ovec[nn]; |
| 5815 |
expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn]; |
5955 |
expand_nlength[expand_nmax++] = ovec[nn+1] - ovec[nn]; |
| 5816 |
} |
5956 |
} |
| 5817 |
expand_nmax--; |
5957 |
expand_nmax--; |
| 5818 |
|
5958 |
|
| 5819 |
/* Copy the characters before the match, plus the expanded insertion. */ |
5959 |
/* Copy the characters before the match, plus the expanded insertion. */ |
| 5820 |
|
5960 |
|
| 5821 |
yield = string_catn(yield, subject + moffset, ovector[0] - moffset); |
5961 |
yield = string_catn(yield, subject + moffset, ovec[0] - moffset); |
|
|
5962 |
|
| 5822 |
if (!(insert = expand_string(sub[2]))) |
5963 |
if (!(insert = expand_string(sub[2]))) |
| 5823 |
goto EXPAND_FAILED; |
5964 |
goto EXPAND_FAILED; |
| 5824 |
yield = string_cat(yield, insert); |
5965 |
yield = string_cat(yield, insert); |
| 5825 |
|
5966 |
|
| 5826 |
moffset = ovector[1]; |
5967 |
moffset = ovec[1]; |
| 5827 |
moffsetextra = 0; |
5968 |
moffsetextra = 0; |
| 5828 |
emptyopt = 0; |
5969 |
emptyopt = 0; |
| 5829 |
|
5970 |
|
|
Lines 5834-5843
Link Here
|
| 5834 |
string at the same point. If this fails (picked up above) we advance to |
5975 |
string at the same point. If this fails (picked up above) we advance to |
| 5835 |
the next character. */ |
5976 |
the next character. */ |
| 5836 |
|
5977 |
|
| 5837 |
if (ovector[0] == ovector[1]) |
5978 |
if (ovec[0] == ovec[1]) |
| 5838 |
{ |
5979 |
{ |
| 5839 |
if (ovector[0] == slen) break; |
5980 |
if (ovec[0] == slen) break; |
| 5840 |
emptyopt = PCRE_NOTEMPTY | PCRE_ANCHORED; |
5981 |
emptyopt = PCRE2_NOTEMPTY | PCRE2_ANCHORED; |
| 5841 |
} |
5982 |
} |
| 5842 |
} |
5983 |
} |
| 5843 |
|
5984 |
|
|
Lines 5845-5851
Link Here
|
| 5845 |
|
5986 |
|
| 5846 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
5987 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
| 5847 |
save_expand_nlength); |
5988 |
save_expand_nlength); |
| 5848 |
continue; |
5989 |
if (skipping) continue; |
|
|
5990 |
break; |
| 5849 |
} |
5991 |
} |
| 5850 |
|
5992 |
|
| 5851 |
/* Handle keyed and numbered substring extraction. If the first argument |
5993 |
/* Handle keyed and numbered substring extraction. If the first argument |
|
Lines 5855-5862
Link Here
|
| 5855 |
{ |
5997 |
{ |
| 5856 |
int field_number = 1; |
5998 |
int field_number = 1; |
| 5857 |
BOOL field_number_set = FALSE; |
5999 |
BOOL field_number_set = FALSE; |
| 5858 |
uschar *save_lookup_value = lookup_value; |
6000 |
uschar * save_lookup_value = lookup_value, * sub[3]; |
| 5859 |
uschar *sub[3]; |
|
|
| 5860 |
int save_expand_nmax = |
6001 |
int save_expand_nmax = |
| 5861 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
6002 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
| 5862 |
|
6003 |
|
|
Lines 5882-5888
Link Here
|
| 5882 |
|
6023 |
|
| 5883 |
if (skipping) |
6024 |
if (skipping) |
| 5884 |
{ |
6025 |
{ |
| 5885 |
for (int j = 5; j > 0 && *s == '{'; j--) /*'}'*/ |
6026 |
for (int j = 5; j > 0 && *s == '{'; j--) /*'}'*/ |
| 5886 |
{ |
6027 |
{ |
| 5887 |
if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)) |
6028 |
if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)) |
| 5888 |
goto EXPAND_FAILED; /*'{'*/ |
6029 |
goto EXPAND_FAILED; /*'{'*/ |
|
Lines 5893-5905
Link Here
|
| 5893 |
} |
6034 |
} |
| 5894 |
Uskip_whitespace(&s); |
6035 |
Uskip_whitespace(&s); |
| 5895 |
} |
6036 |
} |
| 5896 |
if ( Ustrncmp(s, "fail", 4) == 0 /*'{'*/ |
6037 |
if ( Ustrncmp(s, "fail", 4) == 0 /*'{'*/ |
| 5897 |
&& (s[4] == '}' || s[4] == ' ' || s[4] == '\t' || !s[4]) |
6038 |
&& (s[4] == '}' || s[4] == ' ' || s[4] == '\t' || !s[4]) |
| 5898 |
) |
6039 |
) |
| 5899 |
{ |
6040 |
{ |
| 5900 |
s += 4; |
6041 |
s += 4; |
| 5901 |
Uskip_whitespace(&s); |
6042 |
Uskip_whitespace(&s); |
| 5902 |
} /*'{'*/ |
6043 |
} /*'{'*/ |
| 5903 |
if (*s != '}') |
6044 |
if (*s != '}') |
| 5904 |
{ |
6045 |
{ |
| 5905 |
expand_string_message = US"missing '}' closing extract"; |
6046 |
expand_string_message = US"missing '}' closing extract"; |
|
Lines 5909-5918
Link Here
|
| 5909 |
|
6050 |
|
| 5910 |
else for (int i = 0, j = 2; i < j; i++) /* Read the proper number of arguments */ |
6051 |
else for (int i = 0, j = 2; i < j; i++) /* Read the proper number of arguments */ |
| 5911 |
{ |
6052 |
{ |
| 5912 |
if (Uskip_whitespace(&s) == '{') /*'}'*/ |
6053 |
if (Uskip_whitespace(&s) == '{') /*'}'*/ |
| 5913 |
{ |
6054 |
{ |
| 5914 |
if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))) |
6055 |
if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))) |
| 5915 |
goto EXPAND_FAILED; /*'{'*/ |
6056 |
goto EXPAND_FAILED; /*'{'*/ |
| 5916 |
if (*s++ != '}') |
6057 |
if (*s++ != '}') |
| 5917 |
{ |
6058 |
{ |
| 5918 |
expand_string_message = string_sprintf( |
6059 |
expand_string_message = string_sprintf( |
|
Lines 5929-5935
Link Here
|
| 5929 |
{ |
6070 |
{ |
| 5930 |
int len; |
6071 |
int len; |
| 5931 |
int x = 0; |
6072 |
int x = 0; |
| 5932 |
uschar *p = sub[0]; |
6073 |
uschar * p = sub[0]; |
| 5933 |
|
6074 |
|
| 5934 |
Uskip_whitespace(&p); |
6075 |
Uskip_whitespace(&p); |
| 5935 |
sub[0] = p; |
6076 |
sub[0] = p; |
|
Lines 5938-5944
Link Here
|
| 5938 |
while (len > 0 && isspace(p[len-1])) len--; |
6079 |
while (len > 0 && isspace(p[len-1])) len--; |
| 5939 |
p[len] = 0; |
6080 |
p[len] = 0; |
| 5940 |
|
6081 |
|
| 5941 |
if (*p == 0) |
6082 |
if (!*p) |
| 5942 |
{ |
6083 |
{ |
| 5943 |
expand_string_message = US"first argument of \"extract\" must " |
6084 |
expand_string_message = US"first argument of \"extract\" must " |
| 5944 |
"not be empty"; |
6085 |
"not be empty"; |
|
Lines 5950-5957
Link Here
|
| 5950 |
field_number = -1; |
6091 |
field_number = -1; |
| 5951 |
p++; |
6092 |
p++; |
| 5952 |
} |
6093 |
} |
| 5953 |
while (*p != 0 && isdigit(*p)) x = x * 10 + *p++ - '0'; |
6094 |
while (*p && isdigit(*p)) x = x * 10 + *p++ - '0'; |
| 5954 |
if (*p == 0) |
6095 |
if (!*p) |
| 5955 |
{ |
6096 |
{ |
| 5956 |
field_number *= x; |
6097 |
field_number *= x; |
| 5957 |
if (fmt == extract_basic) j = 3; /* Need 3 args */ |
6098 |
if (fmt == extract_basic) j = 3; /* Need 3 args */ |
|
Lines 6081-6087
Link Here
|
| 6081 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
6222 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
| 6082 |
save_expand_nlength); |
6223 |
save_expand_nlength); |
| 6083 |
|
6224 |
|
| 6084 |
continue; |
6225 |
if (skipping) continue; |
|
|
6226 |
break; |
| 6085 |
} |
6227 |
} |
| 6086 |
|
6228 |
|
| 6087 |
/* return the Nth item from a list */ |
6229 |
/* return the Nth item from a list */ |
|
Lines 6089-6096
Link Here
|
| 6089 |
case EITEM_LISTEXTRACT: |
6231 |
case EITEM_LISTEXTRACT: |
| 6090 |
{ |
6232 |
{ |
| 6091 |
int field_number = 1; |
6233 |
int field_number = 1; |
| 6092 |
uschar *save_lookup_value = lookup_value; |
6234 |
uschar * save_lookup_value = lookup_value, * sub[2]; |
| 6093 |
uschar *sub[2]; |
|
|
| 6094 |
int save_expand_nmax = |
6235 |
int save_expand_nmax = |
| 6095 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
6236 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
| 6096 |
|
6237 |
|
|
Lines 6098-6112
Link Here
|
| 6098 |
|
6239 |
|
| 6099 |
for (int i = 0; i < 2; i++) |
6240 |
for (int i = 0; i < 2; i++) |
| 6100 |
{ |
6241 |
{ |
| 6101 |
if (Uskip_whitespace(&s) != '{') /*'}'*/ |
6242 |
if (Uskip_whitespace(&s) != '{') /*}*/ |
| 6102 |
{ |
6243 |
{ |
| 6103 |
expand_string_message = string_sprintf( |
6244 |
expand_string_message = string_sprintf( |
| 6104 |
"missing '{' for arg %d of listextract", i+1); |
6245 |
"missing '{' for arg %d of listextract", i+1); /*}*/ |
| 6105 |
goto EXPAND_FAILED_CURLY; |
6246 |
goto EXPAND_FAILED_CURLY; |
| 6106 |
} |
6247 |
} |
| 6107 |
|
6248 |
|
| 6108 |
sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); |
6249 |
sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); |
| 6109 |
if (!sub[i]) goto EXPAND_FAILED; /*{*/ |
6250 |
if (!sub[i]) goto EXPAND_FAILED; /*{{*/ |
| 6110 |
if (*s++ != '}') |
6251 |
if (*s++ != '}') |
| 6111 |
{ |
6252 |
{ |
| 6112 |
expand_string_message = string_sprintf( |
6253 |
expand_string_message = string_sprintf( |
|
Lines 6179-6185
Link Here
|
| 6179 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
6320 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
| 6180 |
save_expand_nlength); |
6321 |
save_expand_nlength); |
| 6181 |
|
6322 |
|
| 6182 |
continue; |
6323 |
if (skipping) continue; |
|
|
6324 |
break; |
| 6183 |
} |
6325 |
} |
| 6184 |
|
6326 |
|
| 6185 |
case EITEM_LISTQUOTE: |
6327 |
case EITEM_LISTQUOTE: |
|
Lines 6197-6210
Link Here
|
| 6197 |
yield = string_catn(yield, sub[1], 1); |
6339 |
yield = string_catn(yield, sub[1], 1); |
| 6198 |
} |
6340 |
} |
| 6199 |
else yield = string_catn(yield, US" ", 1); |
6341 |
else yield = string_catn(yield, US" ", 1); |
| 6200 |
continue; |
6342 |
if (skipping) continue; |
|
|
6343 |
break; |
| 6201 |
} |
6344 |
} |
| 6202 |
|
6345 |
|
| 6203 |
#ifndef DISABLE_TLS |
6346 |
#ifndef DISABLE_TLS |
| 6204 |
case EITEM_CERTEXTRACT: |
6347 |
case EITEM_CERTEXTRACT: |
| 6205 |
{ |
6348 |
{ |
| 6206 |
uschar *save_lookup_value = lookup_value; |
6349 |
uschar * save_lookup_value = lookup_value, * sub[2]; |
| 6207 |
uschar *sub[2]; |
|
|
| 6208 |
int save_expand_nmax = |
6350 |
int save_expand_nmax = |
| 6209 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
6351 |
save_expand_strings(save_expand_nstring, save_expand_nlength); |
| 6210 |
|
6352 |
|
|
Lines 6212-6221
Link Here
|
| 6212 |
if (Uskip_whitespace(&s) != '{') /*}*/ |
6354 |
if (Uskip_whitespace(&s) != '{') /*}*/ |
| 6213 |
{ |
6355 |
{ |
| 6214 |
expand_string_message = US"missing '{' for field arg of certextract"; |
6356 |
expand_string_message = US"missing '{' for field arg of certextract"; |
| 6215 |
goto EXPAND_FAILED_CURLY; |
6357 |
goto EXPAND_FAILED_CURLY; /*}*/ |
| 6216 |
} |
6358 |
} |
| 6217 |
sub[0] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); |
6359 |
sub[0] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); |
| 6218 |
if (!sub[0]) goto EXPAND_FAILED; /*{*/ |
6360 |
if (!sub[0]) goto EXPAND_FAILED; /*{{*/ |
| 6219 |
if (*s++ != '}') |
6361 |
if (*s++ != '}') |
| 6220 |
{ |
6362 |
{ |
| 6221 |
expand_string_message = US"missing '}' closing field arg of certextract"; |
6363 |
expand_string_message = US"missing '}' closing field arg of certextract"; |
|
Lines 6238-6244
Link Here
|
| 6238 |
if (Uskip_whitespace(&s) != '{') /*}*/ |
6380 |
if (Uskip_whitespace(&s) != '{') /*}*/ |
| 6239 |
{ |
6381 |
{ |
| 6240 |
expand_string_message = US"missing '{' for cert variable arg of certextract"; |
6382 |
expand_string_message = US"missing '{' for cert variable arg of certextract"; |
| 6241 |
goto EXPAND_FAILED_CURLY; |
6383 |
goto EXPAND_FAILED_CURLY; /*}*/ |
| 6242 |
} |
6384 |
} |
| 6243 |
if (*++s != '$') |
6385 |
if (*++s != '$') |
| 6244 |
{ |
6386 |
{ |
|
Lines 6247-6253
Link Here
|
| 6247 |
goto EXPAND_FAILED; |
6389 |
goto EXPAND_FAILED; |
| 6248 |
} |
6390 |
} |
| 6249 |
sub[1] = expand_string_internal(s+1, TRUE, &s, skipping, FALSE, &resetok); |
6391 |
sub[1] = expand_string_internal(s+1, TRUE, &s, skipping, FALSE, &resetok); |
| 6250 |
if (!sub[1]) goto EXPAND_FAILED; /*{*/ |
6392 |
if (!sub[1]) goto EXPAND_FAILED; /*{{*/ |
| 6251 |
if (*s++ != '}') |
6393 |
if (*s++ != '}') |
| 6252 |
{ |
6394 |
{ |
| 6253 |
expand_string_message = US"missing '}' closing cert variable arg of certextract"; |
6395 |
expand_string_message = US"missing '}' closing cert variable arg of certextract"; |
|
Lines 6276-6282
Link Here
|
| 6276 |
|
6418 |
|
| 6277 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
6419 |
restore_expand_strings(save_expand_nmax, save_expand_nstring, |
| 6278 |
save_expand_nlength); |
6420 |
save_expand_nlength); |
| 6279 |
continue; |
6421 |
if (skipping) continue; |
|
|
6422 |
break; |
| 6280 |
} |
6423 |
} |
| 6281 |
#endif /*DISABLE_TLS*/ |
6424 |
#endif /*DISABLE_TLS*/ |
| 6282 |
|
6425 |
|
|
Lines 6286-6308
Link Here
|
| 6286 |
case EITEM_MAP: |
6429 |
case EITEM_MAP: |
| 6287 |
case EITEM_REDUCE: |
6430 |
case EITEM_REDUCE: |
| 6288 |
{ |
6431 |
{ |
| 6289 |
int sep = 0; |
6432 |
int sep = 0, save_ptr = gstring_length(yield); |
| 6290 |
int save_ptr = gstring_length(yield); |
|
|
| 6291 |
uschar outsep[2] = { '\0', '\0' }; |
6433 |
uschar outsep[2] = { '\0', '\0' }; |
| 6292 |
const uschar *list, *expr, *temp; |
6434 |
const uschar *list, *expr, *temp; |
| 6293 |
uschar *save_iterate_item = iterate_item; |
6435 |
uschar * save_iterate_item = iterate_item; |
| 6294 |
uschar *save_lookup_value = lookup_value; |
6436 |
uschar * save_lookup_value = lookup_value; |
| 6295 |
|
6437 |
|
| 6296 |
Uskip_whitespace(&s); |
6438 |
Uskip_whitespace(&s); |
| 6297 |
if (*s++ != '{') |
6439 |
if (*s++ != '{') /*}*/ |
| 6298 |
{ |
6440 |
{ |
| 6299 |
expand_string_message = |
6441 |
expand_string_message = |
| 6300 |
string_sprintf("missing '{' for first arg of %s", name); |
6442 |
string_sprintf("missing '{' for first arg of %s", name); |
| 6301 |
goto EXPAND_FAILED_CURLY; |
6443 |
goto EXPAND_FAILED_CURLY; /*}*/ |
| 6302 |
} |
6444 |
} |
| 6303 |
|
6445 |
|
| 6304 |
if (!(list = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok))) |
6446 |
if (!(list = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok))) |
| 6305 |
goto EXPAND_FAILED; |
6447 |
goto EXPAND_FAILED; /*{{*/ |
| 6306 |
if (*s++ != '}') |
6448 |
if (*s++ != '}') |
| 6307 |
{ |
6449 |
{ |
| 6308 |
expand_string_message = |
6450 |
expand_string_message = |
|
Lines 6314-6327
Link Here
|
| 6314 |
{ |
6456 |
{ |
| 6315 |
uschar * t; |
6457 |
uschar * t; |
| 6316 |
Uskip_whitespace(&s); |
6458 |
Uskip_whitespace(&s); |
| 6317 |
if (*s++ != '{') |
6459 |
if (*s++ != '{') /*}*/ |
| 6318 |
{ |
6460 |
{ |
| 6319 |
expand_string_message = US"missing '{' for second arg of reduce"; |
6461 |
expand_string_message = US"missing '{' for second arg of reduce"; |
| 6320 |
goto EXPAND_FAILED_CURLY; |
6462 |
goto EXPAND_FAILED_CURLY; /*}*/ |
| 6321 |
} |
6463 |
} |
| 6322 |
t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); |
6464 |
t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); |
| 6323 |
if (!t) goto EXPAND_FAILED; |
6465 |
if (!t) goto EXPAND_FAILED; |
| 6324 |
lookup_value = t; |
6466 |
lookup_value = t; /*{{*/ |
| 6325 |
if (*s++ != '}') |
6467 |
if (*s++ != '}') |
| 6326 |
{ |
6468 |
{ |
| 6327 |
expand_string_message = US"missing '}' closing second arg of reduce"; |
6469 |
expand_string_message = US"missing '}' closing second arg of reduce"; |
|
Lines 6330-6339
Link Here
|
| 6330 |
} |
6472 |
} |
| 6331 |
|
6473 |
|
| 6332 |
Uskip_whitespace(&s); |
6474 |
Uskip_whitespace(&s); |
| 6333 |
if (*s++ != '{') |
6475 |
if (*s++ != '{') /*}*/ |
| 6334 |
{ |
6476 |
{ |
| 6335 |
expand_string_message = |
6477 |
expand_string_message = |
| 6336 |
string_sprintf("missing '{' for last arg of %s", name); |
6478 |
string_sprintf("missing '{' for last arg of %s", name); /*}*/ |
| 6337 |
goto EXPAND_FAILED_CURLY; |
6479 |
goto EXPAND_FAILED_CURLY; |
| 6338 |
} |
6480 |
} |
| 6339 |
|
6481 |
|
|
Lines 6345-6357
Link Here
|
| 6345 |
condition for real. For EITEM_MAP and EITEM_REDUCE, do the same, using |
6487 |
condition for real. For EITEM_MAP and EITEM_REDUCE, do the same, using |
| 6346 |
the normal internal expansion function. */ |
6488 |
the normal internal expansion function. */ |
| 6347 |
|
6489 |
|
| 6348 |
if (item_type == EITEM_FILTER) |
6490 |
if (item_type != EITEM_FILTER) |
| 6349 |
{ |
|
|
| 6350 |
if ((temp = eval_condition(expr, &resetok, NULL))) |
| 6351 |
s = temp; |
| 6352 |
} |
| 6353 |
else |
| 6354 |
temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok); |
6491 |
temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok); |
|
|
6492 |
else |
| 6493 |
if ((temp = eval_condition(expr, &resetok, NULL))) s = temp; |
| 6355 |
|
6494 |
|
| 6356 |
if (!temp) |
6495 |
if (!temp) |
| 6357 |
{ |
6496 |
{ |
|
Lines 6360-6377
Link Here
|
| 6360 |
goto EXPAND_FAILED; |
6499 |
goto EXPAND_FAILED; |
| 6361 |
} |
6500 |
} |
| 6362 |
|
6501 |
|
| 6363 |
Uskip_whitespace(&s); |
6502 |
Uskip_whitespace(&s); /*{{{*/ |
| 6364 |
if (*s++ != '}') |
6503 |
if (*s++ != '}') |
| 6365 |
{ /*{*/ |
6504 |
{ |
| 6366 |
expand_string_message = string_sprintf("missing } at end of condition " |
6505 |
expand_string_message = string_sprintf("missing } at end of condition " |
| 6367 |
"or expression inside \"%s\"; could be an unquoted } in the content", |
6506 |
"or expression inside \"%s\"; could be an unquoted } in the content", |
| 6368 |
name); |
6507 |
name); |
| 6369 |
goto EXPAND_FAILED; |
6508 |
goto EXPAND_FAILED; |
| 6370 |
} |
6509 |
} |
| 6371 |
|
6510 |
|
| 6372 |
Uskip_whitespace(&s); /*{*/ |
6511 |
Uskip_whitespace(&s); /*{{*/ |
| 6373 |
if (*s++ != '}') |
6512 |
if (*s++ != '}') |
| 6374 |
{ /*{*/ |
6513 |
{ |
| 6375 |
expand_string_message = string_sprintf("missing } at end of \"%s\"", |
6514 |
expand_string_message = string_sprintf("missing } at end of \"%s\"", |
| 6376 |
name); |
6515 |
name); |
| 6377 |
goto EXPAND_FAILED; |
6516 |
goto EXPAND_FAILED; |
|
Lines 6434-6439
Link Here
|
| 6434 |
item of the output list, add in a space if the new item begins with the |
6573 |
item of the output list, add in a space if the new item begins with the |
| 6435 |
separator character, or is an empty string. */ |
6574 |
separator character, or is an empty string. */ |
| 6436 |
|
6575 |
|
|
|
6576 |
/*XXX is there not a standard support function for this, appending to a list? */ |
| 6577 |
/* yes, string_append_listele(), but it depends on lack of text before the list */ |
| 6578 |
|
| 6437 |
if ( yield && yield->ptr != save_ptr |
6579 |
if ( yield && yield->ptr != save_ptr |
| 6438 |
&& (temp[0] == *outsep || temp[0] == 0)) |
6580 |
&& (temp[0] == *outsep || temp[0] == 0)) |
| 6439 |
yield = string_catn(yield, US" ", 1); |
6581 |
yield = string_catn(yield, US" ", 1); |
|
Lines 6451-6457
Link Here
|
| 6451 |
too many; backup and end the loop. Otherwise arrange to double the |
6593 |
too many; backup and end the loop. Otherwise arrange to double the |
| 6452 |
separator. */ |
6594 |
separator. */ |
| 6453 |
|
6595 |
|
| 6454 |
if (temp[seglen] == '\0') { yield->ptr--; break; } |
6596 |
if (!temp[seglen]) { yield->ptr--; break; } |
| 6455 |
yield = string_catn(yield, outsep, 1); |
6597 |
yield = string_catn(yield, outsep, 1); |
| 6456 |
temp += seglen + 1; |
6598 |
temp += seglen + 1; |
| 6457 |
} |
6599 |
} |
|
Lines 6480-6507
Link Here
|
| 6480 |
/* Restore preserved $item */ |
6622 |
/* Restore preserved $item */ |
| 6481 |
|
6623 |
|
| 6482 |
iterate_item = save_iterate_item; |
6624 |
iterate_item = save_iterate_item; |
| 6483 |
continue; |
6625 |
if (skipping) continue; |
|
|
6626 |
break; |
| 6484 |
} |
6627 |
} |
| 6485 |
|
6628 |
|
| 6486 |
case EITEM_SORT: |
6629 |
case EITEM_SORT: |
| 6487 |
{ |
6630 |
{ |
| 6488 |
int cond_type; |
6631 |
int sep = 0, cond_type; |
| 6489 |
int sep = 0; |
6632 |
const uschar * srclist, * cmp, * xtract; |
| 6490 |
const uschar *srclist, *cmp, *xtract; |
|
|
| 6491 |
uschar * opname, * srcitem; |
6633 |
uschar * opname, * srcitem; |
| 6492 |
const uschar *dstlist = NULL, *dstkeylist = NULL; |
6634 |
const uschar * dstlist = NULL, * dstkeylist = NULL; |
| 6493 |
uschar * tmp; |
6635 |
uschar * tmp, * save_iterate_item = iterate_item; |
| 6494 |
uschar *save_iterate_item = iterate_item; |
|
|
| 6495 |
|
6636 |
|
| 6496 |
Uskip_whitespace(&s); |
6637 |
Uskip_whitespace(&s); |
| 6497 |
if (*s++ != '{') |
6638 |
if (*s++ != '{') /*}*/ |
| 6498 |
{ |
6639 |
{ |
| 6499 |
expand_string_message = US"missing '{' for list arg of sort"; |
6640 |
expand_string_message = US"missing '{' for list arg of sort"; |
| 6500 |
goto EXPAND_FAILED_CURLY; |
6641 |
goto EXPAND_FAILED_CURLY; /*}*/ |
| 6501 |
} |
6642 |
} |
| 6502 |
|
6643 |
|
| 6503 |
srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); |
6644 |
srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); |
| 6504 |
if (!srclist) goto EXPAND_FAILED; |
6645 |
if (!srclist) goto EXPAND_FAILED; /*{{*/ |
| 6505 |
if (*s++ != '}') |
6646 |
if (*s++ != '}') |
| 6506 |
{ |
6647 |
{ |
| 6507 |
expand_string_message = US"missing '}' closing list arg of sort"; |
6648 |
expand_string_message = US"missing '}' closing list arg of sort"; |
|
Lines 6509-6522
Link Here
|
| 6509 |
} |
6650 |
} |
| 6510 |
|
6651 |
|
| 6511 |
Uskip_whitespace(&s); |
6652 |
Uskip_whitespace(&s); |
| 6512 |
if (*s++ != '{') |
6653 |
if (*s++ != '{') /*}*/ |
| 6513 |
{ |
6654 |
{ |
| 6514 |
expand_string_message = US"missing '{' for comparator arg of sort"; |
6655 |
expand_string_message = US"missing '{' for comparator arg of sort"; |
| 6515 |
goto EXPAND_FAILED_CURLY; |
6656 |
goto EXPAND_FAILED_CURLY; /*}*/ |
| 6516 |
} |
6657 |
} |
| 6517 |
|
6658 |
|
| 6518 |
cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok); |
6659 |
cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok); |
| 6519 |
if (!cmp) goto EXPAND_FAILED; |
6660 |
if (!cmp) goto EXPAND_FAILED; /*{{*/ |
| 6520 |
if (*s++ != '}') |
6661 |
if (*s++ != '}') |
| 6521 |
{ |
6662 |
{ |
| 6522 |
expand_string_message = US"missing '}' closing comparator arg of sort"; |
6663 |
expand_string_message = US"missing '}' closing comparator arg of sort"; |
|
Lines 6543-6567
Link Here
|
| 6543 |
} |
6684 |
} |
| 6544 |
|
6685 |
|
| 6545 |
Uskip_whitespace(&s); |
6686 |
Uskip_whitespace(&s); |
| 6546 |
if (*s++ != '{') |
6687 |
if (*s++ != '{') /*}*/ |
| 6547 |
{ |
6688 |
{ |
| 6548 |
expand_string_message = US"missing '{' for extractor arg of sort"; |
6689 |
expand_string_message = US"missing '{' for extractor arg of sort"; |
| 6549 |
goto EXPAND_FAILED_CURLY; |
6690 |
goto EXPAND_FAILED_CURLY; /*}*/ |
| 6550 |
} |
6691 |
} |
| 6551 |
|
6692 |
|
| 6552 |
xtract = s; |
6693 |
xtract = s; |
| 6553 |
if (!(tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok))) |
6694 |
if (!(tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok))) |
| 6554 |
goto EXPAND_FAILED; |
6695 |
goto EXPAND_FAILED; |
| 6555 |
xtract = string_copyn(xtract, s - xtract); |
6696 |
xtract = string_copyn(xtract, s - xtract); |
| 6556 |
|
6697 |
/*{{*/ |
| 6557 |
if (*s++ != '}') |
6698 |
if (*s++ != '}') |
| 6558 |
{ |
6699 |
{ |
| 6559 |
expand_string_message = US"missing '}' closing extractor arg of sort"; |
6700 |
expand_string_message = US"missing '}' closing extractor arg of sort"; |
| 6560 |
goto EXPAND_FAILED_CURLY; |
6701 |
goto EXPAND_FAILED_CURLY; |
| 6561 |
} |
6702 |
} |
| 6562 |
/*{*/ |
6703 |
/*{{*/ |
| 6563 |
if (*s++ != '}') |
6704 |
if (*s++ != '}') |
| 6564 |
{ /*{*/ |
6705 |
{ |
| 6565 |
expand_string_message = US"missing } at end of \"sort\""; |
6706 |
expand_string_message = US"missing } at end of \"sort\""; |
| 6566 |
goto EXPAND_FAILED; |
6707 |
goto EXPAND_FAILED; |
| 6567 |
} |
6708 |
} |
|
Lines 6571-6578
Link Here
|
| 6571 |
while ((srcitem = string_nextinlist(&srclist, &sep, NULL, 0))) |
6712 |
while ((srcitem = string_nextinlist(&srclist, &sep, NULL, 0))) |
| 6572 |
{ |
6713 |
{ |
| 6573 |
uschar * srcfield, * dstitem; |
6714 |
uschar * srcfield, * dstitem; |
| 6574 |
gstring * newlist = NULL; |
6715 |
gstring * newlist = NULL, * newkeylist = NULL; |
| 6575 |
gstring * newkeylist = NULL; |
|
|
| 6576 |
|
6716 |
|
| 6577 |
DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem); |
6717 |
DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem); |
| 6578 |
|
6718 |
|
|
Lines 6596-6602
Link Here
|
| 6596 |
|
6736 |
|
| 6597 |
/* field for comparison */ |
6737 |
/* field for comparison */ |
| 6598 |
if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0))) |
6738 |
if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0))) |
| 6599 |
goto sort_mismatch; |
6739 |
goto SORT_MISMATCH; |
| 6600 |
|
6740 |
|
| 6601 |
/* String-comparator names start with a letter; numeric names do not */ |
6741 |
/* String-comparator names start with a letter; numeric names do not */ |
| 6602 |
|
6742 |
|
|
Lines 6617-6623
Link Here
|
| 6617 |
while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0))) |
6757 |
while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0))) |
| 6618 |
{ |
6758 |
{ |
| 6619 |
if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0))) |
6759 |
if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0))) |
| 6620 |
goto sort_mismatch; |
6760 |
goto SORT_MISMATCH; |
| 6621 |
newlist = string_append_listele(newlist, sep, dstitem); |
6761 |
newlist = string_append_listele(newlist, sep, dstitem); |
| 6622 |
newkeylist = string_append_listele(newkeylist, sep, dstfield); |
6762 |
newkeylist = string_append_listele(newkeylist, sep, dstfield); |
| 6623 |
} |
6763 |
} |
|
Lines 6648-6656
Link Here
|
| 6648 |
|
6788 |
|
| 6649 |
/* Restore preserved $item */ |
6789 |
/* Restore preserved $item */ |
| 6650 |
iterate_item = save_iterate_item; |
6790 |
iterate_item = save_iterate_item; |
| 6651 |
continue; |
6791 |
break; |
| 6652 |
|
6792 |
|
| 6653 |
sort_mismatch: |
6793 |
SORT_MISMATCH: |
| 6654 |
expand_string_message = US"Internal error in sort (list mismatch)"; |
6794 |
expand_string_message = US"Internal error in sort (list mismatch)"; |
| 6655 |
goto EXPAND_FAILED; |
6795 |
goto EXPAND_FAILED; |
| 6656 |
} |
6796 |
} |
|
Lines 6671-6683
Link Here
|
| 6671 |
|
6811 |
|
| 6672 |
#else /* EXPAND_DLFUNC */ |
6812 |
#else /* EXPAND_DLFUNC */ |
| 6673 |
{ |
6813 |
{ |
| 6674 |
tree_node *t; |
6814 |
tree_node * t; |
| 6675 |
exim_dlfunc_t *func; |
6815 |
exim_dlfunc_t * func; |
| 6676 |
uschar *result; |
6816 |
uschar * result; |
| 6677 |
int status, argc; |
6817 |
int status, argc; |
| 6678 |
uschar *argv[EXPAND_DLFUNC_MAX_ARGS + 3]; |
6818 |
uschar * argv[EXPAND_DLFUNC_MAX_ARGS + 3]; |
| 6679 |
|
6819 |
|
| 6680 |
if ((expand_forbid & RDO_DLFUNC) != 0) |
6820 |
if (expand_forbid & RDO_DLFUNC) |
| 6681 |
{ |
6821 |
{ |
| 6682 |
expand_string_message = |
6822 |
expand_string_message = |
| 6683 |
US"dynamically-loaded functions are not permitted"; |
6823 |
US"dynamically-loaded functions are not permitted"; |
|
Lines 6701-6707
Link Here
|
| 6701 |
|
6841 |
|
| 6702 |
if (!(t = tree_search(dlobj_anchor, argv[0]))) |
6842 |
if (!(t = tree_search(dlobj_anchor, argv[0]))) |
| 6703 |
{ |
6843 |
{ |
| 6704 |
void *handle = dlopen(CS argv[0], RTLD_LAZY); |
6844 |
void * handle = dlopen(CS argv[0], RTLD_LAZY); |
| 6705 |
if (!handle) |
6845 |
if (!handle) |
| 6706 |
{ |
6846 |
{ |
| 6707 |
expand_string_message = string_sprintf("dlopen \"%s\" failed: %s", |
6847 |
expand_string_message = string_sprintf("dlopen \"%s\" failed: %s", |
|
Lines 6709-6715
Link Here
|
| 6709 |
log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); |
6849 |
log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); |
| 6710 |
goto EXPAND_FAILED; |
6850 |
goto EXPAND_FAILED; |
| 6711 |
} |
6851 |
} |
| 6712 |
t = store_get_perm(sizeof(tree_node) + Ustrlen(argv[0]), is_tainted(argv[0])); |
6852 |
t = store_get_perm(sizeof(tree_node) + Ustrlen(argv[0]), argv[0]); |
| 6713 |
Ustrcpy(t->name, argv[0]); |
6853 |
Ustrcpy(t->name, argv[0]); |
| 6714 |
t->data.ptr = handle; |
6854 |
t->data.ptr = handle; |
| 6715 |
(void)tree_insertnode(&dlobj_anchor, t); |
6855 |
(void)tree_insertnode(&dlobj_anchor, t); |
|
Lines 6735-6749
Link Here
|
| 6735 |
|
6875 |
|
| 6736 |
resetok = FALSE; |
6876 |
resetok = FALSE; |
| 6737 |
result = NULL; |
6877 |
result = NULL; |
| 6738 |
for (argc = 0; argv[argc]; argc++); |
6878 |
for (argc = 0; argv[argc]; argc++) ; |
| 6739 |
status = func(&result, argc - 2, &argv[2]); |
6879 |
|
| 6740 |
if(status == OK) |
6880 |
if ((status = func(&result, argc - 2, &argv[2])) != OK) |
| 6741 |
{ |
|
|
| 6742 |
if (!result) result = US""; |
| 6743 |
yield = string_cat(yield, result); |
| 6744 |
continue; |
| 6745 |
} |
| 6746 |
else |
| 6747 |
{ |
6881 |
{ |
| 6748 |
expand_string_message = result ? result : US"(no message)"; |
6882 |
expand_string_message = result ? result : US"(no message)"; |
| 6749 |
if (status == FAIL_FORCED) |
6883 |
if (status == FAIL_FORCED) |
|
Lines 6753-6758
Link Here
|
| 6753 |
argv[0], argv[1], status, expand_string_message); |
6887 |
argv[0], argv[1], status, expand_string_message); |
| 6754 |
goto EXPAND_FAILED; |
6888 |
goto EXPAND_FAILED; |
| 6755 |
} |
6889 |
} |
|
|
6890 |
|
| 6891 |
if (result) yield = string_cat(yield, result); |
| 6892 |
break; |
| 6756 |
} |
6893 |
} |
| 6757 |
#endif /* EXPAND_DLFUNC */ |
6894 |
#endif /* EXPAND_DLFUNC */ |
| 6758 |
|
6895 |
|
|
Lines 6765-6774
Link Here
|
| 6765 |
goto EXPAND_FAILED; |
6902 |
goto EXPAND_FAILED; |
| 6766 |
|
6903 |
|
| 6767 |
key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); |
6904 |
key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); |
| 6768 |
if (!key) goto EXPAND_FAILED; /*{*/ |
6905 |
if (!key) goto EXPAND_FAILED; /*{{*/ |
| 6769 |
if (*s++ != '}') |
6906 |
if (*s++ != '}') |
| 6770 |
{ |
6907 |
{ |
| 6771 |
expand_string_message = US"missing '{' for name arg of env"; |
6908 |
expand_string_message = US"missing '}' for name arg of env"; |
| 6772 |
goto EXPAND_FAILED_CURLY; |
6909 |
goto EXPAND_FAILED_CURLY; |
| 6773 |
} |
6910 |
} |
| 6774 |
|
6911 |
|
|
Lines 6786-6800
Link Here
|
| 6786 |
case 1: goto EXPAND_FAILED; /* when all is well, the */ |
6923 |
case 1: goto EXPAND_FAILED; /* when all is well, the */ |
| 6787 |
case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */ |
6924 |
case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */ |
| 6788 |
} |
6925 |
} |
| 6789 |
continue; |
6926 |
if (skipping) continue; |
|
|
6927 |
break; |
| 6790 |
} |
6928 |
} |
| 6791 |
|
6929 |
|
| 6792 |
#ifdef EXPERIMENTAL_SRS_NATIVE |
6930 |
#ifdef SUPPORT_SRS |
| 6793 |
case EITEM_SRS_ENCODE: |
6931 |
case EITEM_SRS_ENCODE: |
| 6794 |
/* ${srs_encode {secret} {return_path} {orig_domain}} */ |
6932 |
/* ${srs_encode {secret} {return_path} {orig_domain}} */ |
| 6795 |
{ |
6933 |
{ |
| 6796 |
uschar * sub[3]; |
6934 |
uschar * sub[3]; |
| 6797 |
uschar cksum[4]; |
6935 |
uschar cksum[4]; |
|
|
6936 |
gstring * g = NULL; |
| 6937 |
BOOL quoted = FALSE; |
| 6798 |
|
6938 |
|
| 6799 |
switch (read_subs(sub, 3, 3, CUSS &s, skipping, TRUE, name, &resetok)) |
6939 |
switch (read_subs(sub, 3, 3, CUSS &s, skipping, TRUE, name, &resetok)) |
| 6800 |
{ |
6940 |
{ |
|
Lines 6802-6850
Link Here
|
| 6802 |
case 2: |
6942 |
case 2: |
| 6803 |
case 3: goto EXPAND_FAILED; |
6943 |
case 3: goto EXPAND_FAILED; |
| 6804 |
} |
6944 |
} |
|
|
6945 |
if (skipping) continue; |
| 6805 |
|
6946 |
|
| 6806 |
yield = string_catn(yield, US"SRS0=", 5); |
6947 |
if (sub[1] && *(sub[1])) |
|
|
6948 |
{ |
| 6949 |
g = string_catn(g, US"SRS0=", 5); |
| 6807 |
|
6950 |
|
| 6808 |
/* ${l_4:${hmac{md5}{SRS_SECRET}{${lc:$return_path}}}}= */ |
6951 |
/* ${l_4:${hmac{md5}{SRS_SECRET}{${lc:$return_path}}}}= */ |
| 6809 |
hmac_md5(sub[0], string_copylc(sub[1]), cksum, sizeof(cksum)); |
6952 |
hmac_md5(sub[0], string_copylc(sub[1]), cksum, sizeof(cksum)); |
| 6810 |
yield = string_catn(yield, cksum, sizeof(cksum)); |
6953 |
g = string_catn(g, cksum, sizeof(cksum)); |
| 6811 |
yield = string_catn(yield, US"=", 1); |
6954 |
g = string_catn(g, US"=", 1); |
| 6812 |
|
6955 |
|
| 6813 |
/* ${base32:${eval:$tod_epoch/86400&0x3ff}}= */ |
6956 |
/* ${base32:${eval:$tod_epoch/86400&0x3ff}}= */ |
| 6814 |
{ |
6957 |
{ |
| 6815 |
struct timeval now; |
6958 |
struct timeval now; |
| 6816 |
unsigned long i; |
6959 |
unsigned long i; |
| 6817 |
gstring * g = NULL; |
6960 |
gstring * h = NULL; |
| 6818 |
|
6961 |
|
| 6819 |
gettimeofday(&now, NULL); |
6962 |
gettimeofday(&now, NULL); |
| 6820 |
for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5) |
6963 |
for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5) |
| 6821 |
g = string_catn(g, &base32_chars[i & 0x1f], 1); |
6964 |
h = string_catn(h, &base32_chars[i & 0x1f], 1); |
| 6822 |
if (g) while (g->ptr > 0) |
6965 |
if (h) while (h->ptr > 0) |
| 6823 |
yield = string_catn(yield, &g->s[--g->ptr], 1); |
6966 |
g = string_catn(g, &h->s[--h->ptr], 1); |
| 6824 |
} |
6967 |
} |
| 6825 |
yield = string_catn(yield, US"=", 1); |
6968 |
g = string_catn(g, US"=", 1); |
| 6826 |
|
6969 |
|
| 6827 |
/* ${domain:$return_path}=${local_part:$return_path} */ |
6970 |
/* ${domain:$return_path}=${local_part:$return_path} */ |
| 6828 |
{ |
6971 |
{ |
| 6829 |
int start, end, domain; |
6972 |
int start, end, domain; |
| 6830 |
uschar * t = parse_extract_address(sub[1], &expand_string_message, |
6973 |
uschar * t = parse_extract_address(sub[1], &expand_string_message, |
| 6831 |
&start, &end, &domain, FALSE); |
6974 |
&start, &end, &domain, FALSE); |
| 6832 |
if (!t) |
6975 |
uschar * s; |
| 6833 |
goto EXPAND_FAILED; |
|
|
| 6834 |
|
6976 |
|
| 6835 |
if (domain > 0) yield = string_cat(yield, t + domain); |
6977 |
if (!t) |
| 6836 |
yield = string_catn(yield, US"=", 1); |
6978 |
goto EXPAND_FAILED; |
| 6837 |
yield = domain > 0 |
|
|
| 6838 |
? string_catn(yield, t, domain - 1) : string_cat(yield, t); |
| 6839 |
} |
| 6840 |
|
6979 |
|
| 6841 |
/* @$original_domain */ |
6980 |
if (domain > 0) g = string_cat(g, t + domain); |
| 6842 |
yield = string_catn(yield, US"@", 1); |
6981 |
g = string_catn(g, US"=", 1); |
| 6843 |
yield = string_cat(yield, sub[2]); |
6982 |
|
| 6844 |
continue; |
6983 |
s = domain > 0 ? string_copyn(t, domain - 1) : t; |
|
|
6984 |
if ((quoted = Ustrchr(s, '"') != NULL)) |
| 6985 |
{ |
| 6986 |
gstring * h = NULL; |
| 6987 |
DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n"); |
| 6988 |
while (*s) /* de-quote */ |
| 6989 |
{ |
| 6990 |
while (*s && *s != '"') h = string_catn(h, s++, 1); |
| 6991 |
if (*s) s++; |
| 6992 |
while (*s && *s != '"') h = string_catn(h, s++, 1); |
| 6993 |
if (*s) s++; |
| 6994 |
} |
| 6995 |
gstring_release_unused(h); |
| 6996 |
s = string_from_gstring(h); |
| 6997 |
} |
| 6998 |
g = string_cat(g, s); |
| 6999 |
} |
| 7000 |
|
| 7001 |
/* Assume that if the original local_part had quotes |
| 7002 |
it was for good reason */ |
| 7003 |
|
| 7004 |
if (quoted) yield = string_catn(yield, US"\"", 1); |
| 7005 |
yield = string_catn(yield, g->s, g->ptr); |
| 7006 |
if (quoted) yield = string_catn(yield, US"\"", 1); |
| 7007 |
|
| 7008 |
/* @$original_domain */ |
| 7009 |
yield = string_catn(yield, US"@", 1); |
| 7010 |
yield = string_cat(yield, sub[2]); |
| 7011 |
} |
| 7012 |
else |
| 7013 |
DEBUG(D_expand) debug_printf_indent("null return_path for srs-encode\n"); |
| 7014 |
|
| 7015 |
break; |
| 6845 |
} |
7016 |
} |
| 6846 |
#endif /*EXPERIMENTAL_SRS_NATIVE*/ |
7017 |
#endif /*SUPPORT_SRS*/ |
|
|
7018 |
|
| 7019 |
default: |
| 7020 |
goto NOT_ITEM; |
| 6847 |
} /* EITEM_* switch */ |
7021 |
} /* EITEM_* switch */ |
|
|
7022 |
/*NOTREACHED*/ |
| 7023 |
|
| 7024 |
DEBUG(D_expand) |
| 7025 |
if (yield && (start > 0 || *s)) /* only if not the sole expansion of the line */ |
| 7026 |
debug_expansion_interim(US"item-res", |
| 7027 |
yield->s + start, yield->ptr - start, skipping); |
| 7028 |
continue; |
| 7029 |
|
| 7030 |
NOT_ITEM: ; |
| 7031 |
} |
| 6848 |
|
7032 |
|
| 6849 |
/* Control reaches here if the name is not recognized as one of the more |
7033 |
/* Control reaches here if the name is not recognized as one of the more |
| 6850 |
complicated expansion items. Check for the "operator" syntax (name terminated |
7034 |
complicated expansion items. Check for the "operator" syntax (name terminated |
|
Lines 6854-6863
Link Here
|
| 6854 |
if (*s == ':') |
7038 |
if (*s == ':') |
| 6855 |
{ |
7039 |
{ |
| 6856 |
int c; |
7040 |
int c; |
| 6857 |
uschar *arg = NULL; |
7041 |
uschar * arg = NULL, * sub; |
| 6858 |
uschar *sub; |
|
|
| 6859 |
#ifndef DISABLE_TLS |
7042 |
#ifndef DISABLE_TLS |
| 6860 |
var_entry *vp = NULL; |
7043 |
var_entry * vp = NULL; |
| 6861 |
#endif |
7044 |
#endif |
| 6862 |
|
7045 |
|
| 6863 |
/* Owing to an historical mis-design, an underscore may be part of the |
7046 |
/* Owing to an historical mis-design, an underscore may be part of the |
|
Lines 6891-6897
Link Here
|
| 6891 |
FALSE, &resetok); |
7074 |
FALSE, &resetok); |
| 6892 |
if (!sub) goto EXPAND_FAILED; /*{*/ |
7075 |
if (!sub) goto EXPAND_FAILED; /*{*/ |
| 6893 |
if (*s1 != '}') |
7076 |
if (*s1 != '}') |
| 6894 |
{ |
7077 |
{ /*{*/ |
| 6895 |
expand_string_message = |
7078 |
expand_string_message = |
| 6896 |
string_sprintf("missing '}' closing cert arg of %s", name); |
7079 |
string_sprintf("missing '}' closing cert arg of %s", name); |
| 6897 |
goto EXPAND_FAILED_CURLY; |
7080 |
goto EXPAND_FAILED_CURLY; |
|
Lines 6920-7048
Link Here
|
| 6920 |
|
7103 |
|
| 6921 |
if (skipping && c >= 0) continue; |
7104 |
if (skipping && c >= 0) continue; |
| 6922 |
|
7105 |
|
| 6923 |
/* Otherwise, switch on the operator type */ |
7106 |
/* Otherwise, switch on the operator type. After handling go back |
|
|
7107 |
to the main loop top. */ |
| 6924 |
|
7108 |
|
| 6925 |
switch(c) |
7109 |
{ |
|
|
7110 |
int start = yield->ptr; |
| 7111 |
switch(c) |
| 6926 |
{ |
7112 |
{ |
| 6927 |
case EOP_BASE32: |
7113 |
case EOP_BASE32: |
| 6928 |
{ |
7114 |
{ |
| 6929 |
uschar *t; |
7115 |
uschar *t; |
| 6930 |
unsigned long int n = Ustrtoul(sub, &t, 10); |
7116 |
unsigned long int n = Ustrtoul(sub, &t, 10); |
| 6931 |
gstring * g = NULL; |
7117 |
gstring * g = NULL; |
| 6932 |
|
7118 |
|
| 6933 |
if (*t != 0) |
7119 |
if (*t != 0) |
| 6934 |
{ |
7120 |
{ |
| 6935 |
expand_string_message = string_sprintf("argument for base32 " |
7121 |
expand_string_message = string_sprintf("argument for base32 " |
| 6936 |
"operator is \"%s\", which is not a decimal number", sub); |
7122 |
"operator is \"%s\", which is not a decimal number", sub); |
| 6937 |
goto EXPAND_FAILED; |
7123 |
goto EXPAND_FAILED; |
| 6938 |
} |
7124 |
} |
| 6939 |
for ( ; n; n >>= 5) |
7125 |
for ( ; n; n >>= 5) |
| 6940 |
g = string_catn(g, &base32_chars[n & 0x1f], 1); |
7126 |
g = string_catn(g, &base32_chars[n & 0x1f], 1); |
| 6941 |
|
7127 |
|
| 6942 |
if (g) while (g->ptr > 0) yield = string_catn(yield, &g->s[--g->ptr], 1); |
7128 |
if (g) while (g->ptr > 0) yield = string_catn(yield, &g->s[--g->ptr], 1); |
| 6943 |
continue; |
7129 |
break; |
| 6944 |
} |
7130 |
} |
| 6945 |
|
7131 |
|
| 6946 |
case EOP_BASE32D: |
7132 |
case EOP_BASE32D: |
| 6947 |
{ |
7133 |
{ |
| 6948 |
uschar *tt = sub; |
7134 |
uschar *tt = sub; |
| 6949 |
unsigned long int n = 0; |
7135 |
unsigned long int n = 0; |
| 6950 |
while (*tt) |
7136 |
while (*tt) |
| 6951 |
{ |
7137 |
{ |
| 6952 |
uschar * t = Ustrchr(base32_chars, *tt++); |
7138 |
uschar * t = Ustrchr(base32_chars, *tt++); |
| 6953 |
if (!t) |
7139 |
if (!t) |
| 6954 |
{ |
7140 |
{ |
| 6955 |
expand_string_message = string_sprintf("argument for base32d " |
7141 |
expand_string_message = string_sprintf("argument for base32d " |
| 6956 |
"operator is \"%s\", which is not a base 32 number", sub); |
7142 |
"operator is \"%s\", which is not a base 32 number", sub); |
| 6957 |
goto EXPAND_FAILED; |
7143 |
goto EXPAND_FAILED; |
| 6958 |
} |
7144 |
} |
| 6959 |
n = n * 32 + (t - base32_chars); |
7145 |
n = n * 32 + (t - base32_chars); |
| 6960 |
} |
7146 |
} |
| 6961 |
yield = string_fmt_append(yield, "%ld", n); |
7147 |
yield = string_fmt_append(yield, "%ld", n); |
| 6962 |
continue; |
7148 |
break; |
| 6963 |
} |
7149 |
} |
| 6964 |
|
7150 |
|
| 6965 |
case EOP_BASE62: |
7151 |
case EOP_BASE62: |
| 6966 |
{ |
7152 |
{ |
| 6967 |
uschar *t; |
7153 |
uschar *t; |
| 6968 |
unsigned long int n = Ustrtoul(sub, &t, 10); |
7154 |
unsigned long int n = Ustrtoul(sub, &t, 10); |
| 6969 |
if (*t != 0) |
7155 |
if (*t != 0) |
| 6970 |
{ |
7156 |
{ |
| 6971 |
expand_string_message = string_sprintf("argument for base62 " |
7157 |
expand_string_message = string_sprintf("argument for base62 " |
| 6972 |
"operator is \"%s\", which is not a decimal number", sub); |
7158 |
"operator is \"%s\", which is not a decimal number", sub); |
| 6973 |
goto EXPAND_FAILED; |
7159 |
goto EXPAND_FAILED; |
| 6974 |
} |
7160 |
} |
| 6975 |
yield = string_cat(yield, string_base62(n)); |
7161 |
yield = string_cat(yield, string_base62(n)); |
| 6976 |
continue; |
7162 |
break; |
| 6977 |
} |
7163 |
} |
| 6978 |
|
7164 |
|
| 6979 |
/* Note that for Darwin and Cygwin, BASE_62 actually has the value 36 */ |
7165 |
/* Note that for Darwin and Cygwin, BASE_62 actually has the value 36 */ |
| 6980 |
|
7166 |
|
| 6981 |
case EOP_BASE62D: |
7167 |
case EOP_BASE62D: |
| 6982 |
{ |
7168 |
{ |
| 6983 |
uschar *tt = sub; |
7169 |
uschar *tt = sub; |
| 6984 |
unsigned long int n = 0; |
7170 |
unsigned long int n = 0; |
| 6985 |
while (*tt != 0) |
7171 |
while (*tt != 0) |
| 6986 |
{ |
|
|
| 6987 |
uschar *t = Ustrchr(base62_chars, *tt++); |
| 6988 |
if (!t) |
| 6989 |
{ |
| 6990 |
expand_string_message = string_sprintf("argument for base62d " |
| 6991 |
"operator is \"%s\", which is not a base %d number", sub, |
| 6992 |
BASE_62); |
| 6993 |
goto EXPAND_FAILED; |
| 6994 |
} |
| 6995 |
n = n * BASE_62 + (t - base62_chars); |
| 6996 |
} |
| 6997 |
yield = string_fmt_append(yield, "%ld", n); |
| 6998 |
continue; |
| 6999 |
} |
| 7000 |
|
| 7001 |
case EOP_BLESS: |
| 7002 |
/* This is purely for the convenience of the test harness. Do not enable |
| 7003 |
it otherwise as it defeats the taint-checking security. */ |
| 7004 |
|
| 7005 |
if (f.running_in_test_harness) |
| 7006 |
yield = string_cat(yield, is_tainted(sub) |
| 7007 |
? string_copy_taint(sub, FALSE) : sub); |
| 7008 |
else |
| 7009 |
{ |
7172 |
{ |
| 7010 |
DEBUG(D_expand) debug_printf_indent("bless operator not supported\n"); |
7173 |
uschar *t = Ustrchr(base62_chars, *tt++); |
| 7011 |
yield = string_cat(yield, sub); |
7174 |
if (!t) |
|
|
7175 |
{ |
| 7176 |
expand_string_message = string_sprintf("argument for base62d " |
| 7177 |
"operator is \"%s\", which is not a base %d number", sub, |
| 7178 |
BASE_62); |
| 7179 |
goto EXPAND_FAILED; |
| 7180 |
} |
| 7181 |
n = n * BASE_62 + (t - base62_chars); |
| 7012 |
} |
7182 |
} |
| 7013 |
continue; |
7183 |
yield = string_fmt_append(yield, "%ld", n); |
|
|
7184 |
break; |
| 7185 |
} |
| 7014 |
|
7186 |
|
| 7015 |
case EOP_EXPAND: |
7187 |
case EOP_EXPAND: |
| 7016 |
{ |
7188 |
{ |
| 7017 |
uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping, TRUE, &resetok); |
7189 |
uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping, TRUE, &resetok); |
| 7018 |
if (!expanded) |
7190 |
if (!expanded) |
| 7019 |
{ |
7191 |
{ |
| 7020 |
expand_string_message = |
7192 |
expand_string_message = |
| 7021 |
string_sprintf("internal expansion of \"%s\" failed: %s", sub, |
7193 |
string_sprintf("internal expansion of \"%s\" failed: %s", sub, |
| 7022 |
expand_string_message); |
7194 |
expand_string_message); |
| 7023 |
goto EXPAND_FAILED; |
7195 |
goto EXPAND_FAILED; |
| 7024 |
} |
7196 |
} |
| 7025 |
yield = string_cat(yield, expanded); |
7197 |
yield = string_cat(yield, expanded); |
| 7026 |
continue; |
7198 |
break; |
| 7027 |
} |
7199 |
} |
| 7028 |
|
7200 |
|
| 7029 |
case EOP_LC: |
7201 |
case EOP_LC: |
| 7030 |
{ |
7202 |
{ |
| 7031 |
int count = 0; |
7203 |
int count = 0; |
| 7032 |
uschar *t = sub - 1; |
7204 |
uschar *t = sub - 1; |
| 7033 |
while (*(++t) != 0) { *t = tolower(*t); count++; } |
7205 |
while (*(++t) != 0) { *t = tolower(*t); count++; } |
| 7034 |
yield = string_catn(yield, sub, count); |
7206 |
yield = string_catn(yield, sub, count); |
| 7035 |
continue; |
7207 |
break; |
| 7036 |
} |
7208 |
} |
| 7037 |
|
7209 |
|
| 7038 |
case EOP_UC: |
7210 |
case EOP_UC: |
| 7039 |
{ |
7211 |
{ |
| 7040 |
int count = 0; |
7212 |
int count = 0; |
| 7041 |
uschar *t = sub - 1; |
7213 |
uschar *t = sub - 1; |
| 7042 |
while (*(++t) != 0) { *t = toupper(*t); count++; } |
7214 |
while (*(++t) != 0) { *t = toupper(*t); count++; } |
| 7043 |
yield = string_catn(yield, sub, count); |
7215 |
yield = string_catn(yield, sub, count); |
| 7044 |
continue; |
7216 |
break; |
| 7045 |
} |
7217 |
} |
| 7046 |
|
7218 |
|
| 7047 |
case EOP_MD5: |
7219 |
case EOP_MD5: |
| 7048 |
#ifndef DISABLE_TLS |
7220 |
#ifndef DISABLE_TLS |
|
Lines 7061-7067
Link Here
|
| 7061 |
for (int j = 0; j < 16; j++) |
7233 |
for (int j = 0; j < 16; j++) |
| 7062 |
yield = string_fmt_append(yield, "%02x", digest[j]); |
7234 |
yield = string_fmt_append(yield, "%02x", digest[j]); |
| 7063 |
} |
7235 |
} |
| 7064 |
continue; |
7236 |
break; |
| 7065 |
|
7237 |
|
| 7066 |
case EOP_SHA1: |
7238 |
case EOP_SHA1: |
| 7067 |
#ifndef DISABLE_TLS |
7239 |
#ifndef DISABLE_TLS |
|
Lines 7080-7086
Link Here
|
| 7080 |
for (int j = 0; j < 20; j++) |
7252 |
for (int j = 0; j < 20; j++) |
| 7081 |
yield = string_fmt_append(yield, "%02X", digest[j]); |
7253 |
yield = string_fmt_append(yield, "%02X", digest[j]); |
| 7082 |
} |
7254 |
} |
| 7083 |
continue; |
7255 |
break; |
| 7084 |
|
7256 |
|
| 7085 |
case EOP_SHA2: |
7257 |
case EOP_SHA2: |
| 7086 |
case EOP_SHA256: |
7258 |
case EOP_SHA256: |
|
Lines 7106-7112
Link Here
|
| 7106 |
goto EXPAND_FAILED; |
7278 |
goto EXPAND_FAILED; |
| 7107 |
} |
7279 |
} |
| 7108 |
|
7280 |
|
| 7109 |
exim_sha_update(&h, sub, Ustrlen(sub)); |
7281 |
exim_sha_update_string(&h, sub); |
| 7110 |
exim_sha_finish(&h, &b); |
7282 |
exim_sha_finish(&h, &b); |
| 7111 |
while (b.len-- > 0) |
7283 |
while (b.len-- > 0) |
| 7112 |
yield = string_fmt_append(yield, "%02X", *b.data++); |
7284 |
yield = string_fmt_append(yield, "%02X", *b.data++); |
|
Lines 7114-7120
Link Here
|
| 7114 |
#else |
7286 |
#else |
| 7115 |
expand_string_message = US"sha256 only supported with TLS"; |
7287 |
expand_string_message = US"sha256 only supported with TLS"; |
| 7116 |
#endif |
7288 |
#endif |
| 7117 |
continue; |
7289 |
break; |
| 7118 |
|
7290 |
|
| 7119 |
case EOP_SHA3: |
7291 |
case EOP_SHA3: |
| 7120 |
#ifdef EXIM_HAVE_SHA3 |
7292 |
#ifdef EXIM_HAVE_SHA3 |
|
Lines 7134-7145
Link Here
|
| 7134 |
goto EXPAND_FAILED; |
7306 |
goto EXPAND_FAILED; |
| 7135 |
} |
7307 |
} |
| 7136 |
|
7308 |
|
| 7137 |
exim_sha_update(&h, sub, Ustrlen(sub)); |
7309 |
exim_sha_update_string(&h, sub); |
| 7138 |
exim_sha_finish(&h, &b); |
7310 |
exim_sha_finish(&h, &b); |
| 7139 |
while (b.len-- > 0) |
7311 |
while (b.len-- > 0) |
| 7140 |
yield = string_fmt_append(yield, "%02X", *b.data++); |
7312 |
yield = string_fmt_append(yield, "%02X", *b.data++); |
| 7141 |
} |
7313 |
} |
| 7142 |
continue; |
7314 |
break; |
| 7143 |
#else |
7315 |
#else |
| 7144 |
expand_string_message = US"sha3 only supported with GnuTLS 3.5.0 + or OpenSSL 1.1.1 +"; |
7316 |
expand_string_message = US"sha3 only supported with GnuTLS 3.5.0 + or OpenSSL 1.1.1 +"; |
| 7145 |
goto EXPAND_FAILED; |
7317 |
goto EXPAND_FAILED; |
|
Lines 7148-7307
Link Here
|
| 7148 |
/* Convert hex encoding to base64 encoding */ |
7320 |
/* Convert hex encoding to base64 encoding */ |
| 7149 |
|
7321 |
|
| 7150 |
case EOP_HEX2B64: |
7322 |
case EOP_HEX2B64: |
| 7151 |
{ |
7323 |
{ |
| 7152 |
int c = 0; |
7324 |
int c = 0; |
| 7153 |
int b = -1; |
7325 |
int b = -1; |
| 7154 |
uschar *in = sub; |
7326 |
uschar *in = sub; |
| 7155 |
uschar *out = sub; |
7327 |
uschar *out = sub; |
| 7156 |
uschar *enc; |
7328 |
uschar *enc; |
| 7157 |
|
7329 |
|
| 7158 |
for (enc = sub; *enc; enc++) |
7330 |
for (enc = sub; *enc; enc++) |
| 7159 |
{ |
7331 |
{ |
| 7160 |
if (!isxdigit(*enc)) |
7332 |
if (!isxdigit(*enc)) |
| 7161 |
{ |
7333 |
{ |
| 7162 |
expand_string_message = string_sprintf("\"%s\" is not a hex " |
7334 |
expand_string_message = string_sprintf("\"%s\" is not a hex " |
| 7163 |
"string", sub); |
7335 |
"string", sub); |
| 7164 |
goto EXPAND_FAILED; |
7336 |
goto EXPAND_FAILED; |
| 7165 |
} |
7337 |
} |
| 7166 |
c++; |
7338 |
c++; |
| 7167 |
} |
7339 |
} |
| 7168 |
|
7340 |
|
| 7169 |
if ((c & 1) != 0) |
7341 |
if ((c & 1) != 0) |
| 7170 |
{ |
7342 |
{ |
| 7171 |
expand_string_message = string_sprintf("\"%s\" contains an odd " |
7343 |
expand_string_message = string_sprintf("\"%s\" contains an odd " |
| 7172 |
"number of characters", sub); |
7344 |
"number of characters", sub); |
| 7173 |
goto EXPAND_FAILED; |
7345 |
goto EXPAND_FAILED; |
| 7174 |
} |
7346 |
} |
| 7175 |
|
7347 |
|
| 7176 |
while ((c = *in++) != 0) |
7348 |
while ((c = *in++) != 0) |
| 7177 |
{ |
7349 |
{ |
| 7178 |
if (isdigit(c)) c -= '0'; |
7350 |
if (isdigit(c)) c -= '0'; |
| 7179 |
else c = toupper(c) - 'A' + 10; |
7351 |
else c = toupper(c) - 'A' + 10; |
| 7180 |
if (b == -1) |
7352 |
if (b == -1) |
| 7181 |
b = c << 4; |
7353 |
b = c << 4; |
| 7182 |
else |
7354 |
else |
| 7183 |
{ |
7355 |
{ |
| 7184 |
*out++ = b | c; |
7356 |
*out++ = b | c; |
| 7185 |
b = -1; |
7357 |
b = -1; |
| 7186 |
} |
7358 |
} |
| 7187 |
} |
7359 |
} |
| 7188 |
|
7360 |
|
| 7189 |
enc = b64encode(CUS sub, out - sub); |
7361 |
enc = b64encode(CUS sub, out - sub); |
| 7190 |
yield = string_cat(yield, enc); |
7362 |
yield = string_cat(yield, enc); |
| 7191 |
continue; |
7363 |
break; |
| 7192 |
} |
7364 |
} |
| 7193 |
|
7365 |
|
| 7194 |
/* Convert octets outside 0x21..0x7E to \xXX form */ |
7366 |
/* Convert octets outside 0x21..0x7E to \xXX form */ |
| 7195 |
|
7367 |
|
| 7196 |
case EOP_HEXQUOTE: |
7368 |
case EOP_HEXQUOTE: |
| 7197 |
{ |
7369 |
{ |
| 7198 |
uschar *t = sub - 1; |
7370 |
uschar *t = sub - 1; |
| 7199 |
while (*(++t) != 0) |
7371 |
while (*(++t) != 0) |
| 7200 |
{ |
7372 |
{ |
| 7201 |
if (*t < 0x21 || 0x7E < *t) |
7373 |
if (*t < 0x21 || 0x7E < *t) |
| 7202 |
yield = string_fmt_append(yield, "\\x%02x", *t); |
7374 |
yield = string_fmt_append(yield, "\\x%02x", *t); |
| 7203 |
else |
7375 |
else |
| 7204 |
yield = string_catn(yield, t, 1); |
7376 |
yield = string_catn(yield, t, 1); |
| 7205 |
} |
7377 |
} |
| 7206 |
continue; |
7378 |
break; |
| 7207 |
} |
7379 |
} |
| 7208 |
|
7380 |
|
| 7209 |
/* count the number of list elements */ |
7381 |
/* count the number of list elements */ |
| 7210 |
|
7382 |
|
| 7211 |
case EOP_LISTCOUNT: |
7383 |
case EOP_LISTCOUNT: |
| 7212 |
{ |
7384 |
{ |
| 7213 |
int cnt = 0; |
7385 |
int cnt = 0, sep = 0; |
| 7214 |
int sep = 0; |
7386 |
uschar * buf = store_get(2, sub); |
| 7215 |
|
7387 |
|
| 7216 |
while (string_nextinlist(CUSS &sub, &sep, NULL, 0)) cnt++; |
7388 |
while (string_nextinlist(CUSS &sub, &sep, buf, 1)) cnt++; |
| 7217 |
yield = string_fmt_append(yield, "%d", cnt); |
7389 |
yield = string_fmt_append(yield, "%d", cnt); |
| 7218 |
continue; |
7390 |
break; |
| 7219 |
} |
7391 |
} |
| 7220 |
|
7392 |
|
| 7221 |
/* expand a named list given the name */ |
7393 |
/* expand a named list given the name */ |
| 7222 |
/* handles nested named lists; requotes as colon-sep list */ |
7394 |
/* handles nested named lists; requotes as colon-sep list */ |
| 7223 |
|
7395 |
|
| 7224 |
case EOP_LISTNAMED: |
7396 |
case EOP_LISTNAMED: |
| 7225 |
{ |
7397 |
expand_string_message = NULL; |
| 7226 |
tree_node *t = NULL; |
7398 |
yield = expand_listnamed(yield, sub, arg); |
| 7227 |
const uschar * list; |
7399 |
if (expand_string_message) |
| 7228 |
int sep = 0; |
|
|
| 7229 |
uschar * item; |
| 7230 |
uschar * suffix = US""; |
| 7231 |
BOOL needsep = FALSE; |
| 7232 |
uschar buffer[256]; |
| 7233 |
|
| 7234 |
if (*sub == '+') sub++; |
| 7235 |
if (!arg) /* no-argument version */ |
| 7236 |
{ |
| 7237 |
if (!(t = tree_search(addresslist_anchor, sub)) && |
| 7238 |
!(t = tree_search(domainlist_anchor, sub)) && |
| 7239 |
!(t = tree_search(hostlist_anchor, sub))) |
| 7240 |
t = tree_search(localpartlist_anchor, sub); |
| 7241 |
} |
| 7242 |
else switch(*arg) /* specific list-type version */ |
| 7243 |
{ |
| 7244 |
case 'a': t = tree_search(addresslist_anchor, sub); suffix = US"_a"; break; |
| 7245 |
case 'd': t = tree_search(domainlist_anchor, sub); suffix = US"_d"; break; |
| 7246 |
case 'h': t = tree_search(hostlist_anchor, sub); suffix = US"_h"; break; |
| 7247 |
case 'l': t = tree_search(localpartlist_anchor, sub); suffix = US"_l"; break; |
| 7248 |
default: |
| 7249 |
expand_string_message = US"bad suffix on \"list\" operator"; |
| 7250 |
goto EXPAND_FAILED; |
| 7251 |
} |
| 7252 |
|
| 7253 |
if(!t) |
| 7254 |
{ |
| 7255 |
expand_string_message = string_sprintf("\"%s\" is not a %snamed list", |
| 7256 |
sub, !arg?"" |
| 7257 |
: *arg=='a'?"address " |
| 7258 |
: *arg=='d'?"domain " |
| 7259 |
: *arg=='h'?"host " |
| 7260 |
: *arg=='l'?"localpart " |
| 7261 |
: 0); |
| 7262 |
goto EXPAND_FAILED; |
7400 |
goto EXPAND_FAILED; |
| 7263 |
} |
7401 |
break; |
| 7264 |
|
|
|
| 7265 |
list = ((namedlist_block *)(t->data.ptr))->string; |
| 7266 |
|
| 7267 |
while ((item = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) |
| 7268 |
{ |
| 7269 |
uschar * buf = US" : "; |
| 7270 |
if (needsep) |
| 7271 |
yield = string_catn(yield, buf, 3); |
| 7272 |
else |
| 7273 |
needsep = TRUE; |
| 7274 |
|
| 7275 |
if (*item == '+') /* list item is itself a named list */ |
| 7276 |
{ |
| 7277 |
uschar * sub = string_sprintf("${listnamed%s:%s}", suffix, item); |
| 7278 |
item = expand_string_internal(sub, FALSE, NULL, FALSE, TRUE, &resetok); |
| 7279 |
} |
| 7280 |
else if (sep != ':') /* item from non-colon-sep list, re-quote for colon list-separator */ |
| 7281 |
{ |
| 7282 |
char * cp; |
| 7283 |
char tok[3]; |
| 7284 |
tok[0] = sep; tok[1] = ':'; tok[2] = 0; |
| 7285 |
while ((cp= strpbrk(CCS item, tok))) |
| 7286 |
{ |
| 7287 |
yield = string_catn(yield, item, cp - CS item); |
| 7288 |
if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */ |
| 7289 |
{ |
| 7290 |
yield = string_catn(yield, US"::", 2); |
| 7291 |
item = US cp; |
| 7292 |
} |
| 7293 |
else /* sep in item; should already be doubled; emit once */ |
| 7294 |
{ |
| 7295 |
yield = string_catn(yield, US tok, 1); |
| 7296 |
if (*cp == sep) cp++; |
| 7297 |
item = US cp; |
| 7298 |
} |
| 7299 |
} |
| 7300 |
} |
| 7301 |
yield = string_cat(yield, item); |
| 7302 |
} |
| 7303 |
continue; |
| 7304 |
} |
| 7305 |
|
7402 |
|
| 7306 |
/* quote a list-item for the given list-separator */ |
7403 |
/* quote a list-item for the given list-separator */ |
| 7307 |
|
7404 |
|
|
Lines 7309-7362
Link Here
|
| 7309 |
${mask:131.111.10.206/28} is 131.111.10.192/28. */ |
7406 |
${mask:131.111.10.206/28} is 131.111.10.192/28. */ |
| 7310 |
|
7407 |
|
| 7311 |
case EOP_MASK: |
7408 |
case EOP_MASK: |
| 7312 |
{ |
7409 |
{ |
| 7313 |
int count; |
7410 |
int count; |
| 7314 |
uschar *endptr; |
7411 |
uschar *endptr; |
| 7315 |
int binary[4]; |
7412 |
int binary[4]; |
| 7316 |
int mask, maskoffset; |
7413 |
int type, mask, maskoffset; |
| 7317 |
int type = string_is_ip_address(sub, &maskoffset); |
7414 |
BOOL normalised; |
| 7318 |
uschar buffer[64]; |
7415 |
uschar buffer[64]; |
| 7319 |
|
7416 |
|
| 7320 |
if (type == 0) |
7417 |
if ((type = string_is_ip_address(sub, &maskoffset)) == 0) |
| 7321 |
{ |
7418 |
{ |
| 7322 |
expand_string_message = string_sprintf("\"%s\" is not an IP address", |
7419 |
expand_string_message = string_sprintf("\"%s\" is not an IP address", |
| 7323 |
sub); |
7420 |
sub); |
| 7324 |
goto EXPAND_FAILED; |
7421 |
goto EXPAND_FAILED; |
| 7325 |
} |
7422 |
} |
| 7326 |
|
7423 |
|
| 7327 |
if (maskoffset == 0) |
7424 |
if (maskoffset == 0) |
| 7328 |
{ |
7425 |
{ |
| 7329 |
expand_string_message = string_sprintf("missing mask value in \"%s\"", |
7426 |
expand_string_message = string_sprintf("missing mask value in \"%s\"", |
| 7330 |
sub); |
7427 |
sub); |
| 7331 |
goto EXPAND_FAILED; |
7428 |
goto EXPAND_FAILED; |
| 7332 |
} |
7429 |
} |
| 7333 |
|
7430 |
|
| 7334 |
mask = Ustrtol(sub + maskoffset + 1, &endptr, 10); |
7431 |
mask = Ustrtol(sub + maskoffset + 1, &endptr, 10); |
| 7335 |
|
7432 |
|
| 7336 |
if (*endptr != 0 || mask < 0 || mask > ((type == 4)? 32 : 128)) |
7433 |
if (*endptr || mask < 0 || mask > (type == 4 ? 32 : 128)) |
| 7337 |
{ |
7434 |
{ |
| 7338 |
expand_string_message = string_sprintf("mask value too big in \"%s\"", |
7435 |
expand_string_message = string_sprintf("mask value too big in \"%s\"", |
| 7339 |
sub); |
7436 |
sub); |
| 7340 |
goto EXPAND_FAILED; |
7437 |
goto EXPAND_FAILED; |
| 7341 |
} |
7438 |
} |
| 7342 |
|
7439 |
|
| 7343 |
/* Convert the address to binary integer(s) and apply the mask */ |
7440 |
/* If an optional 'n' was given, ipv6 gets normalised output: |
|
|
7441 |
colons rather than dots, and zero-compressed. */ |
| 7344 |
|
7442 |
|
| 7345 |
sub[maskoffset] = 0; |
7443 |
normalised = arg && *arg == 'n'; |
| 7346 |
count = host_aton(sub, binary); |
|
|
| 7347 |
host_mask(count, binary, mask); |
| 7348 |
|
7444 |
|
| 7349 |
/* Convert to masked textual format and add to output. */ |
7445 |
/* Convert the address to binary integer(s) and apply the mask */ |
| 7350 |
|
7446 |
|
| 7351 |
yield = string_catn(yield, buffer, |
7447 |
sub[maskoffset] = 0; |
| 7352 |
host_nmtoa(count, binary, mask, buffer, '.')); |
7448 |
count = host_aton(sub, binary); |
| 7353 |
continue; |
7449 |
host_mask(count, binary, mask); |
| 7354 |
} |
7450 |
|
|
|
7451 |
/* Convert to masked textual format and add to output. */ |
| 7452 |
|
| 7453 |
if (type == 4 || !normalised) |
| 7454 |
yield = string_catn(yield, buffer, |
| 7455 |
host_nmtoa(count, binary, mask, buffer, '.')); |
| 7456 |
else |
| 7457 |
{ |
| 7458 |
ipv6_nmtoa(binary, buffer); |
| 7459 |
yield = string_fmt_append(yield, "%s/%d", buffer, mask); |
| 7460 |
} |
| 7461 |
break; |
| 7462 |
} |
| 7355 |
|
7463 |
|
| 7356 |
case EOP_IPV6NORM: |
7464 |
case EOP_IPV6NORM: |
| 7357 |
case EOP_IPV6DENORM: |
7465 |
case EOP_IPV6DENORM: |
| 7358 |
{ |
7466 |
{ |
| 7359 |
int type = string_is_ip_address(sub, NULL); |
7467 |
int type = string_is_ip_address(sub, NULL); |
| 7360 |
int binary[4]; |
7468 |
int binary[4]; |
| 7361 |
uschar buffer[44]; |
7469 |
uschar buffer[44]; |
| 7362 |
|
7470 |
|
|
Lines 7382-7475
Link Here
|
| 7382 |
? ipv6_nmtoa(binary, buffer) |
7490 |
? ipv6_nmtoa(binary, buffer) |
| 7383 |
: host_nmtoa(4, binary, -1, buffer, ':') |
7491 |
: host_nmtoa(4, binary, -1, buffer, ':') |
| 7384 |
); |
7492 |
); |
| 7385 |
continue; |
7493 |
break; |
| 7386 |
} |
7494 |
} |
| 7387 |
|
7495 |
|
| 7388 |
case EOP_ADDRESS: |
7496 |
case EOP_ADDRESS: |
| 7389 |
case EOP_LOCAL_PART: |
7497 |
case EOP_LOCAL_PART: |
| 7390 |
case EOP_DOMAIN: |
7498 |
case EOP_DOMAIN: |
| 7391 |
{ |
7499 |
{ |
| 7392 |
uschar * error; |
7500 |
uschar * error; |
| 7393 |
int start, end, domain; |
7501 |
int start, end, domain; |
| 7394 |
uschar * t = parse_extract_address(sub, &error, &start, &end, &domain, |
7502 |
uschar * t = parse_extract_address(sub, &error, &start, &end, &domain, |
| 7395 |
FALSE); |
7503 |
FALSE); |
| 7396 |
if (t) |
7504 |
if (t) |
| 7397 |
if (c != EOP_DOMAIN) |
7505 |
if (c != EOP_DOMAIN) |
| 7398 |
yield = c == EOP_LOCAL_PART && domain > 0 |
7506 |
yield = c == EOP_LOCAL_PART && domain > 0 |
| 7399 |
? string_catn(yield, t, domain - 1) |
7507 |
? string_catn(yield, t, domain - 1) |
| 7400 |
: string_cat(yield, t); |
7508 |
: string_cat(yield, t); |
| 7401 |
else if (domain > 0) |
7509 |
else if (domain > 0) |
| 7402 |
yield = string_cat(yield, t + domain); |
7510 |
yield = string_cat(yield, t + domain); |
| 7403 |
continue; |
7511 |
break; |
| 7404 |
} |
7512 |
} |
| 7405 |
|
7513 |
|
| 7406 |
case EOP_ADDRESSES: |
7514 |
case EOP_ADDRESSES: |
| 7407 |
{ |
7515 |
{ |
| 7408 |
uschar outsep[2] = { ':', '\0' }; |
7516 |
uschar outsep[2] = { ':', '\0' }; |
| 7409 |
uschar *address, *error; |
7517 |
uschar *address, *error; |
| 7410 |
int save_ptr = gstring_length(yield); |
7518 |
int save_ptr = gstring_length(yield); |
| 7411 |
int start, end, domain; /* Not really used */ |
7519 |
int start, end, domain; /* Not really used */ |
| 7412 |
|
7520 |
|
| 7413 |
if (Uskip_whitespace(&sub) == '>') |
7521 |
if (Uskip_whitespace(&sub) == '>') |
| 7414 |
if (*outsep = *++sub) ++sub; |
7522 |
if (*outsep = *++sub) ++sub; |
| 7415 |
else |
7523 |
else |
| 7416 |
{ |
7524 |
{ |
| 7417 |
expand_string_message = string_sprintf("output separator " |
7525 |
expand_string_message = string_sprintf("output separator " |
| 7418 |
"missing in expanding ${addresses:%s}", --sub); |
7526 |
"missing in expanding ${addresses:%s}", --sub); |
| 7419 |
goto EXPAND_FAILED; |
7527 |
goto EXPAND_FAILED; |
| 7420 |
} |
7528 |
} |
| 7421 |
f.parse_allow_group = TRUE; |
7529 |
f.parse_allow_group = TRUE; |
| 7422 |
|
7530 |
|
| 7423 |
for (;;) |
7531 |
for (;;) |
| 7424 |
{ |
7532 |
{ |
| 7425 |
uschar * p = parse_find_address_end(sub, FALSE); |
7533 |
uschar * p = parse_find_address_end(sub, FALSE); |
| 7426 |
uschar saveend = *p; |
7534 |
uschar saveend = *p; |
| 7427 |
*p = '\0'; |
7535 |
*p = '\0'; |
| 7428 |
address = parse_extract_address(sub, &error, &start, &end, &domain, |
7536 |
address = parse_extract_address(sub, &error, &start, &end, &domain, |
| 7429 |
FALSE); |
7537 |
FALSE); |
| 7430 |
*p = saveend; |
7538 |
*p = saveend; |
| 7431 |
|
7539 |
|
| 7432 |
/* Add the address to the output list that we are building. This is |
7540 |
/* Add the address to the output list that we are building. This is |
| 7433 |
done in chunks by searching for the separator character. At the |
7541 |
done in chunks by searching for the separator character. At the |
| 7434 |
start, unless we are dealing with the first address of the output |
7542 |
start, unless we are dealing with the first address of the output |
| 7435 |
list, add in a space if the new address begins with the separator |
7543 |
list, add in a space if the new address begins with the separator |
| 7436 |
character, or is an empty string. */ |
7544 |
character, or is an empty string. */ |
| 7437 |
|
7545 |
|
| 7438 |
if (address) |
7546 |
if (address) |
| 7439 |
{ |
7547 |
{ |
| 7440 |
if (yield && yield->ptr != save_ptr && address[0] == *outsep) |
7548 |
if (yield && yield->ptr != save_ptr && address[0] == *outsep) |
| 7441 |
yield = string_catn(yield, US" ", 1); |
7549 |
yield = string_catn(yield, US" ", 1); |
| 7442 |
|
7550 |
|
| 7443 |
for (;;) |
7551 |
for (;;) |
| 7444 |
{ |
7552 |
{ |
| 7445 |
size_t seglen = Ustrcspn(address, outsep); |
7553 |
size_t seglen = Ustrcspn(address, outsep); |
| 7446 |
yield = string_catn(yield, address, seglen + 1); |
7554 |
yield = string_catn(yield, address, seglen + 1); |
| 7447 |
|
|
|
| 7448 |
/* If we got to the end of the string we output one character |
| 7449 |
too many. */ |
| 7450 |
|
| 7451 |
if (address[seglen] == '\0') { yield->ptr--; break; } |
| 7452 |
yield = string_catn(yield, outsep, 1); |
| 7453 |
address += seglen + 1; |
| 7454 |
} |
| 7455 |
|
7555 |
|
| 7456 |
/* Output a separator after the string: we will remove the |
7556 |
/* If we got to the end of the string we output one character |
| 7457 |
redundant final one at the end. */ |
7557 |
too many. */ |
| 7458 |
|
7558 |
|
| 7459 |
yield = string_catn(yield, outsep, 1); |
7559 |
if (address[seglen] == '\0') { yield->ptr--; break; } |
| 7460 |
} |
7560 |
yield = string_catn(yield, outsep, 1); |
|
|
7561 |
address += seglen + 1; |
| 7562 |
} |
| 7461 |
|
7563 |
|
| 7462 |
if (saveend == '\0') break; |
7564 |
/* Output a separator after the string: we will remove the |
| 7463 |
sub = p + 1; |
7565 |
redundant final one at the end. */ |
| 7464 |
} |
|
|
| 7465 |
|
7566 |
|
| 7466 |
/* If we have generated anything, remove the redundant final |
7567 |
yield = string_catn(yield, outsep, 1); |
| 7467 |
separator. */ |
7568 |
} |
| 7468 |
|
7569 |
|
| 7469 |
if (yield && yield->ptr != save_ptr) yield->ptr--; |
7570 |
if (saveend == '\0') break; |
| 7470 |
f.parse_allow_group = FALSE; |
7571 |
sub = p + 1; |
| 7471 |
continue; |
7572 |
} |
| 7472 |
} |
7573 |
|
|
|
7574 |
/* If we have generated anything, remove the redundant final |
| 7575 |
separator. */ |
| 7576 |
|
| 7577 |
if (yield && yield->ptr != save_ptr) yield->ptr--; |
| 7578 |
f.parse_allow_group = FALSE; |
| 7579 |
break; |
| 7580 |
} |
| 7473 |
|
7581 |
|
| 7474 |
|
7582 |
|
| 7475 |
/* quote puts a string in quotes if it is empty or contains anything |
7583 |
/* quote puts a string in quotes if it is empty or contains anything |
|
Lines 7483-8068
Link Here
|
| 7483 |
|
7591 |
|
| 7484 |
case EOP_QUOTE: |
7592 |
case EOP_QUOTE: |
| 7485 |
case EOP_QUOTE_LOCAL_PART: |
7593 |
case EOP_QUOTE_LOCAL_PART: |
| 7486 |
if (!arg) |
7594 |
if (!arg) |
| 7487 |
{ |
7595 |
{ |
| 7488 |
BOOL needs_quote = (!*sub); /* TRUE for empty string */ |
7596 |
BOOL needs_quote = (!*sub); /* TRUE for empty string */ |
| 7489 |
uschar *t = sub - 1; |
7597 |
uschar *t = sub - 1; |
| 7490 |
|
|
|
| 7491 |
if (c == EOP_QUOTE) |
| 7492 |
{ |
| 7493 |
while (!needs_quote && *(++t) != 0) |
| 7494 |
needs_quote = !isalnum(*t) && !strchr("_-.", *t); |
| 7495 |
} |
| 7496 |
else /* EOP_QUOTE_LOCAL_PART */ |
| 7497 |
{ |
| 7498 |
while (!needs_quote && *(++t) != 0) |
| 7499 |
needs_quote = !isalnum(*t) && |
| 7500 |
strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL && |
| 7501 |
(*t != '.' || t == sub || t[1] == 0); |
| 7502 |
} |
| 7503 |
|
7598 |
|
| 7504 |
if (needs_quote) |
7599 |
if (c == EOP_QUOTE) |
| 7505 |
{ |
7600 |
while (!needs_quote && *++t) |
| 7506 |
yield = string_catn(yield, US"\"", 1); |
7601 |
needs_quote = !isalnum(*t) && !strchr("_-.", *t); |
| 7507 |
t = sub - 1; |
7602 |
|
| 7508 |
while (*(++t) != 0) |
7603 |
else /* EOP_QUOTE_LOCAL_PART */ |
| 7509 |
{ |
7604 |
while (!needs_quote && *++t) |
| 7510 |
if (*t == '\n') |
7605 |
needs_quote = !isalnum(*t) |
| 7511 |
yield = string_catn(yield, US"\\n", 2); |
7606 |
&& strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL |
| 7512 |
else if (*t == '\r') |
7607 |
&& (*t != '.' || t == sub || !t[1]); |
| 7513 |
yield = string_catn(yield, US"\\r", 2); |
|
|
| 7514 |
else |
| 7515 |
{ |
| 7516 |
if (*t == '\\' || *t == '"') |
| 7517 |
yield = string_catn(yield, US"\\", 1); |
| 7518 |
yield = string_catn(yield, t, 1); |
| 7519 |
} |
| 7520 |
} |
| 7521 |
yield = string_catn(yield, US"\"", 1); |
| 7522 |
} |
| 7523 |
else yield = string_cat(yield, sub); |
| 7524 |
continue; |
| 7525 |
} |
| 7526 |
|
7608 |
|
| 7527 |
/* quote_lookuptype does lookup-specific quoting */ |
7609 |
if (needs_quote) |
|
|
7610 |
{ |
| 7611 |
yield = string_catn(yield, US"\"", 1); |
| 7612 |
t = sub - 1; |
| 7613 |
while (*++t) |
| 7614 |
if (*t == '\n') |
| 7615 |
yield = string_catn(yield, US"\\n", 2); |
| 7616 |
else if (*t == '\r') |
| 7617 |
yield = string_catn(yield, US"\\r", 2); |
| 7618 |
else |
| 7619 |
{ |
| 7620 |
if (*t == '\\' || *t == '"') |
| 7621 |
yield = string_catn(yield, US"\\", 1); |
| 7622 |
yield = string_catn(yield, t, 1); |
| 7623 |
} |
| 7624 |
yield = string_catn(yield, US"\"", 1); |
| 7625 |
} |
| 7626 |
else |
| 7627 |
yield = string_cat(yield, sub); |
| 7628 |
break; |
| 7629 |
} |
| 7528 |
|
7630 |
|
| 7529 |
else |
7631 |
/* quote_lookuptype does lookup-specific quoting */ |
| 7530 |
{ |
|
|
| 7531 |
int n; |
| 7532 |
uschar *opt = Ustrchr(arg, '_'); |
| 7533 |
|
7632 |
|
| 7534 |
if (opt) *opt++ = 0; |
7633 |
else |
|
|
7634 |
{ |
| 7635 |
int n; |
| 7636 |
uschar * opt = Ustrchr(arg, '_'); |
| 7535 |
|
7637 |
|
| 7536 |
if ((n = search_findtype(arg, Ustrlen(arg))) < 0) |
7638 |
if (opt) *opt++ = 0; |
| 7537 |
{ |
|
|
| 7538 |
expand_string_message = search_error_message; |
| 7539 |
goto EXPAND_FAILED; |
| 7540 |
} |
| 7541 |
|
7639 |
|
| 7542 |
if (lookup_list[n]->quote) |
7640 |
if ((n = search_findtype(arg, Ustrlen(arg))) < 0) |
| 7543 |
sub = (lookup_list[n]->quote)(sub, opt); |
7641 |
{ |
| 7544 |
else if (opt) |
7642 |
expand_string_message = search_error_message; |
| 7545 |
sub = NULL; |
7643 |
goto EXPAND_FAILED; |
|
|
7644 |
} |
| 7546 |
|
7645 |
|
| 7547 |
if (!sub) |
7646 |
if (lookup_list[n]->quote) |
| 7548 |
{ |
7647 |
sub = (lookup_list[n]->quote)(sub, opt, (unsigned)n); |
| 7549 |
expand_string_message = string_sprintf( |
7648 |
else if (opt) |
| 7550 |
"\"%s\" unrecognized after \"${quote_%s\"", |
7649 |
sub = NULL; |
| 7551 |
opt, arg); |
|
|
| 7552 |
goto EXPAND_FAILED; |
| 7553 |
} |
| 7554 |
|
7650 |
|
| 7555 |
yield = string_cat(yield, sub); |
7651 |
if (!sub) |
| 7556 |
continue; |
7652 |
{ |
| 7557 |
} |
7653 |
expand_string_message = string_sprintf( |
|
|
7654 |
"\"%s\" unrecognized after \"${quote_%s\"", /*}*/ |
| 7655 |
opt, arg); |
| 7656 |
goto EXPAND_FAILED; |
| 7657 |
} |
| 7558 |
|
7658 |
|
| 7559 |
/* rx quote sticks in \ before any non-alphameric character so that |
7659 |
yield = string_cat(yield, sub); |
| 7560 |
the insertion works in a regular expression. */ |
7660 |
break; |
|
|
7661 |
} |
| 7561 |
|
7662 |
|
| 7562 |
case EOP_RXQUOTE: |
7663 |
/* rx quote sticks in \ before any non-alphameric character so that |
| 7563 |
{ |
7664 |
the insertion works in a regular expression. */ |
| 7564 |
uschar *t = sub - 1; |
|
|
| 7565 |
while (*(++t) != 0) |
| 7566 |
{ |
| 7567 |
if (!isalnum(*t)) |
| 7568 |
yield = string_catn(yield, US"\\", 1); |
| 7569 |
yield = string_catn(yield, t, 1); |
| 7570 |
} |
| 7571 |
continue; |
| 7572 |
} |
| 7573 |
|
7665 |
|
| 7574 |
/* RFC 2047 encodes, assuming headers_charset (default ISO 8859-1) as |
7666 |
case EOP_RXQUOTE: |
| 7575 |
prescribed by the RFC, if there are characters that need to be encoded */ |
7667 |
{ |
|
|
7668 |
uschar *t = sub - 1; |
| 7669 |
while (*(++t) != 0) |
| 7670 |
{ |
| 7671 |
if (!isalnum(*t)) |
| 7672 |
yield = string_catn(yield, US"\\", 1); |
| 7673 |
yield = string_catn(yield, t, 1); |
| 7674 |
} |
| 7675 |
break; |
| 7676 |
} |
| 7576 |
|
7677 |
|
| 7577 |
case EOP_RFC2047: |
7678 |
/* RFC 2047 encodes, assuming headers_charset (default ISO 8859-1) as |
| 7578 |
yield = string_cat(yield, |
7679 |
prescribed by the RFC, if there are characters that need to be encoded */ |
| 7579 |
parse_quote_2047(sub, Ustrlen(sub), headers_charset, |
|
|
| 7580 |
FALSE)); |
| 7581 |
continue; |
| 7582 |
|
7680 |
|
| 7583 |
/* RFC 2047 decode */ |
7681 |
case EOP_RFC2047: |
|
|
7682 |
yield = string_cat(yield, |
| 7683 |
parse_quote_2047(sub, Ustrlen(sub), headers_charset, |
| 7684 |
FALSE)); |
| 7685 |
break; |
| 7584 |
|
7686 |
|
| 7585 |
case EOP_RFC2047D: |
7687 |
/* RFC 2047 decode */ |
| 7586 |
{ |
|
|
| 7587 |
int len; |
| 7588 |
uschar *error; |
| 7589 |
uschar *decoded = rfc2047_decode(sub, check_rfc2047_length, |
| 7590 |
headers_charset, '?', &len, &error); |
| 7591 |
if (error) |
| 7592 |
{ |
| 7593 |
expand_string_message = error; |
| 7594 |
goto EXPAND_FAILED; |
| 7595 |
} |
| 7596 |
yield = string_catn(yield, decoded, len); |
| 7597 |
continue; |
| 7598 |
} |
| 7599 |
|
7688 |
|
| 7600 |
/* from_utf8 converts UTF-8 to 8859-1, turning non-existent chars into |
7689 |
case EOP_RFC2047D: |
| 7601 |
underscores */ |
7690 |
{ |
|
|
7691 |
int len; |
| 7692 |
uschar *error; |
| 7693 |
uschar *decoded = rfc2047_decode(sub, check_rfc2047_length, |
| 7694 |
headers_charset, '?', &len, &error); |
| 7695 |
if (error) |
| 7696 |
{ |
| 7697 |
expand_string_message = error; |
| 7698 |
goto EXPAND_FAILED; |
| 7699 |
} |
| 7700 |
yield = string_catn(yield, decoded, len); |
| 7701 |
break; |
| 7702 |
} |
| 7602 |
|
7703 |
|
| 7603 |
case EOP_FROM_UTF8: |
7704 |
/* from_utf8 converts UTF-8 to 8859-1, turning non-existent chars into |
| 7604 |
{ |
7705 |
underscores */ |
| 7605 |
uschar * buff = store_get(4, is_tainted(sub)); |
|
|
| 7606 |
while (*sub) |
| 7607 |
{ |
| 7608 |
int c; |
| 7609 |
GETUTF8INC(c, sub); |
| 7610 |
if (c > 255) c = '_'; |
| 7611 |
buff[0] = c; |
| 7612 |
yield = string_catn(yield, buff, 1); |
| 7613 |
} |
| 7614 |
continue; |
| 7615 |
} |
| 7616 |
|
7706 |
|
| 7617 |
/* replace illegal UTF-8 sequences by replacement character */ |
7707 |
case EOP_FROM_UTF8: |
|
|
7708 |
{ |
| 7709 |
uschar * buff = store_get(4, sub); |
| 7710 |
while (*sub) |
| 7711 |
{ |
| 7712 |
int c; |
| 7713 |
GETUTF8INC(c, sub); |
| 7714 |
if (c > 255) c = '_'; |
| 7715 |
buff[0] = c; |
| 7716 |
yield = string_catn(yield, buff, 1); |
| 7717 |
} |
| 7718 |
break; |
| 7719 |
} |
| 7618 |
|
7720 |
|
| 7619 |
#define UTF8_REPLACEMENT_CHAR US"?" |
7721 |
/* replace illegal UTF-8 sequences by replacement character */ |
| 7620 |
|
7722 |
|
| 7621 |
case EOP_UTF8CLEAN: |
7723 |
#define UTF8_REPLACEMENT_CHAR US"?" |
| 7622 |
{ |
|
|
| 7623 |
int seq_len = 0, index = 0; |
| 7624 |
int bytes_left = 0; |
| 7625 |
long codepoint = -1; |
| 7626 |
int complete; |
| 7627 |
uschar seq_buff[4]; /* accumulate utf-8 here */ |
| 7628 |
|
7724 |
|
| 7629 |
/* Manually track tainting, as we deal in individual chars below */ |
7725 |
case EOP_UTF8CLEAN: |
|
|
7726 |
{ |
| 7727 |
int seq_len = 0, index = 0; |
| 7728 |
int bytes_left = 0; |
| 7729 |
long codepoint = -1; |
| 7730 |
int complete; |
| 7731 |
uschar seq_buff[4]; /* accumulate utf-8 here */ |
| 7630 |
|
7732 |
|
| 7631 |
if (is_tainted(sub)) |
7733 |
/* Manually track tainting, as we deal in individual chars below */ |
| 7632 |
if (yield->s && yield->ptr) |
|
|
| 7633 |
gstring_rebuffer(yield); |
| 7634 |
else |
| 7635 |
yield->s = store_get(yield->size = Ustrlen(sub), TRUE); |
| 7636 |
|
7734 |
|
| 7637 |
/* Check the UTF-8, byte-by-byte */ |
7735 |
if (!yield->s || !yield->ptr) |
|
|
7736 |
yield->s = store_get(yield->size = Ustrlen(sub), sub); |
| 7737 |
else if (is_incompatible(yield->s, sub)) |
| 7738 |
gstring_rebuffer(yield, sub); |
| 7638 |
|
7739 |
|
| 7639 |
while (*sub) |
7740 |
/* Check the UTF-8, byte-by-byte */ |
| 7640 |
{ |
|
|
| 7641 |
complete = 0; |
| 7642 |
uschar c = *sub++; |
| 7643 |
|
7741 |
|
| 7644 |
if (bytes_left) |
7742 |
while (*sub) |
| 7645 |
{ |
7743 |
{ |
| 7646 |
if ((c & 0xc0) != 0x80) |
7744 |
complete = 0; |
| 7647 |
/* wrong continuation byte; invalidate all bytes */ |
7745 |
uschar c = *sub++; |
| 7648 |
complete = 1; /* error */ |
7746 |
|
| 7649 |
else |
7747 |
if (bytes_left) |
| 7650 |
{ |
|
|
| 7651 |
codepoint = (codepoint << 6) | (c & 0x3f); |
| 7652 |
seq_buff[index++] = c; |
| 7653 |
if (--bytes_left == 0) /* codepoint complete */ |
| 7654 |
if(codepoint > 0x10FFFF) /* is it too large? */ |
| 7655 |
complete = -1; /* error (RFC3629 limit) */ |
| 7656 |
else |
| 7657 |
{ /* finished; output utf-8 sequence */ |
| 7658 |
yield = string_catn(yield, seq_buff, seq_len); |
| 7659 |
index = 0; |
| 7660 |
} |
| 7661 |
} |
| 7662 |
} |
| 7663 |
else /* no bytes left: new sequence */ |
| 7664 |
{ |
| 7665 |
if(!(c & 0x80)) /* 1-byte sequence, US-ASCII, keep it */ |
| 7666 |
{ |
| 7667 |
yield = string_catn(yield, &c, 1); |
| 7668 |
continue; |
| 7669 |
} |
| 7670 |
if((c & 0xe0) == 0xc0) /* 2-byte sequence */ |
| 7671 |
{ |
7748 |
{ |
| 7672 |
if(c == 0xc0 || c == 0xc1) /* 0xc0 and 0xc1 are illegal */ |
7749 |
if ((c & 0xc0) != 0x80) |
| 7673 |
complete = -1; |
7750 |
/* wrong continuation byte; invalidate all bytes */ |
|
|
7751 |
complete = 1; /* error */ |
| 7674 |
else |
7752 |
else |
| 7675 |
{ |
7753 |
{ |
| 7676 |
bytes_left = 1; |
7754 |
codepoint = (codepoint << 6) | (c & 0x3f); |
| 7677 |
codepoint = c & 0x1f; |
7755 |
seq_buff[index++] = c; |
|
|
7756 |
if (--bytes_left == 0) /* codepoint complete */ |
| 7757 |
if(codepoint > 0x10FFFF) /* is it too large? */ |
| 7758 |
complete = -1; /* error (RFC3629 limit) */ |
| 7759 |
else |
| 7760 |
{ /* finished; output utf-8 sequence */ |
| 7761 |
yield = string_catn(yield, seq_buff, seq_len); |
| 7762 |
index = 0; |
| 7763 |
} |
| 7678 |
} |
7764 |
} |
| 7679 |
} |
7765 |
} |
| 7680 |
else if((c & 0xf0) == 0xe0) /* 3-byte sequence */ |
7766 |
else /* no bytes left: new sequence */ |
| 7681 |
{ |
7767 |
{ |
| 7682 |
bytes_left = 2; |
7768 |
if(!(c & 0x80)) /* 1-byte sequence, US-ASCII, keep it */ |
| 7683 |
codepoint = c & 0x0f; |
7769 |
{ |
| 7684 |
} |
7770 |
yield = string_catn(yield, &c, 1); |
| 7685 |
else if((c & 0xf8) == 0xf0) /* 4-byte sequence */ |
7771 |
continue; |
|
|
7772 |
} |
| 7773 |
if((c & 0xe0) == 0xc0) /* 2-byte sequence */ |
| 7774 |
{ |
| 7775 |
if(c == 0xc0 || c == 0xc1) /* 0xc0 and 0xc1 are illegal */ |
| 7776 |
complete = -1; |
| 7777 |
else |
| 7778 |
{ |
| 7779 |
bytes_left = 1; |
| 7780 |
codepoint = c & 0x1f; |
| 7781 |
} |
| 7782 |
} |
| 7783 |
else if((c & 0xf0) == 0xe0) /* 3-byte sequence */ |
| 7784 |
{ |
| 7785 |
bytes_left = 2; |
| 7786 |
codepoint = c & 0x0f; |
| 7787 |
} |
| 7788 |
else if((c & 0xf8) == 0xf0) /* 4-byte sequence */ |
| 7789 |
{ |
| 7790 |
bytes_left = 3; |
| 7791 |
codepoint = c & 0x07; |
| 7792 |
} |
| 7793 |
else /* invalid or too long (RFC3629 allows only 4 bytes) */ |
| 7794 |
complete = -1; |
| 7795 |
|
| 7796 |
seq_buff[index++] = c; |
| 7797 |
seq_len = bytes_left + 1; |
| 7798 |
} /* if(bytes_left) */ |
| 7799 |
|
| 7800 |
if (complete != 0) |
| 7686 |
{ |
7801 |
{ |
| 7687 |
bytes_left = 3; |
7802 |
bytes_left = index = 0; |
| 7688 |
codepoint = c & 0x07; |
7803 |
yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1); |
| 7689 |
} |
7804 |
} |
| 7690 |
else /* invalid or too long (RFC3629 allows only 4 bytes) */ |
7805 |
if ((complete == 1) && ((c & 0x80) == 0)) |
| 7691 |
complete = -1; |
7806 |
/* ASCII character follows incomplete sequence */ |
| 7692 |
|
7807 |
yield = string_catn(yield, &c, 1); |
| 7693 |
seq_buff[index++] = c; |
7808 |
} |
| 7694 |
seq_len = bytes_left + 1; |
7809 |
/* If given a sequence truncated mid-character, we also want to report ? |
| 7695 |
} /* if(bytes_left) */ |
7810 |
Eg, ${length_1:フィル} is one byte, not one character, so we expect |
|
|
7811 |
${utf8clean:${length_1:フィル}} to yield '?' */ |
| 7696 |
|
7812 |
|
| 7697 |
if (complete != 0) |
7813 |
if (bytes_left != 0) |
| 7698 |
{ |
|
|
| 7699 |
bytes_left = index = 0; |
| 7700 |
yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1); |
7814 |
yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1); |
| 7701 |
} |
|
|
| 7702 |
if ((complete == 1) && ((c & 0x80) == 0)) |
| 7703 |
/* ASCII character follows incomplete sequence */ |
| 7704 |
yield = string_catn(yield, &c, 1); |
| 7705 |
} |
| 7706 |
/* If given a sequence truncated mid-character, we also want to report ? |
| 7707 |
* Eg, ${length_1:フィル} is one byte, not one character, so we expect |
| 7708 |
* ${utf8clean:${length_1:フィル}} to yield '?' */ |
| 7709 |
if (bytes_left != 0) |
| 7710 |
yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1); |
| 7711 |
|
7815 |
|
| 7712 |
continue; |
7816 |
break; |
| 7713 |
} |
7817 |
} |
| 7714 |
|
7818 |
|
| 7715 |
#ifdef SUPPORT_I18N |
7819 |
#ifdef SUPPORT_I18N |
| 7716 |
case EOP_UTF8_DOMAIN_TO_ALABEL: |
7820 |
case EOP_UTF8_DOMAIN_TO_ALABEL: |
| 7717 |
{ |
|
|
| 7718 |
uschar * error = NULL; |
| 7719 |
uschar * s = string_domain_utf8_to_alabel(sub, &error); |
| 7720 |
if (error) |
| 7721 |
{ |
7821 |
{ |
| 7722 |
expand_string_message = string_sprintf( |
7822 |
uschar * error = NULL; |
| 7723 |
"error converting utf8 (%s) to alabel: %s", |
7823 |
uschar * s = string_domain_utf8_to_alabel(sub, &error); |
| 7724 |
string_printing(sub), error); |
7824 |
if (error) |
| 7725 |
goto EXPAND_FAILED; |
7825 |
{ |
|
|
7826 |
expand_string_message = string_sprintf( |
| 7827 |
"error converting utf8 (%s) to alabel: %s", |
| 7828 |
string_printing(sub), error); |
| 7829 |
goto EXPAND_FAILED; |
| 7830 |
} |
| 7831 |
yield = string_cat(yield, s); |
| 7832 |
break; |
| 7726 |
} |
7833 |
} |
| 7727 |
yield = string_cat(yield, s); |
|
|
| 7728 |
continue; |
| 7729 |
} |
| 7730 |
|
7834 |
|
| 7731 |
case EOP_UTF8_DOMAIN_FROM_ALABEL: |
7835 |
case EOP_UTF8_DOMAIN_FROM_ALABEL: |
| 7732 |
{ |
|
|
| 7733 |
uschar * error = NULL; |
| 7734 |
uschar * s = string_domain_alabel_to_utf8(sub, &error); |
| 7735 |
if (error) |
| 7736 |
{ |
7836 |
{ |
| 7737 |
expand_string_message = string_sprintf( |
7837 |
uschar * error = NULL; |
| 7738 |
"error converting alabel (%s) to utf8: %s", |
7838 |
uschar * s = string_domain_alabel_to_utf8(sub, &error); |
| 7739 |
string_printing(sub), error); |
7839 |
if (error) |
| 7740 |
goto EXPAND_FAILED; |
7840 |
{ |
|
|
7841 |
expand_string_message = string_sprintf( |
| 7842 |
"error converting alabel (%s) to utf8: %s", |
| 7843 |
string_printing(sub), error); |
| 7844 |
goto EXPAND_FAILED; |
| 7845 |
} |
| 7846 |
yield = string_cat(yield, s); |
| 7847 |
break; |
| 7741 |
} |
7848 |
} |
| 7742 |
yield = string_cat(yield, s); |
|
|
| 7743 |
continue; |
| 7744 |
} |
| 7745 |
|
7849 |
|
| 7746 |
case EOP_UTF8_LOCALPART_TO_ALABEL: |
7850 |
case EOP_UTF8_LOCALPART_TO_ALABEL: |
| 7747 |
{ |
|
|
| 7748 |
uschar * error = NULL; |
| 7749 |
uschar * s = string_localpart_utf8_to_alabel(sub, &error); |
| 7750 |
if (error) |
| 7751 |
{ |
7851 |
{ |
| 7752 |
expand_string_message = string_sprintf( |
7852 |
uschar * error = NULL; |
| 7753 |
"error converting utf8 (%s) to alabel: %s", |
7853 |
uschar * s = string_localpart_utf8_to_alabel(sub, &error); |
| 7754 |
string_printing(sub), error); |
7854 |
if (error) |
| 7755 |
goto EXPAND_FAILED; |
7855 |
{ |
|
|
7856 |
expand_string_message = string_sprintf( |
| 7857 |
"error converting utf8 (%s) to alabel: %s", |
| 7858 |
string_printing(sub), error); |
| 7859 |
goto EXPAND_FAILED; |
| 7860 |
} |
| 7861 |
yield = string_cat(yield, s); |
| 7862 |
DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield->s); |
| 7863 |
break; |
| 7756 |
} |
7864 |
} |
| 7757 |
yield = string_cat(yield, s); |
|
|
| 7758 |
DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield->s); |
| 7759 |
continue; |
| 7760 |
} |
| 7761 |
|
7865 |
|
| 7762 |
case EOP_UTF8_LOCALPART_FROM_ALABEL: |
7866 |
case EOP_UTF8_LOCALPART_FROM_ALABEL: |
| 7763 |
{ |
|
|
| 7764 |
uschar * error = NULL; |
| 7765 |
uschar * s = string_localpart_alabel_to_utf8(sub, &error); |
| 7766 |
if (error) |
| 7767 |
{ |
7867 |
{ |
| 7768 |
expand_string_message = string_sprintf( |
7868 |
uschar * error = NULL; |
| 7769 |
"error converting alabel (%s) to utf8: %s", |
7869 |
uschar * s = string_localpart_alabel_to_utf8(sub, &error); |
| 7770 |
string_printing(sub), error); |
7870 |
if (error) |
| 7771 |
goto EXPAND_FAILED; |
7871 |
{ |
|
|
7872 |
expand_string_message = string_sprintf( |
| 7873 |
"error converting alabel (%s) to utf8: %s", |
| 7874 |
string_printing(sub), error); |
| 7875 |
goto EXPAND_FAILED; |
| 7876 |
} |
| 7877 |
yield = string_cat(yield, s); |
| 7878 |
break; |
| 7772 |
} |
7879 |
} |
| 7773 |
yield = string_cat(yield, s); |
|
|
| 7774 |
continue; |
| 7775 |
} |
| 7776 |
#endif /* EXPERIMENTAL_INTERNATIONAL */ |
7880 |
#endif /* EXPERIMENTAL_INTERNATIONAL */ |
| 7777 |
|
7881 |
|
| 7778 |
/* escape turns all non-printing characters into escape sequences. */ |
7882 |
/* escape turns all non-printing characters into escape sequences. */ |
| 7779 |
|
7883 |
|
| 7780 |
case EOP_ESCAPE: |
7884 |
case EOP_ESCAPE: |
| 7781 |
{ |
7885 |
{ |
| 7782 |
const uschar * t = string_printing(sub); |
7886 |
const uschar * t = string_printing(sub); |
| 7783 |
yield = string_cat(yield, t); |
7887 |
yield = string_cat(yield, t); |
| 7784 |
continue; |
7888 |
break; |
| 7785 |
} |
7889 |
} |
| 7786 |
|
7890 |
|
| 7787 |
case EOP_ESCAPE8BIT: |
7891 |
case EOP_ESCAPE8BIT: |
| 7788 |
{ |
7892 |
{ |
| 7789 |
uschar c; |
7893 |
uschar c; |
| 7790 |
|
7894 |
|
| 7791 |
for (const uschar * s = sub; (c = *s); s++) |
7895 |
for (const uschar * s = sub; (c = *s); s++) |
| 7792 |
yield = c < 127 && c != '\\' |
7896 |
yield = c < 127 && c != '\\' |
| 7793 |
? string_catn(yield, s, 1) |
7897 |
? string_catn(yield, s, 1) |
| 7794 |
: string_fmt_append(yield, "\\%03o", c); |
7898 |
: string_fmt_append(yield, "\\%03o", c); |
| 7795 |
continue; |
7899 |
break; |
| 7796 |
} |
7900 |
} |
| 7797 |
|
7901 |
|
| 7798 |
/* Handle numeric expression evaluation */ |
7902 |
/* Handle numeric expression evaluation */ |
| 7799 |
|
7903 |
|
| 7800 |
case EOP_EVAL: |
7904 |
case EOP_EVAL: |
| 7801 |
case EOP_EVAL10: |
7905 |
case EOP_EVAL10: |
| 7802 |
{ |
7906 |
{ |
| 7803 |
uschar *save_sub = sub; |
7907 |
uschar *save_sub = sub; |
| 7804 |
uschar *error = NULL; |
7908 |
uschar *error = NULL; |
| 7805 |
int_eximarith_t n = eval_expr(&sub, (c == EOP_EVAL10), &error, FALSE); |
7909 |
int_eximarith_t n = eval_expr(&sub, (c == EOP_EVAL10), &error, FALSE); |
| 7806 |
if (error) |
7910 |
if (error) |
| 7807 |
{ |
7911 |
{ |
| 7808 |
expand_string_message = string_sprintf("error in expression " |
7912 |
expand_string_message = string_sprintf("error in expression " |
| 7809 |
"evaluation: %s (after processing \"%.*s\")", error, |
7913 |
"evaluation: %s (after processing \"%.*s\")", error, |
| 7810 |
(int)(sub-save_sub), save_sub); |
7914 |
(int)(sub-save_sub), save_sub); |
| 7811 |
goto EXPAND_FAILED; |
7915 |
goto EXPAND_FAILED; |
| 7812 |
} |
7916 |
} |
| 7813 |
yield = string_fmt_append(yield, PR_EXIM_ARITH, n); |
7917 |
yield = string_fmt_append(yield, PR_EXIM_ARITH, n); |
| 7814 |
continue; |
7918 |
break; |
| 7815 |
} |
7919 |
} |
| 7816 |
|
7920 |
|
| 7817 |
/* Handle time period formatting */ |
7921 |
/* Handle time period formatting */ |
| 7818 |
|
7922 |
|
| 7819 |
case EOP_TIME_EVAL: |
7923 |
case EOP_TIME_EVAL: |
| 7820 |
{ |
7924 |
{ |
| 7821 |
int n = readconf_readtime(sub, 0, FALSE); |
7925 |
int n = readconf_readtime(sub, 0, FALSE); |
| 7822 |
if (n < 0) |
7926 |
if (n < 0) |
| 7823 |
{ |
7927 |
{ |
| 7824 |
expand_string_message = string_sprintf("string \"%s\" is not an " |
7928 |
expand_string_message = string_sprintf("string \"%s\" is not an " |
| 7825 |
"Exim time interval in \"%s\" operator", sub, name); |
7929 |
"Exim time interval in \"%s\" operator", sub, name); |
| 7826 |
goto EXPAND_FAILED; |
7930 |
goto EXPAND_FAILED; |
| 7827 |
} |
7931 |
} |
| 7828 |
yield = string_fmt_append(yield, "%d", n); |
7932 |
yield = string_fmt_append(yield, "%d", n); |
| 7829 |
continue; |
7933 |
break; |
| 7830 |
} |
7934 |
} |
| 7831 |
|
7935 |
|
| 7832 |
case EOP_TIME_INTERVAL: |
7936 |
case EOP_TIME_INTERVAL: |
| 7833 |
{ |
7937 |
{ |
| 7834 |
int n; |
7938 |
int n; |
| 7835 |
uschar *t = read_number(&n, sub); |
7939 |
uschar *t = read_number(&n, sub); |
| 7836 |
if (*t != 0) /* Not A Number*/ |
7940 |
if (*t != 0) /* Not A Number*/ |
| 7837 |
{ |
7941 |
{ |
| 7838 |
expand_string_message = string_sprintf("string \"%s\" is not a " |
7942 |
expand_string_message = string_sprintf("string \"%s\" is not a " |
| 7839 |
"positive number in \"%s\" operator", sub, name); |
7943 |
"positive number in \"%s\" operator", sub, name); |
| 7840 |
goto EXPAND_FAILED; |
7944 |
goto EXPAND_FAILED; |
| 7841 |
} |
7945 |
} |
| 7842 |
t = readconf_printtime(n); |
7946 |
t = readconf_printtime(n); |
| 7843 |
yield = string_cat(yield, t); |
7947 |
yield = string_cat(yield, t); |
| 7844 |
continue; |
7948 |
break; |
| 7845 |
} |
7949 |
} |
| 7846 |
|
7950 |
|
| 7847 |
/* Convert string to base64 encoding */ |
7951 |
/* Convert string to base64 encoding */ |
| 7848 |
|
7952 |
|
| 7849 |
case EOP_STR2B64: |
7953 |
case EOP_STR2B64: |
| 7850 |
case EOP_BASE64: |
7954 |
case EOP_BASE64: |
| 7851 |
{ |
7955 |
{ |
| 7852 |
#ifndef DISABLE_TLS |
7956 |
#ifndef DISABLE_TLS |
| 7853 |
uschar * s = vp && *(void **)vp->value |
7957 |
uschar * s = vp && *(void **)vp->value |
| 7854 |
? tls_cert_der_b64(*(void **)vp->value) |
7958 |
? tls_cert_der_b64(*(void **)vp->value) |
| 7855 |
: b64encode(CUS sub, Ustrlen(sub)); |
7959 |
: b64encode(CUS sub, Ustrlen(sub)); |
| 7856 |
#else |
7960 |
#else |
| 7857 |
uschar * s = b64encode(CUS sub, Ustrlen(sub)); |
7961 |
uschar * s = b64encode(CUS sub, Ustrlen(sub)); |
| 7858 |
#endif |
7962 |
#endif |
| 7859 |
yield = string_cat(yield, s); |
7963 |
yield = string_cat(yield, s); |
| 7860 |
continue; |
7964 |
break; |
| 7861 |
} |
7965 |
} |
| 7862 |
|
7966 |
|
| 7863 |
case EOP_BASE64D: |
7967 |
case EOP_BASE64D: |
| 7864 |
{ |
7968 |
{ |
| 7865 |
uschar * s; |
7969 |
uschar * s; |
| 7866 |
int len = b64decode(sub, &s); |
7970 |
int len = b64decode(sub, &s); |
| 7867 |
if (len < 0) |
7971 |
if (len < 0) |
| 7868 |
{ |
7972 |
{ |
| 7869 |
expand_string_message = string_sprintf("string \"%s\" is not " |
7973 |
expand_string_message = string_sprintf("string \"%s\" is not " |
| 7870 |
"well-formed for \"%s\" operator", sub, name); |
7974 |
"well-formed for \"%s\" operator", sub, name); |
| 7871 |
goto EXPAND_FAILED; |
7975 |
goto EXPAND_FAILED; |
| 7872 |
} |
7976 |
} |
| 7873 |
yield = string_cat(yield, s); |
7977 |
yield = string_cat(yield, s); |
| 7874 |
continue; |
7978 |
break; |
| 7875 |
} |
7979 |
} |
| 7876 |
|
7980 |
|
| 7877 |
/* strlen returns the length of the string */ |
7981 |
/* strlen returns the length of the string */ |
| 7878 |
|
7982 |
|
| 7879 |
case EOP_STRLEN: |
7983 |
case EOP_STRLEN: |
| 7880 |
yield = string_fmt_append(yield, "%d", Ustrlen(sub)); |
7984 |
yield = string_fmt_append(yield, "%d", Ustrlen(sub)); |
| 7881 |
continue; |
7985 |
break; |
| 7882 |
|
7986 |
|
| 7883 |
/* length_n or l_n takes just the first n characters or the whole string, |
7987 |
/* length_n or l_n takes just the first n characters or the whole string, |
| 7884 |
whichever is the shorter; |
7988 |
whichever is the shorter; |
| 7885 |
|
7989 |
|
| 7886 |
substr_m_n, and s_m_n take n characters from offset m; negative m take |
7990 |
substr_m_n, and s_m_n take n characters from offset m; negative m take |
| 7887 |
from the end; l_n is synonymous with s_0_n. If n is omitted in substr it |
7991 |
from the end; l_n is synonymous with s_0_n. If n is omitted in substr it |
| 7888 |
takes the rest, either to the right or to the left. |
7992 |
takes the rest, either to the right or to the left. |
| 7889 |
|
7993 |
|
| 7890 |
hash_n or h_n makes a hash of length n from the string, yielding n |
7994 |
hash_n or h_n makes a hash of length n from the string, yielding n |
| 7891 |
characters from the set a-z; hash_n_m makes a hash of length n, but |
7995 |
characters from the set a-z; hash_n_m makes a hash of length n, but |
| 7892 |
uses m characters from the set a-zA-Z0-9. |
7996 |
uses m characters from the set a-zA-Z0-9. |
| 7893 |
|
7997 |
|
| 7894 |
nhash_n returns a single number between 0 and n-1 (in text form), while |
7998 |
nhash_n returns a single number between 0 and n-1 (in text form), while |
| 7895 |
nhash_n_m returns a div/mod hash as two numbers "a/b". The first lies |
7999 |
nhash_n_m returns a div/mod hash as two numbers "a/b". The first lies |
| 7896 |
between 0 and n-1 and the second between 0 and m-1. */ |
8000 |
between 0 and n-1 and the second between 0 and m-1. */ |
| 7897 |
|
8001 |
|
| 7898 |
case EOP_LENGTH: |
8002 |
case EOP_LENGTH: |
| 7899 |
case EOP_L: |
8003 |
case EOP_L: |
| 7900 |
case EOP_SUBSTR: |
8004 |
case EOP_SUBSTR: |
| 7901 |
case EOP_S: |
8005 |
case EOP_S: |
| 7902 |
case EOP_HASH: |
8006 |
case EOP_HASH: |
| 7903 |
case EOP_H: |
8007 |
case EOP_H: |
| 7904 |
case EOP_NHASH: |
8008 |
case EOP_NHASH: |
| 7905 |
case EOP_NH: |
8009 |
case EOP_NH: |
| 7906 |
{ |
8010 |
{ |
| 7907 |
int sign = 1; |
8011 |
int sign = 1; |
| 7908 |
int value1 = 0; |
8012 |
int value1 = 0; |
| 7909 |
int value2 = -1; |
8013 |
int value2 = -1; |
| 7910 |
int *pn; |
8014 |
int *pn; |
| 7911 |
int len; |
8015 |
int len; |
| 7912 |
uschar *ret; |
8016 |
uschar *ret; |
| 7913 |
|
8017 |
|
| 7914 |
if (!arg) |
8018 |
if (!arg) |
| 7915 |
{ |
8019 |
{ |
| 7916 |
expand_string_message = string_sprintf("missing values after %s", |
8020 |
expand_string_message = string_sprintf("missing values after %s", |
| 7917 |
name); |
8021 |
name); |
| 7918 |
goto EXPAND_FAILED; |
8022 |
goto EXPAND_FAILED; |
| 7919 |
} |
8023 |
} |
| 7920 |
|
8024 |
|
| 7921 |
/* "length" has only one argument, effectively being synonymous with |
8025 |
/* "length" has only one argument, effectively being synonymous with |
| 7922 |
substr_0_n. */ |
8026 |
substr_0_n. */ |
| 7923 |
|
8027 |
|
| 7924 |
if (c == EOP_LENGTH || c == EOP_L) |
8028 |
if (c == EOP_LENGTH || c == EOP_L) |
| 7925 |
{ |
8029 |
{ |
| 7926 |
pn = &value2; |
8030 |
pn = &value2; |
| 7927 |
value2 = 0; |
8031 |
value2 = 0; |
| 7928 |
} |
8032 |
} |
| 7929 |
|
8033 |
|
| 7930 |
/* The others have one or two arguments; for "substr" the first may be |
8034 |
/* The others have one or two arguments; for "substr" the first may be |
| 7931 |
negative. The second being negative means "not supplied". */ |
8035 |
negative. The second being negative means "not supplied". */ |
| 7932 |
|
8036 |
|
| 7933 |
else |
8037 |
else |
| 7934 |
{ |
8038 |
{ |
| 7935 |
pn = &value1; |
8039 |
pn = &value1; |
| 7936 |
if (name[0] == 's' && *arg == '-') { sign = -1; arg++; } |
8040 |
if (name[0] == 's' && *arg == '-') { sign = -1; arg++; } |
| 7937 |
} |
8041 |
} |
| 7938 |
|
8042 |
|
| 7939 |
/* Read up to two numbers, separated by underscores */ |
8043 |
/* Read up to two numbers, separated by underscores */ |
| 7940 |
|
8044 |
|
| 7941 |
ret = arg; |
8045 |
ret = arg; |
| 7942 |
while (*arg != 0) |
8046 |
while (*arg != 0) |
| 7943 |
{ |
8047 |
{ |
| 7944 |
if (arg != ret && *arg == '_' && pn == &value1) |
8048 |
if (arg != ret && *arg == '_' && pn == &value1) |
| 7945 |
{ |
8049 |
{ |
| 7946 |
pn = &value2; |
8050 |
pn = &value2; |
| 7947 |
value2 = 0; |
8051 |
value2 = 0; |
| 7948 |
if (arg[1] != 0) arg++; |
8052 |
if (arg[1] != 0) arg++; |
| 7949 |
} |
8053 |
} |
| 7950 |
else if (!isdigit(*arg)) |
8054 |
else if (!isdigit(*arg)) |
| 7951 |
{ |
8055 |
{ |
| 7952 |
expand_string_message = |
8056 |
expand_string_message = |
| 7953 |
string_sprintf("non-digit after underscore in \"%s\"", name); |
8057 |
string_sprintf("non-digit after underscore in \"%s\"", name); |
| 7954 |
goto EXPAND_FAILED; |
8058 |
goto EXPAND_FAILED; |
| 7955 |
} |
8059 |
} |
| 7956 |
else *pn = (*pn)*10 + *arg++ - '0'; |
8060 |
else *pn = (*pn)*10 + *arg++ - '0'; |
| 7957 |
} |
8061 |
} |
| 7958 |
value1 *= sign; |
8062 |
value1 *= sign; |
| 7959 |
|
8063 |
|
| 7960 |
/* Perform the required operation */ |
8064 |
/* Perform the required operation */ |
| 7961 |
|
8065 |
|
| 7962 |
ret = c == EOP_HASH || c == EOP_H |
8066 |
ret = c == EOP_HASH || c == EOP_H |
| 7963 |
? compute_hash(sub, value1, value2, &len) |
8067 |
? compute_hash(sub, value1, value2, &len) |
| 7964 |
: c == EOP_NHASH || c == EOP_NH |
8068 |
: c == EOP_NHASH || c == EOP_NH |
| 7965 |
? compute_nhash(sub, value1, value2, &len) |
8069 |
? compute_nhash(sub, value1, value2, &len) |
| 7966 |
: extract_substr(sub, value1, value2, &len); |
8070 |
: extract_substr(sub, value1, value2, &len); |
| 7967 |
if (!ret) goto EXPAND_FAILED; |
8071 |
if (!ret) goto EXPAND_FAILED; |
| 7968 |
|
8072 |
|
| 7969 |
yield = string_catn(yield, ret, len); |
8073 |
yield = string_catn(yield, ret, len); |
| 7970 |
continue; |
8074 |
break; |
| 7971 |
} |
8075 |
} |
| 7972 |
|
8076 |
|
| 7973 |
/* Stat a path */ |
8077 |
/* Stat a path */ |
| 7974 |
|
8078 |
|
| 7975 |
case EOP_STAT: |
8079 |
case EOP_STAT: |
| 7976 |
{ |
8080 |
{ |
| 7977 |
uschar smode[12]; |
8081 |
uschar smode[12]; |
| 7978 |
uschar **modetable[3]; |
8082 |
uschar **modetable[3]; |
| 7979 |
mode_t mode; |
8083 |
mode_t mode; |
| 7980 |
struct stat st; |
8084 |
struct stat st; |
| 7981 |
|
8085 |
|
| 7982 |
if (expand_forbid & RDO_EXISTS) |
8086 |
if (expand_forbid & RDO_EXISTS) |
| 7983 |
{ |
8087 |
{ |
| 7984 |
expand_string_message = US"Use of the stat() expansion is not permitted"; |
8088 |
expand_string_message = US"Use of the stat() expansion is not permitted"; |
| 7985 |
goto EXPAND_FAILED; |
8089 |
goto EXPAND_FAILED; |
| 7986 |
} |
8090 |
} |
| 7987 |
|
8091 |
|
| 7988 |
if (stat(CS sub, &st) < 0) |
8092 |
if (stat(CS sub, &st) < 0) |
| 7989 |
{ |
8093 |
{ |
| 7990 |
expand_string_message = string_sprintf("stat(%s) failed: %s", |
8094 |
expand_string_message = string_sprintf("stat(%s) failed: %s", |
| 7991 |
sub, strerror(errno)); |
8095 |
sub, strerror(errno)); |
| 7992 |
goto EXPAND_FAILED; |
8096 |
goto EXPAND_FAILED; |
| 7993 |
} |
8097 |
} |
| 7994 |
mode = st.st_mode; |
8098 |
mode = st.st_mode; |
| 7995 |
switch (mode & S_IFMT) |
8099 |
switch (mode & S_IFMT) |
| 7996 |
{ |
8100 |
{ |
| 7997 |
case S_IFIFO: smode[0] = 'p'; break; |
8101 |
case S_IFIFO: smode[0] = 'p'; break; |
| 7998 |
case S_IFCHR: smode[0] = 'c'; break; |
8102 |
case S_IFCHR: smode[0] = 'c'; break; |
| 7999 |
case S_IFDIR: smode[0] = 'd'; break; |
8103 |
case S_IFDIR: smode[0] = 'd'; break; |
| 8000 |
case S_IFBLK: smode[0] = 'b'; break; |
8104 |
case S_IFBLK: smode[0] = 'b'; break; |
| 8001 |
case S_IFREG: smode[0] = '-'; break; |
8105 |
case S_IFREG: smode[0] = '-'; break; |
| 8002 |
default: smode[0] = '?'; break; |
8106 |
default: smode[0] = '?'; break; |
| 8003 |
} |
8107 |
} |
| 8004 |
|
8108 |
|
| 8005 |
modetable[0] = ((mode & 01000) == 0)? mtable_normal : mtable_sticky; |
8109 |
modetable[0] = ((mode & 01000) == 0)? mtable_normal : mtable_sticky; |
| 8006 |
modetable[1] = ((mode & 02000) == 0)? mtable_normal : mtable_setid; |
8110 |
modetable[1] = ((mode & 02000) == 0)? mtable_normal : mtable_setid; |
| 8007 |
modetable[2] = ((mode & 04000) == 0)? mtable_normal : mtable_setid; |
8111 |
modetable[2] = ((mode & 04000) == 0)? mtable_normal : mtable_setid; |
| 8008 |
|
8112 |
|
| 8009 |
for (int i = 0; i < 3; i++) |
8113 |
for (int i = 0; i < 3; i++) |
| 8010 |
{ |
8114 |
{ |
| 8011 |
memcpy(CS(smode + 7 - i*3), CS(modetable[i][mode & 7]), 3); |
8115 |
memcpy(CS(smode + 7 - i*3), CS(modetable[i][mode & 7]), 3); |
| 8012 |
mode >>= 3; |
8116 |
mode >>= 3; |
| 8013 |
} |
8117 |
} |
| 8014 |
|
8118 |
|
| 8015 |
smode[10] = 0; |
8119 |
smode[10] = 0; |
| 8016 |
yield = string_fmt_append(yield, |
8120 |
yield = string_fmt_append(yield, |
| 8017 |
"mode=%04lo smode=%s inode=%ld device=%ld links=%ld " |
8121 |
"mode=%04lo smode=%s inode=%ld device=%ld links=%ld " |
| 8018 |
"uid=%ld gid=%ld size=" OFF_T_FMT " atime=%ld mtime=%ld ctime=%ld", |
8122 |
"uid=%ld gid=%ld size=" OFF_T_FMT " atime=%ld mtime=%ld ctime=%ld", |
| 8019 |
(long)(st.st_mode & 077777), smode, (long)st.st_ino, |
8123 |
(long)(st.st_mode & 077777), smode, (long)st.st_ino, |
| 8020 |
(long)st.st_dev, (long)st.st_nlink, (long)st.st_uid, |
8124 |
(long)st.st_dev, (long)st.st_nlink, (long)st.st_uid, |
| 8021 |
(long)st.st_gid, st.st_size, (long)st.st_atime, |
8125 |
(long)st.st_gid, st.st_size, (long)st.st_atime, |
| 8022 |
(long)st.st_mtime, (long)st.st_ctime); |
8126 |
(long)st.st_mtime, (long)st.st_ctime); |
| 8023 |
continue; |
8127 |
break; |
| 8024 |
} |
8128 |
} |
| 8025 |
|
8129 |
|
| 8026 |
/* vaguely random number less than N */ |
8130 |
/* vaguely random number less than N */ |
| 8027 |
|
8131 |
|
| 8028 |
case EOP_RANDINT: |
8132 |
case EOP_RANDINT: |
| 8029 |
{ |
8133 |
{ |
| 8030 |
int_eximarith_t max = expanded_string_integer(sub, TRUE); |
8134 |
int_eximarith_t max = expanded_string_integer(sub, TRUE); |
| 8031 |
|
8135 |
|
| 8032 |
if (expand_string_message) |
8136 |
if (expand_string_message) |
| 8033 |
goto EXPAND_FAILED; |
8137 |
goto EXPAND_FAILED; |
| 8034 |
yield = string_fmt_append(yield, "%d", vaguely_random_number((int)max)); |
8138 |
yield = string_fmt_append(yield, "%d", vaguely_random_number((int)max)); |
| 8035 |
continue; |
8139 |
break; |
| 8036 |
} |
8140 |
} |
| 8037 |
|
8141 |
|
| 8038 |
/* Reverse IP, including IPv6 to dotted-nibble */ |
8142 |
/* Reverse IP, including IPv6 to dotted-nibble */ |
| 8039 |
|
8143 |
|
| 8040 |
case EOP_REVERSE_IP: |
8144 |
case EOP_REVERSE_IP: |
| 8041 |
{ |
8145 |
{ |
| 8042 |
int family, maskptr; |
8146 |
int family, maskptr; |
| 8043 |
uschar reversed[128]; |
8147 |
uschar reversed[128]; |
| 8044 |
|
8148 |
|
| 8045 |
family = string_is_ip_address(sub, &maskptr); |
8149 |
family = string_is_ip_address(sub, &maskptr); |
| 8046 |
if (family == 0) |
8150 |
if (family == 0) |
| 8047 |
{ |
8151 |
{ |
| 8048 |
expand_string_message = string_sprintf( |
8152 |
expand_string_message = string_sprintf( |
| 8049 |
"reverse_ip() not given an IP address [%s]", sub); |
8153 |
"reverse_ip() not given an IP address [%s]", sub); |
| 8050 |
goto EXPAND_FAILED; |
8154 |
goto EXPAND_FAILED; |
| 8051 |
} |
8155 |
} |
| 8052 |
invert_address(reversed, sub); |
8156 |
invert_address(reversed, sub); |
| 8053 |
yield = string_cat(yield, reversed); |
8157 |
yield = string_cat(yield, reversed); |
| 8054 |
continue; |
8158 |
break; |
| 8055 |
} |
8159 |
} |
| 8056 |
|
8160 |
|
| 8057 |
/* Unknown operator */ |
8161 |
/* Unknown operator */ |
| 8058 |
|
8162 |
|
| 8059 |
default: |
8163 |
default: |
| 8060 |
expand_string_message = |
8164 |
expand_string_message = |
| 8061 |
string_sprintf("unknown expansion operator \"%s\"", name); |
8165 |
string_sprintf("unknown expansion operator \"%s\"", name); |
| 8062 |
goto EXPAND_FAILED; |
8166 |
goto EXPAND_FAILED; |
| 8063 |
} |
8167 |
} /* EOP_* switch */ |
|
|
8168 |
|
| 8169 |
DEBUG(D_expand) |
| 8170 |
{ |
| 8171 |
const uschar * s = yield->s + start; |
| 8172 |
int i = yield->ptr - start; |
| 8173 |
BOOL tainted = is_tainted(s); |
| 8174 |
|
| 8175 |
DEBUG(D_noutf8) |
| 8176 |
{ |
| 8177 |
debug_printf_indent("|-----op-res: %.*s\n", i, s); |
| 8178 |
if (tainted) |
| 8179 |
{ |
| 8180 |
debug_printf_indent("%s \\__", skipping ? "| " : " "); |
| 8181 |
debug_print_taint(yield->s); |
| 8182 |
} |
| 8183 |
} |
| 8184 |
else |
| 8185 |
{ |
| 8186 |
debug_printf_indent(UTF8_VERT_RIGHT |
| 8187 |
UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ |
| 8188 |
"op-res: %.*s\n", i, s); |
| 8189 |
if (tainted) |
| 8190 |
{ |
| 8191 |
debug_printf_indent("%s", |
| 8192 |
skipping |
| 8193 |
? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ); |
| 8194 |
debug_print_taint(yield->s); |
| 8195 |
} |
| 8196 |
} |
| 8197 |
} |
| 8198 |
continue; |
| 8199 |
} |
| 8064 |
} |
8200 |
} |
| 8065 |
|
8201 |
|
|
|
8202 |
/* Not an item or an operator */ |
| 8066 |
/* Handle a plain name. If this is the first thing in the expansion, release |
8203 |
/* Handle a plain name. If this is the first thing in the expansion, release |
| 8067 |
the pre-allocated buffer. If the result data is known to be in a new buffer, |
8204 |
the pre-allocated buffer. If the result data is known to be in a new buffer, |
| 8068 |
newsize will be set to the size of that buffer, and we can just point at that |
8205 |
newsize will be set to the size of that buffer, and we can just point at that |
|
Lines 8072-8089
Link Here
|
| 8072 |
/*{*/ |
8209 |
/*{*/ |
| 8073 |
if (*s++ == '}') |
8210 |
if (*s++ == '}') |
| 8074 |
{ |
8211 |
{ |
|
|
8212 |
const uschar * value; |
| 8075 |
int len; |
8213 |
int len; |
| 8076 |
int newsize = 0; |
8214 |
int newsize = 0; |
| 8077 |
gstring * g = NULL; |
8215 |
gstring * g = NULL; |
| 8078 |
|
8216 |
|
| 8079 |
if (!yield) |
8217 |
if (!yield) |
| 8080 |
g = store_get(sizeof(gstring), FALSE); |
8218 |
g = store_get(sizeof(gstring), GET_UNTAINTED); |
| 8081 |
else if (yield->ptr == 0) |
8219 |
else if (yield->ptr == 0) |
| 8082 |
{ |
8220 |
{ |
| 8083 |
if (resetok) reset_point = store_reset(reset_point); |
8221 |
if (resetok) reset_point = store_reset(reset_point); |
| 8084 |
yield = NULL; |
8222 |
yield = NULL; |
| 8085 |
reset_point = store_mark(); |
8223 |
reset_point = store_mark(); |
| 8086 |
g = store_get(sizeof(gstring), FALSE); /* alloc _before_ calling find_variable() */ |
8224 |
g = store_get(sizeof(gstring), GET_UNTAINTED); /* alloc _before_ calling find_variable() */ |
| 8087 |
} |
8225 |
} |
| 8088 |
if (!(value = find_variable(name, FALSE, skipping, &newsize))) |
8226 |
if (!(value = find_variable(name, FALSE, skipping, &newsize))) |
| 8089 |
{ |
8227 |
{ |
|
Lines 8098-8104
Link Here
|
| 8098 |
yield = g; |
8236 |
yield = g; |
| 8099 |
yield->size = newsize; |
8237 |
yield->size = newsize; |
| 8100 |
yield->ptr = len; |
8238 |
yield->ptr = len; |
| 8101 |
yield->s = value; |
8239 |
yield->s = US value; /* known to be in new store i.e. a copy, so deconst safe */ |
| 8102 |
} |
8240 |
} |
| 8103 |
else |
8241 |
else |
| 8104 |
yield = string_catn(yield, value, len); |
8242 |
yield = string_catn(yield, value, len); |
|
Lines 8116-8122
Link Here
|
| 8116 |
/* If we hit the end of the string when ket_ends is set, there is a missing |
8254 |
/* If we hit the end of the string when ket_ends is set, there is a missing |
| 8117 |
terminating brace. */ |
8255 |
terminating brace. */ |
| 8118 |
|
8256 |
|
| 8119 |
if (ket_ends && *s == 0) |
8257 |
if (ket_ends && !*s) |
| 8120 |
{ |
8258 |
{ |
| 8121 |
expand_string_message = malformed_header |
8259 |
expand_string_message = malformed_header |
| 8122 |
? US"missing } at end of string - could be header name not terminated by colon" |
8260 |
? US"missing } at end of string - could be header name not terminated by colon" |
|
Lines 8149-8156
Link Here
|
| 8149 |
debug_printf_indent("%sresult: %s\n", |
8287 |
debug_printf_indent("%sresult: %s\n", |
| 8150 |
skipping ? "|-----" : "\\_____", yield->s); |
8288 |
skipping ? "|-----" : "\\_____", yield->s); |
| 8151 |
if (tainted) |
8289 |
if (tainted) |
| 8152 |
debug_printf_indent("%s \\__(tainted)\n", |
8290 |
{ |
| 8153 |
skipping ? "| " : " "); |
8291 |
debug_printf_indent("%s \\__", skipping ? "| " : " "); |
|
|
8292 |
debug_print_taint(yield->s); |
| 8293 |
} |
| 8154 |
if (skipping) |
8294 |
if (skipping) |
| 8155 |
debug_printf_indent("\\___skipping: result is not used\n"); |
8295 |
debug_printf_indent("\\___skipping: result is not used\n"); |
| 8156 |
} |
8296 |
} |
|
Lines 8164-8172
Link Here
|
| 8164 |
skipping ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT, |
8304 |
skipping ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT, |
| 8165 |
yield->s); |
8305 |
yield->s); |
| 8166 |
if (tainted) |
8306 |
if (tainted) |
| 8167 |
debug_printf_indent("%s(tainted)\n", |
8307 |
{ |
|
|
8308 |
debug_printf_indent("%s", |
| 8168 |
skipping |
8309 |
skipping |
| 8169 |
? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ); |
8310 |
? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ); |
|
|
8311 |
debug_print_taint(yield->s); |
| 8312 |
} |
| 8170 |
if (skipping) |
8313 |
if (skipping) |
| 8171 |
debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ |
8314 |
debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ |
| 8172 |
"skipping: result is not used\n"); |
8315 |
"skipping: result is not used\n"); |
|
Lines 8193-8198
Link Here
|
| 8193 |
EXPAND_FAILED: |
8336 |
EXPAND_FAILED: |
| 8194 |
if (left) *left = s; |
8337 |
if (left) *left = s; |
| 8195 |
DEBUG(D_expand) |
8338 |
DEBUG(D_expand) |
|
|
8339 |
{ |
| 8196 |
DEBUG(D_noutf8) |
8340 |
DEBUG(D_noutf8) |
| 8197 |
{ |
8341 |
{ |
| 8198 |
debug_printf_indent("|failed to expand: %s\n", string); |
8342 |
debug_printf_indent("|failed to expand: %s\n", string); |
|
Lines 8212-8217
Link Here
|
| 8212 |
if (f.expand_string_forcedfail) |
8356 |
if (f.expand_string_forcedfail) |
| 8213 |
debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n"); |
8357 |
debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n"); |
| 8214 |
} |
8358 |
} |
|
|
8359 |
} |
| 8215 |
if (resetok_p && !resetok) *resetok_p = FALSE; |
8360 |
if (resetok_p && !resetok) *resetok_p = FALSE; |
| 8216 |
expand_level--; |
8361 |
expand_level--; |
| 8217 |
return NULL; |
8362 |
return NULL; |
|
Lines 8519-8524
Link Here
|
| 8519 |
const uschar *var_data; |
8664 |
const uschar *var_data; |
| 8520 |
} err_ctx; |
8665 |
} err_ctx; |
| 8521 |
|
8666 |
|
|
|
8667 |
/* Called via tree_walk, which allows nonconst name/data. Our usage is const. */ |
| 8522 |
static void |
8668 |
static void |
| 8523 |
assert_variable_notin(uschar * var_name, uschar * var_data, void * ctx) |
8669 |
assert_variable_notin(uschar * var_name, uschar * var_data, void * ctx) |
| 8524 |
{ |
8670 |
{ |
|
Lines 8540-8552
Link Here
|
| 8540 |
tree_walk(acl_var_c, assert_variable_notin, &e); |
8686 |
tree_walk(acl_var_c, assert_variable_notin, &e); |
| 8541 |
tree_walk(acl_var_m, assert_variable_notin, &e); |
8687 |
tree_walk(acl_var_m, assert_variable_notin, &e); |
| 8542 |
|
8688 |
|
| 8543 |
/* check auth<n> variables */ |
8689 |
/* check auth<n> variables. |
|
|
8690 |
assert_variable_notin() treats as const, so deconst is safe. */ |
| 8544 |
for (int i = 0; i < AUTH_VARS; i++) if (auth_vars[i]) |
8691 |
for (int i = 0; i < AUTH_VARS; i++) if (auth_vars[i]) |
| 8545 |
assert_variable_notin(US"auth<n>", auth_vars[i], &e); |
8692 |
assert_variable_notin(US"auth<n>", US auth_vars[i], &e); |
| 8546 |
|
8693 |
|
| 8547 |
/* check regex<n> variables */ |
8694 |
/* check regex<n> variables. assert_variable_notin() treats as const. */ |
| 8548 |
for (int i = 0; i < REGEX_VARS; i++) if (regex_vars[i]) |
8695 |
for (int i = 0; i < REGEX_VARS; i++) if (regex_vars[i]) |
| 8549 |
assert_variable_notin(US"regex<n>", regex_vars[i], &e); |
8696 |
assert_variable_notin(US"regex<n>", US regex_vars[i], &e); |
| 8550 |
|
8697 |
|
| 8551 |
/* check known-name variables */ |
8698 |
/* check known-name variables */ |
| 8552 |
for (var_entry * v = var_table; v < var_table + var_table_size; v++) |
8699 |
for (var_entry * v = var_table; v < var_table + var_table_size; v++) |
|
Lines 8577-8587
Link Here
|
| 8577 |
|
8724 |
|
| 8578 |
|
8725 |
|
| 8579 |
BOOL |
8726 |
BOOL |
| 8580 |
regex_match_and_setup(const pcre *re, uschar *subject, int options, int setup) |
8727 |
regex_match_and_setup(const pcre2_code *re, uschar *subject, int options, int setup) |
| 8581 |
{ |
8728 |
{ |
| 8582 |
int ovector[3*(EXPAND_MAXN+1)]; |
8729 |
int ovec[3*(EXPAND_MAXN+1)]; |
| 8583 |
int n = pcre_exec(re, NULL, subject, Ustrlen(subject), 0, PCRE_EOPT|options, |
8730 |
int n = pcre_exec(re, NULL, subject, Ustrlen(subject), 0, PCRE_EOPT|options, |
| 8584 |
ovector, nelem(ovector)); |
8731 |
ovec, nelem(ovec)); |
| 8585 |
BOOL yield = n >= 0; |
8732 |
BOOL yield = n >= 0; |
| 8586 |
if (n == 0) n = EXPAND_MAXN + 1; |
8733 |
if (n == 0) n = EXPAND_MAXN + 1; |
| 8587 |
if (yield) |
8734 |
if (yield) |
|
Lines 8589-8596
Link Here
|
| 8589 |
expand_nmax = setup < 0 ? 0 : setup + 1; |
8736 |
expand_nmax = setup < 0 ? 0 : setup + 1; |
| 8590 |
for (int nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2) |
8737 |
for (int nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2) |
| 8591 |
{ |
8738 |
{ |
| 8592 |
expand_nstring[expand_nmax] = subject + ovector[nn]; |
8739 |
expand_nstring[expand_nmax] = subject + ovec[nn]; |
| 8593 |
expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn]; |
8740 |
expand_nlength[expand_nmax++] = ovec[nn+1] - ovec[nn]; |
| 8594 |
} |
8741 |
} |
| 8595 |
expand_nmax--; |
8742 |
expand_nmax--; |
| 8596 |
} |
8743 |
} |
|
Lines 8606-8611
Link Here
|
| 8606 |
debug_file = stderr; |
8753 |
debug_file = stderr; |
| 8607 |
debug_fd = fileno(debug_file); |
8754 |
debug_fd = fileno(debug_file); |
| 8608 |
big_buffer = malloc(big_buffer_size); |
8755 |
big_buffer = malloc(big_buffer_size); |
|
|
8756 |
store_init(); |
| 8609 |
|
8757 |
|
| 8610 |
for (int i = 1; i < argc; i++) |
8758 |
for (int i = 1; i < argc; i++) |
| 8611 |
{ |
8759 |
{ |