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 |
{ |