Copyright updates:
[exim.git] / src / src / expand.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
1e1ddfac 6/* Copyright (c) The Exim Maintainers 2020 */
059ec3d9
PH
7/* See the file NOTICE for conditions of use and distribution. */
8
9
10/* Functions for handling string expansion. */
11
12
13#include "exim.h"
14
96c065cb
PH
15/* Recursively called function */
16
55414b25
JH
17static uschar *expand_string_internal(const uschar *, BOOL, const uschar **, BOOL, BOOL, BOOL *);
18static int_eximarith_t expanded_string_integer(const uschar *, BOOL);
96c065cb 19
059ec3d9 20#ifdef STAND_ALONE
9d466bf7
JH
21# ifndef SUPPORT_CRYPTEQ
22# define SUPPORT_CRYPTEQ
23# endif
059ec3d9
PH
24#endif
25
96c065cb 26#ifdef LOOKUP_LDAP
9d466bf7 27# include "lookups/ldap.h"
96c065cb
PH
28#endif
29
059ec3d9 30#ifdef SUPPORT_CRYPTEQ
9d466bf7
JH
31# ifdef CRYPT_H
32# include <crypt.h>
33# endif
34# ifndef HAVE_CRYPT16
059ec3d9 35extern char* crypt16(char*, char*);
9d466bf7 36# endif
059ec3d9
PH
37#endif
38
96c065cb
PH
39/* The handling of crypt16() is a mess. I will record below the analysis of the
40mess that was sent to me. We decided, however, to make changing this very low
41priority, because in practice people are moving away from the crypt()
42algorithms nowadays, so it doesn't seem worth it.
43
44<quote>
45There is an algorithm named "crypt16" in Ultrix and Tru64. It crypts
46the first 8 characters of the password using a 20-round version of crypt
47(standard crypt does 25 rounds). It then crypts the next 8 characters,
48or an empty block if the password is less than 9 characters, using a
4920-round version of crypt and the same salt as was used for the first
4c04137d 50block. Characters after the first 16 are ignored. It always generates
96c065cb
PH
51a 16-byte hash, which is expressed together with the salt as a string
52of 24 base 64 digits. Here are some links to peruse:
53
54 http://cvs.pld.org.pl/pam/pamcrypt/crypt16.c?rev=1.2
55 http://seclists.org/bugtraq/1999/Mar/0076.html
56
57There's a different algorithm named "bigcrypt" in HP-UX, Digital Unix,
58and OSF/1. This is the same as the standard crypt if given a password
59of 8 characters or less. If given more, it first does the same as crypt
60using the first 8 characters, then crypts the next 8 (the 9th to 16th)
61using as salt the first two base 64 digits from the first hash block.
62If the password is more than 16 characters then it crypts the 17th to 24th
63characters using as salt the first two base 64 digits from the second hash
64block. And so on: I've seen references to it cutting off the password at
6540 characters (5 blocks), 80 (10 blocks), or 128 (16 blocks). Some links:
66
67 http://cvs.pld.org.pl/pam/pamcrypt/bigcrypt.c?rev=1.2
68 http://seclists.org/bugtraq/1999/Mar/0109.html
69 http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/HTML/AA-Q0R2D-
70 TET1_html/sec.c222.html#no_id_208
71
72Exim has something it calls "crypt16". It will either use a native
73crypt16 or its own implementation. A native crypt16 will presumably
74be the one that I called "crypt16" above. The internal "crypt16"
75function, however, is a two-block-maximum implementation of what I called
76"bigcrypt". The documentation matches the internal code.
77
78I suspect that whoever did the "crypt16" stuff for Exim didn't realise
79that crypt16 and bigcrypt were different things.
80
81Exim uses the LDAP-style scheme identifier "{crypt16}" to refer
82to whatever it is using under that name. This unfortunately sets a
83precedent for using "{crypt16}" to identify two incompatible algorithms
84whose output can't be distinguished. With "{crypt16}" thus rendered
85ambiguous, I suggest you deprecate it and invent two new identifiers
86for the two algorithms.
87
88Both crypt16 and bigcrypt are very poor algorithms, btw. Hashing parts
89of the password separately means they can be cracked separately, so
90the double-length hash only doubles the cracking effort instead of
91squaring it. I recommend salted SHA-1 ({SSHA}), or the Blowfish-based
92bcrypt ({CRYPT}$2a$).
93</quote>
94*/
059ec3d9
PH
95
96
059ec3d9 97
059ec3d9
PH
98/*************************************************
99* Local statics and tables *
100*************************************************/
101
102/* Table of item names, and corresponding switch numbers. The names must be in
103alphabetical order. */
104
105static uschar *item_table[] = {
723c72e6 106 US"acl",
dfbcb5ac 107 US"authresults",
9d1c15ef 108 US"certextract",
1a46a8c5 109 US"dlfunc",
089fc87a 110 US"env",
059ec3d9 111 US"extract",
29f89cad 112 US"filter",
059ec3d9
PH
113 US"hash",
114 US"hmac",
115 US"if",
8c5d388a 116#ifdef SUPPORT_I18N
ed0512a1
JH
117 US"imapfolder",
118#endif
059ec3d9 119 US"length",
aa26e137 120 US"listextract",
48b30ae1 121 US"listquote",
059ec3d9 122 US"lookup",
29f89cad 123 US"map",
059ec3d9 124 US"nhash",
1a46a8c5 125 US"perl",
fffda43a
TK
126 US"prvs",
127 US"prvscheck",
059ec3d9
PH
128 US"readfile",
129 US"readsocket",
29f89cad 130 US"reduce",
059ec3d9
PH
131 US"run",
132 US"sg",
ac4ef9bd 133 US"sort",
7ef88aa0
JH
134#ifdef EXPERIMENTAL_SRS_NATIVE
135 US"srs_encode",
136#endif
059ec3d9
PH
137 US"substr",
138 US"tr" };
139
140enum {
723c72e6 141 EITEM_ACL,
dfbcb5ac 142 EITEM_AUTHRESULTS,
9d1c15ef 143 EITEM_CERTEXTRACT,
1a46a8c5 144 EITEM_DLFUNC,
089fc87a 145 EITEM_ENV,
059ec3d9 146 EITEM_EXTRACT,
29f89cad 147 EITEM_FILTER,
059ec3d9
PH
148 EITEM_HASH,
149 EITEM_HMAC,
150 EITEM_IF,
8c5d388a 151#ifdef SUPPORT_I18N
ed0512a1
JH
152 EITEM_IMAPFOLDER,
153#endif
059ec3d9 154 EITEM_LENGTH,
aa26e137 155 EITEM_LISTEXTRACT,
48b30ae1 156 EITEM_LISTQUOTE,
059ec3d9 157 EITEM_LOOKUP,
29f89cad 158 EITEM_MAP,
059ec3d9 159 EITEM_NHASH,
1a46a8c5 160 EITEM_PERL,
fffda43a
TK
161 EITEM_PRVS,
162 EITEM_PRVSCHECK,
059ec3d9
PH
163 EITEM_READFILE,
164 EITEM_READSOCK,
29f89cad 165 EITEM_REDUCE,
059ec3d9
PH
166 EITEM_RUN,
167 EITEM_SG,
ac4ef9bd 168 EITEM_SORT,
7ef88aa0
JH
169#ifdef EXPERIMENTAL_SRS_NATIVE
170 EITEM_SRS_ENCODE,
171#endif
059ec3d9
PH
172 EITEM_SUBSTR,
173 EITEM_TR };
174
175/* Tables of operator names, and corresponding switch numbers. The names must be
176in alphabetical order. There are two tables, because underscore is used in some
177cases to introduce arguments, whereas for other it is part of the name. This is
178an historical mis-design. */
179
180static uschar *op_table_underscore[] = {
181 US"from_utf8",
182 US"local_part",
183 US"quote_local_part",
83e029d5 184 US"reverse_ip",
f90d018c 185 US"time_eval",
4e08fd50 186 US"time_interval"
8c5d388a 187#ifdef SUPPORT_I18N
4e08fd50
JH
188 ,US"utf8_domain_from_alabel",
189 US"utf8_domain_to_alabel",
190 US"utf8_localpart_from_alabel",
191 US"utf8_localpart_to_alabel"
192#endif
193 };
059ec3d9
PH
194
195enum {
196 EOP_FROM_UTF8,
197 EOP_LOCAL_PART,
198 EOP_QUOTE_LOCAL_PART,
83e029d5 199 EOP_REVERSE_IP,
f90d018c 200 EOP_TIME_EVAL,
4e08fd50 201 EOP_TIME_INTERVAL
8c5d388a 202#ifdef SUPPORT_I18N
4e08fd50
JH
203 ,EOP_UTF8_DOMAIN_FROM_ALABEL,
204 EOP_UTF8_DOMAIN_TO_ALABEL,
205 EOP_UTF8_LOCALPART_FROM_ALABEL,
206 EOP_UTF8_LOCALPART_TO_ALABEL
207#endif
208 };
059ec3d9
PH
209
210static uschar *op_table_main[] = {
211 US"address",
29f89cad 212 US"addresses",
03ca21f8
JH
213 US"base32",
214 US"base32d",
059ec3d9
PH
215 US"base62",
216 US"base62d",
9aa35e9c
JH
217 US"base64",
218 US"base64d",
0d2e392e 219 US"bless",
059ec3d9
PH
220 US"domain",
221 US"escape",
3367f8c2 222 US"escape8bit",
059ec3d9
PH
223 US"eval",
224 US"eval10",
225 US"expand",
226 US"h",
227 US"hash",
228 US"hex2b64",
c393f931 229 US"hexquote",
fc4a7f70
JH
230 US"ipv6denorm",
231 US"ipv6norm",
059ec3d9
PH
232 US"l",
233 US"lc",
234 US"length",
a64a3dfa
JH
235 US"listcount",
236 US"listnamed",
059ec3d9
PH
237 US"mask",
238 US"md5",
239 US"nh",
240 US"nhash",
241 US"quote",
9e3331ea 242 US"randint",
059ec3d9 243 US"rfc2047",
9c57cbc0 244 US"rfc2047d",
059ec3d9
PH
245 US"rxquote",
246 US"s",
247 US"sha1",
12e9bb25 248 US"sha2",
9ef9101c 249 US"sha256",
6e773413 250 US"sha3",
059ec3d9
PH
251 US"stat",
252 US"str2b64",
253 US"strlen",
254 US"substr",
b9c2e32f
AR
255 US"uc",
256 US"utf8clean" };
059ec3d9
PH
257
258enum {
0539a19d 259 EOP_ADDRESS = nelem(op_table_underscore),
29f89cad 260 EOP_ADDRESSES,
03ca21f8
JH
261 EOP_BASE32,
262 EOP_BASE32D,
059ec3d9
PH
263 EOP_BASE62,
264 EOP_BASE62D,
9aa35e9c
JH
265 EOP_BASE64,
266 EOP_BASE64D,
0d2e392e 267 EOP_BLESS,
059ec3d9
PH
268 EOP_DOMAIN,
269 EOP_ESCAPE,
3367f8c2 270 EOP_ESCAPE8BIT,
059ec3d9
PH
271 EOP_EVAL,
272 EOP_EVAL10,
273 EOP_EXPAND,
274 EOP_H,
275 EOP_HASH,
276 EOP_HEX2B64,
c393f931 277 EOP_HEXQUOTE,
fc4a7f70
JH
278 EOP_IPV6DENORM,
279 EOP_IPV6NORM,
059ec3d9
PH
280 EOP_L,
281 EOP_LC,
282 EOP_LENGTH,
a64a3dfa
JH
283 EOP_LISTCOUNT,
284 EOP_LISTNAMED,
059ec3d9
PH
285 EOP_MASK,
286 EOP_MD5,
287 EOP_NH,
288 EOP_NHASH,
289 EOP_QUOTE,
9e3331ea 290 EOP_RANDINT,
059ec3d9 291 EOP_RFC2047,
9c57cbc0 292 EOP_RFC2047D,
059ec3d9
PH
293 EOP_RXQUOTE,
294 EOP_S,
295 EOP_SHA1,
12e9bb25 296 EOP_SHA2,
9ef9101c 297 EOP_SHA256,
6e773413 298 EOP_SHA3,
059ec3d9
PH
299 EOP_STAT,
300 EOP_STR2B64,
301 EOP_STRLEN,
302 EOP_SUBSTR,
b9c2e32f
AR
303 EOP_UC,
304 EOP_UTF8CLEAN };
059ec3d9
PH
305
306
307/* Table of condition names, and corresponding switch numbers. The names must
308be in alphabetical order. */
309
310static uschar *cond_table[] = {
311 US"<",
312 US"<=",
313 US"=",
314 US"==", /* Backward compatibility */
315 US">",
316 US">=",
333eea9c 317 US"acl",
059ec3d9 318 US"and",
f3766eb5 319 US"bool",
6a8de854 320 US"bool_lax",
059ec3d9
PH
321 US"crypteq",
322 US"def",
323 US"eq",
324 US"eqi",
325 US"exists",
326 US"first_delivery",
0ce9abe6 327 US"forall",
7f69e814
JH
328 US"forall_json",
329 US"forall_jsons",
0ce9abe6 330 US"forany",
7f69e814
JH
331 US"forany_json",
332 US"forany_jsons",
059ec3d9
PH
333 US"ge",
334 US"gei",
335 US"gt",
336 US"gti",
7ef88aa0
JH
337#ifdef EXPERIMENTAL_SRS_NATIVE
338 US"inbound_srs",
339#endif
76dca828
PP
340 US"inlist",
341 US"inlisti",
059ec3d9
PH
342 US"isip",
343 US"isip4",
344 US"isip6",
345 US"ldapauth",
346 US"le",
347 US"lei",
348 US"lt",
349 US"lti",
350 US"match",
351 US"match_address",
352 US"match_domain",
32d668a5 353 US"match_ip",
059ec3d9
PH
354 US"match_local_part",
355 US"or",
356 US"pam",
357 US"pwcheck",
358 US"queue_running",
359 US"radius",
360 US"saslauthd"
361};
362
363enum {
364 ECOND_NUM_L,
365 ECOND_NUM_LE,
366 ECOND_NUM_E,
367 ECOND_NUM_EE,
368 ECOND_NUM_G,
369 ECOND_NUM_GE,
333eea9c 370 ECOND_ACL,
059ec3d9 371 ECOND_AND,
f3766eb5 372 ECOND_BOOL,
6a8de854 373 ECOND_BOOL_LAX,
059ec3d9
PH
374 ECOND_CRYPTEQ,
375 ECOND_DEF,
376 ECOND_STR_EQ,
377 ECOND_STR_EQI,
378 ECOND_EXISTS,
379 ECOND_FIRST_DELIVERY,
0ce9abe6 380 ECOND_FORALL,
7f69e814
JH
381 ECOND_FORALL_JSON,
382 ECOND_FORALL_JSONS,
0ce9abe6 383 ECOND_FORANY,
7f69e814
JH
384 ECOND_FORANY_JSON,
385 ECOND_FORANY_JSONS,
059ec3d9
PH
386 ECOND_STR_GE,
387 ECOND_STR_GEI,
388 ECOND_STR_GT,
389 ECOND_STR_GTI,
7ef88aa0
JH
390#ifdef EXPERIMENTAL_SRS_NATIVE
391 ECOND_INBOUND_SRS,
392#endif
76dca828
PP
393 ECOND_INLIST,
394 ECOND_INLISTI,
059ec3d9
PH
395 ECOND_ISIP,
396 ECOND_ISIP4,
397 ECOND_ISIP6,
398 ECOND_LDAPAUTH,
399 ECOND_STR_LE,
400 ECOND_STR_LEI,
401 ECOND_STR_LT,
402 ECOND_STR_LTI,
403 ECOND_MATCH,
404 ECOND_MATCH_ADDRESS,
405 ECOND_MATCH_DOMAIN,
32d668a5 406 ECOND_MATCH_IP,
059ec3d9
PH
407 ECOND_MATCH_LOCAL_PART,
408 ECOND_OR,
409 ECOND_PAM,
410 ECOND_PWCHECK,
411 ECOND_QUEUE_RUNNING,
412 ECOND_RADIUS,
413 ECOND_SASLAUTHD
414};
415
416
059ec3d9
PH
417/* Types of table entry */
418
7e75538e 419enum vtypes {
059ec3d9
PH
420 vtype_int, /* value is address of int */
421 vtype_filter_int, /* ditto, but recognized only when filtering */
422 vtype_ino, /* value is address of ino_t (not always an int) */
423 vtype_uid, /* value is address of uid_t (not always an int) */
424 vtype_gid, /* value is address of gid_t (not always an int) */
11d7e4fa 425 vtype_bool, /* value is address of bool */
059ec3d9
PH
426 vtype_stringptr, /* value is address of pointer to string */
427 vtype_msgbody, /* as stringptr, but read when first required */
428 vtype_msgbody_end, /* ditto, the end of the message */
ff75a1f7
PH
429 vtype_msgheaders, /* the message's headers, processed */
430 vtype_msgheaders_raw, /* the message's headers, unprocessed */
059ec3d9
PH
431 vtype_localpart, /* extract local part from string */
432 vtype_domain, /* extract domain from string */
362145b5 433 vtype_string_func, /* value is string returned by given function */
059ec3d9
PH
434 vtype_todbsdin, /* value not used; generate BSD inbox tod */
435 vtype_tode, /* value not used; generate tod in epoch format */
f5787926 436 vtype_todel, /* value not used; generate tod in epoch/usec format */
059ec3d9
PH
437 vtype_todf, /* value not used; generate full tod */
438 vtype_todl, /* value not used; generate log tod */
439 vtype_todlf, /* value not used; generate log file datestamp tod */
440 vtype_todzone, /* value not used; generate time zone only */
441 vtype_todzulu, /* value not used; generate zulu tod */
442 vtype_reply, /* value not used; get reply from headers */
443 vtype_pid, /* value not used; result is pid */
444 vtype_host_lookup, /* value not used; get host name */
5cb8cbc6
PH
445 vtype_load_avg, /* value not used; result is int from os_getloadavg */
446 vtype_pspace, /* partition space; value is T/F for spool/log */
9d1c15ef
JH
447 vtype_pinodes, /* partition inodes; value is T/F for spool/log */
448 vtype_cert /* SSL certificate */
80a47a2c
TK
449 #ifndef DISABLE_DKIM
450 ,vtype_dkim /* Lookup of value in DKIM signature */
451 #endif
7e75538e
JH
452};
453
454/* Type for main variable table */
455
456typedef struct {
457 const char *name;
458 enum vtypes type;
459 void *value;
460} var_entry;
461
462/* Type for entries pointing to address/length pairs. Not currently
463in use. */
464
465typedef struct {
466 uschar **address;
467 int *length;
468} alblock;
059ec3d9 469
362145b5 470static uschar * fn_recipients(void);
6d95688d 471typedef uschar * stringptr_fn_t(void);
04403ab0 472static uschar * fn_queue_size(void);
362145b5 473
059ec3d9
PH
474/* This table must be kept in alphabetical order. */
475
476static var_entry var_table[] = {
38a0a95f
PH
477 /* WARNING: Do not invent variables whose names start acl_c or acl_m because
478 they will be confused with user-creatable ACL variables. */
525239c1
JH
479 { "acl_arg1", vtype_stringptr, &acl_arg[0] },
480 { "acl_arg2", vtype_stringptr, &acl_arg[1] },
481 { "acl_arg3", vtype_stringptr, &acl_arg[2] },
482 { "acl_arg4", vtype_stringptr, &acl_arg[3] },
483 { "acl_arg5", vtype_stringptr, &acl_arg[4] },
484 { "acl_arg6", vtype_stringptr, &acl_arg[5] },
485 { "acl_arg7", vtype_stringptr, &acl_arg[6] },
486 { "acl_arg8", vtype_stringptr, &acl_arg[7] },
487 { "acl_arg9", vtype_stringptr, &acl_arg[8] },
488 { "acl_narg", vtype_int, &acl_narg },
059ec3d9
PH
489 { "acl_verify_message", vtype_stringptr, &acl_verify_message },
490 { "address_data", vtype_stringptr, &deliver_address_data },
491 { "address_file", vtype_stringptr, &address_file },
492 { "address_pipe", vtype_stringptr, &address_pipe },
93c931f8 493#ifdef EXPERIMENTAL_ARC
6d95688d 494 { "arc_domains", vtype_string_func, (void *) &fn_arc_domains },
ea7b1f16 495 { "arc_oldest_pass", vtype_int, &arc_oldest_pass },
93c931f8
JH
496 { "arc_state", vtype_stringptr, &arc_state },
497 { "arc_state_reason", vtype_stringptr, &arc_state_reason },
498#endif
2d07a215 499 { "authenticated_fail_id",vtype_stringptr, &authenticated_fail_id },
059ec3d9
PH
500 { "authenticated_id", vtype_stringptr, &authenticated_id },
501 { "authenticated_sender",vtype_stringptr, &authenticated_sender },
502 { "authentication_failed",vtype_int, &authentication_failed },
9e949f00
PP
503#ifdef WITH_CONTENT_SCAN
504 { "av_failed", vtype_int, &av_failed },
505#endif
8523533c
TK
506#ifdef EXPERIMENTAL_BRIGHTMAIL
507 { "bmi_alt_location", vtype_stringptr, &bmi_alt_location },
508 { "bmi_base64_tracker_verdict", vtype_stringptr, &bmi_base64_tracker_verdict },
509 { "bmi_base64_verdict", vtype_stringptr, &bmi_base64_verdict },
510 { "bmi_deliver", vtype_int, &bmi_deliver },
511#endif
059ec3d9
PH
512 { "body_linecount", vtype_int, &body_linecount },
513 { "body_zerocount", vtype_int, &body_zerocount },
514 { "bounce_recipient", vtype_stringptr, &bounce_recipient },
515 { "bounce_return_size_limit", vtype_int, &bounce_return_size_limit },
516 { "caller_gid", vtype_gid, &real_gid },
517 { "caller_uid", vtype_uid, &real_uid },
055e2cb4 518 { "callout_address", vtype_stringptr, &callout_address },
059ec3d9
PH
519 { "compile_date", vtype_stringptr, &version_date },
520 { "compile_number", vtype_stringptr, &version_cnumber },
98b8312f
HSHR
521 { "config_dir", vtype_stringptr, &config_main_directory },
522 { "config_file", vtype_stringptr, &config_main_filename },
e5a9dba6 523 { "csa_status", vtype_stringptr, &csa_status },
6a8f9482
TK
524#ifdef EXPERIMENTAL_DCC
525 { "dcc_header", vtype_stringptr, &dcc_header },
526 { "dcc_result", vtype_stringptr, &dcc_result },
527#endif
80a47a2c
TK
528#ifndef DISABLE_DKIM
529 { "dkim_algo", vtype_dkim, (void *)DKIM_ALGO },
530 { "dkim_bodylength", vtype_dkim, (void *)DKIM_BODYLENGTH },
531 { "dkim_canon_body", vtype_dkim, (void *)DKIM_CANON_BODY },
532 { "dkim_canon_headers", vtype_dkim, (void *)DKIM_CANON_HEADERS },
533 { "dkim_copiedheaders", vtype_dkim, (void *)DKIM_COPIEDHEADERS },
534 { "dkim_created", vtype_dkim, (void *)DKIM_CREATED },
2df588c9 535 { "dkim_cur_signer", vtype_stringptr, &dkim_cur_signer },
e08d09e5 536 { "dkim_domain", vtype_stringptr, &dkim_signing_domain },
80a47a2c
TK
537 { "dkim_expires", vtype_dkim, (void *)DKIM_EXPIRES },
538 { "dkim_headernames", vtype_dkim, (void *)DKIM_HEADERNAMES },
539 { "dkim_identity", vtype_dkim, (void *)DKIM_IDENTITY },
540 { "dkim_key_granularity",vtype_dkim, (void *)DKIM_KEY_GRANULARITY },
abe1010c 541 { "dkim_key_length", vtype_int, &dkim_key_length },
80a47a2c
TK
542 { "dkim_key_nosubdomains",vtype_dkim, (void *)DKIM_NOSUBDOMAINS },
543 { "dkim_key_notes", vtype_dkim, (void *)DKIM_KEY_NOTES },
544 { "dkim_key_srvtype", vtype_dkim, (void *)DKIM_KEY_SRVTYPE },
545 { "dkim_key_testing", vtype_dkim, (void *)DKIM_KEY_TESTING },
e08d09e5 546 { "dkim_selector", vtype_stringptr, &dkim_signing_selector },
9e5d6b55 547 { "dkim_signers", vtype_stringptr, &dkim_signers },
a79d8834
JH
548 { "dkim_verify_reason", vtype_stringptr, &dkim_verify_reason },
549 { "dkim_verify_status", vtype_stringptr, &dkim_verify_status },
e08d09e5 550#endif
1a2e76e1 551#ifdef SUPPORT_DMARC
8c8b8274 552 { "dmarc_domain_policy", vtype_stringptr, &dmarc_domain_policy },
4840604e
TL
553 { "dmarc_status", vtype_stringptr, &dmarc_status },
554 { "dmarc_status_text", vtype_stringptr, &dmarc_status_text },
555 { "dmarc_used_domain", vtype_stringptr, &dmarc_used_domain },
556#endif
059ec3d9 557 { "dnslist_domain", vtype_stringptr, &dnslist_domain },
93655c46 558 { "dnslist_matched", vtype_stringptr, &dnslist_matched },
059ec3d9
PH
559 { "dnslist_text", vtype_stringptr, &dnslist_text },
560 { "dnslist_value", vtype_stringptr, &dnslist_value },
561 { "domain", vtype_stringptr, &deliver_domain },
562 { "domain_data", vtype_stringptr, &deliver_domain_data },
0cbf2b82 563#ifndef DISABLE_EVENT
774ef2d7
JH
564 { "event_data", vtype_stringptr, &event_data },
565
566 /*XXX want to use generic vars for as many of these as possible*/
567 { "event_defer_errno", vtype_int, &event_defer_errno },
568
569 { "event_name", vtype_stringptr, &event_name },
570#endif
059ec3d9
PH
571 { "exim_gid", vtype_gid, &exim_gid },
572 { "exim_path", vtype_stringptr, &exim_path },
573 { "exim_uid", vtype_uid, &exim_uid },
71224040 574 { "exim_version", vtype_stringptr, &version_string },
6d95688d 575 { "headers_added", vtype_string_func, (void *) &fn_hdrs_added },
059ec3d9
PH
576 { "home", vtype_stringptr, &deliver_home },
577 { "host", vtype_stringptr, &deliver_host },
578 { "host_address", vtype_stringptr, &deliver_host_address },
579 { "host_data", vtype_stringptr, &host_data },
b08b24c8 580 { "host_lookup_deferred",vtype_int, &host_lookup_deferred },
059ec3d9 581 { "host_lookup_failed", vtype_int, &host_lookup_failed },
a7538db1 582 { "host_port", vtype_int, &deliver_host_port },
3615fa9a 583 { "initial_cwd", vtype_stringptr, &initial_cwd },
059ec3d9
PH
584 { "inode", vtype_ino, &deliver_inode },
585 { "interface_address", vtype_stringptr, &interface_address },
586 { "interface_port", vtype_int, &interface_port },
0ce9abe6 587 { "item", vtype_stringptr, &iterate_item },
059ec3d9
PH
588 #ifdef LOOKUP_LDAP
589 { "ldap_dn", vtype_stringptr, &eldap_dn },
590 #endif
591 { "load_average", vtype_load_avg, NULL },
592 { "local_part", vtype_stringptr, &deliver_localpart },
593 { "local_part_data", vtype_stringptr, &deliver_localpart_data },
594 { "local_part_prefix", vtype_stringptr, &deliver_localpart_prefix },
759502e5 595 { "local_part_prefix_v", vtype_stringptr, &deliver_localpart_prefix_v },
059ec3d9 596 { "local_part_suffix", vtype_stringptr, &deliver_localpart_suffix },
759502e5 597 { "local_part_suffix_v", vtype_stringptr, &deliver_localpart_suffix_v },
163144aa 598 { "local_part_verified", vtype_stringptr, &deliver_localpart_verified },
9723f966 599#ifdef HAVE_LOCAL_SCAN
059ec3d9 600 { "local_scan_data", vtype_stringptr, &local_scan_data },
9723f966 601#endif
059ec3d9
PH
602 { "local_user_gid", vtype_gid, &local_user_gid },
603 { "local_user_uid", vtype_uid, &local_user_uid },
604 { "localhost_number", vtype_int, &host_number },
5cb8cbc6 605 { "log_inodes", vtype_pinodes, (void *)FALSE },
8e669ac1 606 { "log_space", vtype_pspace, (void *)FALSE },
4e0983dc 607 { "lookup_dnssec_authenticated",vtype_stringptr,&lookup_dnssec_authenticated},
059ec3d9 608 { "mailstore_basename", vtype_stringptr, &mailstore_basename },
8523533c
TK
609#ifdef WITH_CONTENT_SCAN
610 { "malware_name", vtype_stringptr, &malware_name },
611#endif
d677b2f2 612 { "max_received_linelength", vtype_int, &max_received_linelength },
059ec3d9
PH
613 { "message_age", vtype_int, &message_age },
614 { "message_body", vtype_msgbody, &message_body },
615 { "message_body_end", vtype_msgbody_end, &message_body_end },
616 { "message_body_size", vtype_int, &message_body_size },
1ab52c69 617 { "message_exim_id", vtype_stringptr, &message_id },
059ec3d9 618 { "message_headers", vtype_msgheaders, NULL },
ff75a1f7 619 { "message_headers_raw", vtype_msgheaders_raw, NULL },
059ec3d9 620 { "message_id", vtype_stringptr, &message_id },
2e0c1448 621 { "message_linecount", vtype_int, &message_linecount },
059ec3d9 622 { "message_size", vtype_int, &message_size },
8c5d388a 623#ifdef SUPPORT_I18N
eb02f5df
JH
624 { "message_smtputf8", vtype_bool, &message_smtputf8 },
625#endif
8523533c
TK
626#ifdef WITH_CONTENT_SCAN
627 { "mime_anomaly_level", vtype_int, &mime_anomaly_level },
628 { "mime_anomaly_text", vtype_stringptr, &mime_anomaly_text },
629 { "mime_boundary", vtype_stringptr, &mime_boundary },
630 { "mime_charset", vtype_stringptr, &mime_charset },
631 { "mime_content_description", vtype_stringptr, &mime_content_description },
632 { "mime_content_disposition", vtype_stringptr, &mime_content_disposition },
633 { "mime_content_id", vtype_stringptr, &mime_content_id },
634 { "mime_content_size", vtype_int, &mime_content_size },
635 { "mime_content_transfer_encoding",vtype_stringptr, &mime_content_transfer_encoding },
636 { "mime_content_type", vtype_stringptr, &mime_content_type },
637 { "mime_decoded_filename", vtype_stringptr, &mime_decoded_filename },
638 { "mime_filename", vtype_stringptr, &mime_filename },
639 { "mime_is_coverletter", vtype_int, &mime_is_coverletter },
640 { "mime_is_multipart", vtype_int, &mime_is_multipart },
641 { "mime_is_rfc822", vtype_int, &mime_is_rfc822 },
642 { "mime_part_count", vtype_int, &mime_part_count },
643#endif
059ec3d9
PH
644 { "n0", vtype_filter_int, &filter_n[0] },
645 { "n1", vtype_filter_int, &filter_n[1] },
646 { "n2", vtype_filter_int, &filter_n[2] },
647 { "n3", vtype_filter_int, &filter_n[3] },
648 { "n4", vtype_filter_int, &filter_n[4] },
649 { "n5", vtype_filter_int, &filter_n[5] },
650 { "n6", vtype_filter_int, &filter_n[6] },
651 { "n7", vtype_filter_int, &filter_n[7] },
652 { "n8", vtype_filter_int, &filter_n[8] },
653 { "n9", vtype_filter_int, &filter_n[9] },
654 { "original_domain", vtype_stringptr, &deliver_domain_orig },
655 { "original_local_part", vtype_stringptr, &deliver_localpart_orig },
656 { "originator_gid", vtype_gid, &originator_gid },
657 { "originator_uid", vtype_uid, &originator_uid },
658 { "parent_domain", vtype_stringptr, &deliver_domain_parent },
659 { "parent_local_part", vtype_stringptr, &deliver_localpart_parent },
660 { "pid", vtype_pid, NULL },
858e91c2
JH
661#ifndef DISABLE_PRDR
662 { "prdr_requested", vtype_bool, &prdr_requested },
663#endif
059ec3d9 664 { "primary_hostname", vtype_stringptr, &primary_hostname },
e6d2a989
JH
665#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
666 { "proxy_external_address",vtype_stringptr, &proxy_external_address },
667 { "proxy_external_port", vtype_int, &proxy_external_port },
668 { "proxy_local_address", vtype_stringptr, &proxy_local_address },
669 { "proxy_local_port", vtype_int, &proxy_local_port },
a3c86431
TL
670 { "proxy_session", vtype_bool, &proxy_session },
671#endif
fffda43a
TK
672 { "prvscheck_address", vtype_stringptr, &prvscheck_address },
673 { "prvscheck_keynum", vtype_stringptr, &prvscheck_keynum },
674 { "prvscheck_result", vtype_stringptr, &prvscheck_result },
059ec3d9
PH
675 { "qualify_domain", vtype_stringptr, &qualify_domain_sender },
676 { "qualify_recipient", vtype_stringptr, &qualify_domain_recipient },
0cd5fd23 677 { "queue_name", vtype_stringptr, &queue_name },
04403ab0 678 { "queue_size", vtype_string_func, &fn_queue_size },
059ec3d9
PH
679 { "rcpt_count", vtype_int, &rcpt_count },
680 { "rcpt_defer_count", vtype_int, &rcpt_defer_count },
681 { "rcpt_fail_count", vtype_int, &rcpt_fail_count },
682 { "received_count", vtype_int, &received_count },
683 { "received_for", vtype_stringptr, &received_for },
194cc0e4
PH
684 { "received_ip_address", vtype_stringptr, &interface_address },
685 { "received_port", vtype_int, &interface_port },
059ec3d9 686 { "received_protocol", vtype_stringptr, &received_protocol },
32dfdf8b 687 { "received_time", vtype_int, &received_time.tv_sec },
059ec3d9 688 { "recipient_data", vtype_stringptr, &recipient_data },
8e669ac1 689 { "recipient_verify_failure",vtype_stringptr,&recipient_verify_failure },
6d95688d 690 { "recipients", vtype_string_func, (void *) &fn_recipients },
059ec3d9 691 { "recipients_count", vtype_int, &recipients_count },
8523533c
TK
692#ifdef WITH_CONTENT_SCAN
693 { "regex_match_string", vtype_stringptr, &regex_match_string },
694#endif
059ec3d9
PH
695 { "reply_address", vtype_reply, NULL },
696 { "return_path", vtype_stringptr, &return_path },
697 { "return_size_limit", vtype_int, &bounce_return_size_limit },
181d9bf8 698 { "router_name", vtype_stringptr, &router_name },
059ec3d9
PH
699 { "runrc", vtype_int, &runrc },
700 { "self_hostname", vtype_stringptr, &self_hostname },
701 { "sender_address", vtype_stringptr, &sender_address },
2a3eea10 702 { "sender_address_data", vtype_stringptr, &sender_address_data },
059ec3d9
PH
703 { "sender_address_domain", vtype_domain, &sender_address },
704 { "sender_address_local_part", vtype_localpart, &sender_address },
705 { "sender_data", vtype_stringptr, &sender_data },
706 { "sender_fullhost", vtype_stringptr, &sender_fullhost },
1705dd20 707 { "sender_helo_dnssec", vtype_bool, &sender_helo_dnssec },
059ec3d9
PH
708 { "sender_helo_name", vtype_stringptr, &sender_helo_name },
709 { "sender_host_address", vtype_stringptr, &sender_host_address },
710 { "sender_host_authenticated",vtype_stringptr, &sender_host_authenticated },
11d7e4fa 711 { "sender_host_dnssec", vtype_bool, &sender_host_dnssec },
059ec3d9
PH
712 { "sender_host_name", vtype_host_lookup, NULL },
713 { "sender_host_port", vtype_int, &sender_host_port },
714 { "sender_ident", vtype_stringptr, &sender_ident },
870f6ba8
TF
715 { "sender_rate", vtype_stringptr, &sender_rate },
716 { "sender_rate_limit", vtype_stringptr, &sender_rate_limit },
717 { "sender_rate_period", vtype_stringptr, &sender_rate_period },
059ec3d9 718 { "sender_rcvhost", vtype_stringptr, &sender_rcvhost },
8e669ac1 719 { "sender_verify_failure",vtype_stringptr, &sender_verify_failure },
41c7c167
PH
720 { "sending_ip_address", vtype_stringptr, &sending_ip_address },
721 { "sending_port", vtype_int, &sending_port },
8e669ac1 722 { "smtp_active_hostname", vtype_stringptr, &smtp_active_hostname },
3ee512ff
PH
723 { "smtp_command", vtype_stringptr, &smtp_cmd_buffer },
724 { "smtp_command_argument", vtype_stringptr, &smtp_cmd_argument },
6d95688d 725 { "smtp_command_history", vtype_string_func, (void *) &smtp_cmd_hist },
b01dd148 726 { "smtp_count_at_connection_start", vtype_int, &smtp_accept_count },
8f128379 727 { "smtp_notquit_reason", vtype_stringptr, &smtp_notquit_reason },
059ec3d9
PH
728 { "sn0", vtype_filter_int, &filter_sn[0] },
729 { "sn1", vtype_filter_int, &filter_sn[1] },
730 { "sn2", vtype_filter_int, &filter_sn[2] },
731 { "sn3", vtype_filter_int, &filter_sn[3] },
732 { "sn4", vtype_filter_int, &filter_sn[4] },
733 { "sn5", vtype_filter_int, &filter_sn[5] },
734 { "sn6", vtype_filter_int, &filter_sn[6] },
735 { "sn7", vtype_filter_int, &filter_sn[7] },
736 { "sn8", vtype_filter_int, &filter_sn[8] },
737 { "sn9", vtype_filter_int, &filter_sn[9] },
8523533c 738#ifdef WITH_CONTENT_SCAN
c5f280e2 739 { "spam_action", vtype_stringptr, &spam_action },
8523533c
TK
740 { "spam_bar", vtype_stringptr, &spam_bar },
741 { "spam_report", vtype_stringptr, &spam_report },
742 { "spam_score", vtype_stringptr, &spam_score },
743 { "spam_score_int", vtype_stringptr, &spam_score_int },
744#endif
7952eef9 745#ifdef SUPPORT_SPF
65a7d8c3 746 { "spf_guess", vtype_stringptr, &spf_guess },
8523533c
TK
747 { "spf_header_comment", vtype_stringptr, &spf_header_comment },
748 { "spf_received", vtype_stringptr, &spf_received },
749 { "spf_result", vtype_stringptr, &spf_result },
87e9d061 750 { "spf_result_guessed", vtype_bool, &spf_result_guessed },
8523533c
TK
751 { "spf_smtp_comment", vtype_stringptr, &spf_smtp_comment },
752#endif
059ec3d9 753 { "spool_directory", vtype_stringptr, &spool_directory },
5cb8cbc6 754 { "spool_inodes", vtype_pinodes, (void *)TRUE },
8e669ac1 755 { "spool_space", vtype_pspace, (void *)TRUE },
8523533c
TK
756#ifdef EXPERIMENTAL_SRS
757 { "srs_db_address", vtype_stringptr, &srs_db_address },
758 { "srs_db_key", vtype_stringptr, &srs_db_key },
759 { "srs_orig_recipient", vtype_stringptr, &srs_orig_recipient },
760 { "srs_orig_sender", vtype_stringptr, &srs_orig_sender },
7ef88aa0
JH
761#endif
762#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE)
8523533c 763 { "srs_recipient", vtype_stringptr, &srs_recipient },
7ef88aa0
JH
764#endif
765#ifdef EXPERIMENTAL_SRS
8523533c
TK
766 { "srs_status", vtype_stringptr, &srs_status },
767#endif
059ec3d9 768 { "thisaddress", vtype_stringptr, &filter_thisaddress },
817d9f57 769
d9b2312b 770 /* The non-(in,out) variables are now deprecated */
817d9f57
JH
771 { "tls_bits", vtype_int, &tls_in.bits },
772 { "tls_certificate_verified", vtype_int, &tls_in.certificate_verified },
773 { "tls_cipher", vtype_stringptr, &tls_in.cipher },
d9b2312b
JH
774
775 { "tls_in_bits", vtype_int, &tls_in.bits },
776 { "tls_in_certificate_verified", vtype_int, &tls_in.certificate_verified },
777 { "tls_in_cipher", vtype_stringptr, &tls_in.cipher },
f1be21cf 778 { "tls_in_cipher_std", vtype_stringptr, &tls_in.cipher_stdname },
44662487 779 { "tls_in_ocsp", vtype_int, &tls_in.ocsp },
9d1c15ef
JH
780 { "tls_in_ourcert", vtype_cert, &tls_in.ourcert },
781 { "tls_in_peercert", vtype_cert, &tls_in.peercert },
d9b2312b 782 { "tls_in_peerdn", vtype_stringptr, &tls_in.peerdn },
b10c87b3
JH
783#ifdef EXPERIMENTAL_TLS_RESUME
784 { "tls_in_resumption", vtype_int, &tls_in.resumption },
785#endif
01603eec 786#ifndef DISABLE_TLS
d9b2312b
JH
787 { "tls_in_sni", vtype_stringptr, &tls_in.sni },
788#endif
5b195d6b 789 { "tls_in_ver", vtype_stringptr, &tls_in.ver },
817d9f57 790 { "tls_out_bits", vtype_int, &tls_out.bits },
cb9d95ae 791 { "tls_out_certificate_verified", vtype_int,&tls_out.certificate_verified },
817d9f57 792 { "tls_out_cipher", vtype_stringptr, &tls_out.cipher },
f1be21cf 793 { "tls_out_cipher_std", vtype_stringptr, &tls_out.cipher_stdname },
c0635b6d 794#ifdef SUPPORT_DANE
594706ea
JH
795 { "tls_out_dane", vtype_bool, &tls_out.dane_verified },
796#endif
44662487 797 { "tls_out_ocsp", vtype_int, &tls_out.ocsp },
9d1c15ef
JH
798 { "tls_out_ourcert", vtype_cert, &tls_out.ourcert },
799 { "tls_out_peercert", vtype_cert, &tls_out.peercert },
817d9f57 800 { "tls_out_peerdn", vtype_stringptr, &tls_out.peerdn },
b10c87b3
JH
801#ifdef EXPERIMENTAL_TLS_RESUME
802 { "tls_out_resumption", vtype_int, &tls_out.resumption },
803#endif
01603eec 804#ifndef DISABLE_TLS
817d9f57 805 { "tls_out_sni", vtype_stringptr, &tls_out.sni },
7be682ca 806#endif
c0635b6d 807#ifdef SUPPORT_DANE
594706ea
JH
808 { "tls_out_tlsa_usage", vtype_int, &tls_out.tlsa_usage },
809#endif
5b195d6b 810 { "tls_out_ver", vtype_stringptr, &tls_out.ver },
d9b2312b 811
613dd4ae 812 { "tls_peerdn", vtype_stringptr, &tls_in.peerdn }, /* mind the alphabetical order! */
01603eec 813#ifndef DISABLE_TLS
613dd4ae
JH
814 { "tls_sni", vtype_stringptr, &tls_in.sni }, /* mind the alphabetical order! */
815#endif
817d9f57 816
059ec3d9
PH
817 { "tod_bsdinbox", vtype_todbsdin, NULL },
818 { "tod_epoch", vtype_tode, NULL },
f5787926 819 { "tod_epoch_l", vtype_todel, NULL },
059ec3d9
PH
820 { "tod_full", vtype_todf, NULL },
821 { "tod_log", vtype_todl, NULL },
822 { "tod_logfile", vtype_todlf, NULL },
823 { "tod_zone", vtype_todzone, NULL },
824 { "tod_zulu", vtype_todzulu, NULL },
181d9bf8 825 { "transport_name", vtype_stringptr, &transport_name },
059ec3d9 826 { "value", vtype_stringptr, &lookup_value },
aec45841 827 { "verify_mode", vtype_stringptr, &verify_mode },
059ec3d9
PH
828 { "version_number", vtype_stringptr, &version_string },
829 { "warn_message_delay", vtype_stringptr, &warnmsg_delay },
830 { "warn_message_recipient",vtype_stringptr, &warnmsg_recipients },
831 { "warn_message_recipients",vtype_stringptr,&warnmsg_recipients },
832 { "warnmsg_delay", vtype_stringptr, &warnmsg_delay },
833 { "warnmsg_recipient", vtype_stringptr, &warnmsg_recipients },
834 { "warnmsg_recipients", vtype_stringptr, &warnmsg_recipients }
835};
836
0539a19d 837static int var_table_size = nelem(var_table);
059ec3d9
PH
838static uschar var_buffer[256];
839static BOOL malformed_header;
840
841/* For textual hashes */
842
1ba28e2b
PP
843static const char *hashcodes = "abcdefghijklmnopqrtsuvwxyz"
844 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
845 "0123456789";
059ec3d9
PH
846
847enum { HMAC_MD5, HMAC_SHA1 };
848
849/* For numeric hashes */
850
851static unsigned int prime[] = {
852 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
853 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
854 73, 79, 83, 89, 97, 101, 103, 107, 109, 113};
855
856/* For printing modes in symbolic form */
857
858static uschar *mtable_normal[] =
859 { US"---", US"--x", US"-w-", US"-wx", US"r--", US"r-x", US"rw-", US"rwx" };
860
861static uschar *mtable_setid[] =
862 { US"--S", US"--s", US"-wS", US"-ws", US"r-S", US"r-s", US"rwS", US"rws" };
863
864static uschar *mtable_sticky[] =
865 { US"--T", US"--t", US"-wT", US"-wt", US"r-T", US"r-t", US"rwT", US"rwt" };
866
bce15b62
JH
867/* flags for find_header() */
868#define FH_EXISTS_ONLY BIT(0)
869#define FH_WANT_RAW BIT(1)
870#define FH_WANT_LIST BIT(2)
059ec3d9
PH
871
872
873/*************************************************
874* Tables for UTF-8 support *
875*************************************************/
876
877/* Table of the number of extra characters, indexed by the first character
878masked with 0x3f. The highest number for a valid UTF-8 character is in fact
8790x3d. */
880
881static uschar utf8_table1[] = {
882 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
883 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
884 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
885 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
886
887/* These are the masks for the data bits in the first byte of a character,
888indexed by the number of additional bytes. */
889
890static int utf8_table2[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
891
892/* Get the next UTF-8 character, advancing the pointer. */
893
894#define GETUTF8INC(c, ptr) \
895 c = *ptr++; \
896 if ((c & 0xc0) == 0xc0) \
897 { \
898 int a = utf8_table1[c & 0x3f]; /* Number of additional bytes */ \
899 int s = 6*a; \
900 c = (c & utf8_table2[a]) << s; \
901 while (a-- > 0) \
902 { \
903 s -= 6; \
904 c |= (*ptr++ & 0x3f) << s; \
905 } \
906 }
907
908
03ca21f8
JH
909
910static uschar * base32_chars = US"abcdefghijklmnopqrstuvwxyz234567";
911
059ec3d9
PH
912/*************************************************
913* Binary chop search on a table *
914*************************************************/
915
916/* This is used for matching expansion items and operators.
917
918Arguments:
919 name the name that is being sought
920 table the table to search
921 table_size the number of items in the table
922
923Returns: the offset in the table, or -1
924*/
925
926static int
927chop_match(uschar *name, uschar **table, int table_size)
928{
929uschar **bot = table;
930uschar **top = table + table_size;
931
932while (top > bot)
933 {
934 uschar **mid = bot + (top - bot)/2;
935 int c = Ustrcmp(name, *mid);
936 if (c == 0) return mid - table;
937 if (c > 0) bot = mid + 1; else top = mid;
938 }
939
940return -1;
941}
942
943
944
945/*************************************************
946* Check a condition string *
947*************************************************/
948
949/* This function is called to expand a string, and test the result for a "true"
950or "false" value. Failure of the expansion yields FALSE; logged unless it was a
be7a5781
JH
951forced fail or lookup defer.
952
953We used to release all store used, but this is not not safe due
954to ${dlfunc } and ${acl }. In any case expand_string_internal()
955is reasonably careful to release what it can.
059ec3d9 956
6a8de854
PP
957The actual false-value tests should be replicated for ECOND_BOOL_LAX.
958
059ec3d9
PH
959Arguments:
960 condition the condition string
961 m1 text to be incorporated in panic error
962 m2 ditto
963
964Returns: TRUE if condition is met, FALSE if not
965*/
966
967BOOL
968expand_check_condition(uschar *condition, uschar *m1, uschar *m2)
969{
5694b905
JH
970uschar * ss = expand_string(condition);
971if (!ss)
059ec3d9 972 {
8768d548 973 if (!f.expand_string_forcedfail && !f.search_find_defer)
059ec3d9
PH
974 log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand condition \"%s\" "
975 "for %s %s: %s", condition, m1, m2, expand_string_message);
976 return FALSE;
977 }
5694b905 978return *ss && Ustrcmp(ss, "0") != 0 && strcmpic(ss, US"no") != 0 &&
059ec3d9 979 strcmpic(ss, US"false") != 0;
059ec3d9
PH
980}
981
982
983
17c76198 984
059ec3d9 985/*************************************************
9e3331ea
TK
986* Pseudo-random number generation *
987*************************************************/
988
989/* Pseudo-random number generation. The result is not "expected" to be
990cryptographically strong but not so weak that someone will shoot themselves
991in the foot using it as a nonce in some email header scheme or whatever
992weirdness they'll twist this into. The result should ideally handle fork().
993
994However, if we're stuck unable to provide this, then we'll fall back to
995appallingly bad randomness.
996
01603eec 997If DISABLE_TLS is not defined then this will not be used except as an emergency
17c76198 998fallback.
9e3331ea
TK
999
1000Arguments:
1001 max range maximum
1002Returns a random number in range [0, max-1]
1003*/
1004
01603eec 1005#ifndef DISABLE_TLS
17c76198
PP
1006# define vaguely_random_number vaguely_random_number_fallback
1007#endif
9e3331ea 1008int
17c76198 1009vaguely_random_number(int max)
9e3331ea 1010{
01603eec 1011#ifndef DISABLE_TLS
17c76198
PP
1012# undef vaguely_random_number
1013#endif
dca6d121
JH
1014static pid_t pid = 0;
1015pid_t p2;
9e3331ea 1016
dca6d121
JH
1017if ((p2 = getpid()) != pid)
1018 {
1019 if (pid != 0)
9e3331ea 1020 {
9e3331ea
TK
1021
1022#ifdef HAVE_ARC4RANDOM
dca6d121
JH
1023 /* cryptographically strong randomness, common on *BSD platforms, not
1024 so much elsewhere. Alas. */
1025# ifndef NOT_HAVE_ARC4RANDOM_STIR
1026 arc4random_stir();
1027# endif
9e3331ea 1028#elif defined(HAVE_SRANDOM) || defined(HAVE_SRANDOMDEV)
dca6d121
JH
1029# ifdef HAVE_SRANDOMDEV
1030 /* uses random(4) for seeding */
1031 srandomdev();
1032# else
1033 {
1034 struct timeval tv;
1035 gettimeofday(&tv, NULL);
1036 srandom(tv.tv_sec | tv.tv_usec | getpid());
1037 }
1038# endif
9e3331ea 1039#else
dca6d121 1040 /* Poor randomness and no seeding here */
9e3331ea
TK
1041#endif
1042
9e3331ea 1043 }
dca6d121
JH
1044 pid = p2;
1045 }
9e3331ea
TK
1046
1047#ifdef HAVE_ARC4RANDOM
dca6d121 1048return arc4random() % max;
9e3331ea 1049#elif defined(HAVE_SRANDOM) || defined(HAVE_SRANDOMDEV)
dca6d121 1050return random() % max;
9e3331ea 1051#else
dca6d121
JH
1052/* This one returns a 16-bit number, definitely not crypto-strong */
1053return random_number(max);
9e3331ea
TK
1054#endif
1055}
1056
17c76198
PP
1057
1058
9e3331ea
TK
1059
1060/*************************************************
059ec3d9
PH
1061* Pick out a name from a string *
1062*************************************************/
1063
1064/* If the name is too long, it is silently truncated.
1065
1066Arguments:
1067 name points to a buffer into which to put the name
1068 max is the length of the buffer
1069 s points to the first alphabetic character of the name
1070 extras chars other than alphanumerics to permit
1071
1072Returns: pointer to the first character after the name
1073
1074Note: The test for *s != 0 in the while loop is necessary because
1075Ustrchr() yields non-NULL if the character is zero (which is not something
1076I expected). */
1077
55414b25
JH
1078static const uschar *
1079read_name(uschar *name, int max, const uschar *s, uschar *extras)
059ec3d9
PH
1080{
1081int ptr = 0;
5694b905 1082while (*s && (isalnum(*s) || Ustrchr(extras, *s) != NULL))
059ec3d9
PH
1083 {
1084 if (ptr < max-1) name[ptr++] = *s;
1085 s++;
1086 }
1087name[ptr] = 0;
1088return s;
1089}
1090
1091
1092
1093/*************************************************
1094* Pick out the rest of a header name *
1095*************************************************/
1096
1097/* A variable name starting $header_ (or just $h_ for those who like
1098abbreviations) might not be the complete header name because headers can
1099contain any printing characters in their names, except ':'. This function is
1100called to read the rest of the name, chop h[eader]_ off the front, and put ':'
1101on the end, if the name was terminated by white space.
1102
1103Arguments:
1104 name points to a buffer in which the name read so far exists
1105 max is the length of the buffer
1106 s points to the first character after the name so far, i.e. the
1107 first non-alphameric character after $header_xxxxx
1108
1109Returns: a pointer to the first character after the header name
1110*/
1111
55414b25
JH
1112static const uschar *
1113read_header_name(uschar *name, int max, const uschar *s)
059ec3d9
PH
1114{
1115int prelen = Ustrchr(name, '_') - name + 1;
1116int ptr = Ustrlen(name) - prelen;
1117if (ptr > 0) memmove(name, name+prelen, ptr);
1118while (mac_isgraph(*s) && *s != ':')
1119 {
1120 if (ptr < max-1) name[ptr++] = *s;
1121 s++;
1122 }
1123if (*s == ':') s++;
1124name[ptr++] = ':';
1125name[ptr] = 0;
1126return s;
1127}
1128
1129
1130
1131/*************************************************
1132* Pick out a number from a string *
1133*************************************************/
1134
1135/* Arguments:
1136 n points to an integer into which to put the number
1137 s points to the first digit of the number
1138
1139Returns: a pointer to the character after the last digit
1140*/
13559da6
JH
1141/*XXX consider expanding to int_eximarith_t. But the test for
1142"overbig numbers" in 0002 still needs to overflow it. */
059ec3d9
PH
1143
1144static uschar *
1145read_number(int *n, uschar *s)
1146{
1147*n = 0;
1148while (isdigit(*s)) *n = *n * 10 + (*s++ - '0');
1149return s;
1150}
1151
55414b25
JH
1152static const uschar *
1153read_cnumber(int *n, const uschar *s)
1154{
1155*n = 0;
1156while (isdigit(*s)) *n = *n * 10 + (*s++ - '0');
1157return s;
1158}
1159
059ec3d9
PH
1160
1161
1162/*************************************************
1163* Extract keyed subfield from a string *
1164*************************************************/
1165
1166/* The yield is in dynamic store; NULL means that the key was not found.
1167
1168Arguments:
1169 key points to the name of the key
1170 s points to the string from which to extract the subfield
1171
1172Returns: NULL if the subfield was not found, or
1173 a pointer to the subfield's data
1174*/
1175
be24b950
JH
1176uschar *
1177expand_getkeyed(const uschar * key, const uschar * s)
059ec3d9
PH
1178{
1179int length = Ustrlen(key);
137ae145 1180Uskip_whitespace(&s);
059ec3d9
PH
1181
1182/* Loop to search for the key */
1183
8fdf20fd 1184while (*s)
059ec3d9
PH
1185 {
1186 int dkeylength;
8fdf20fd
JH
1187 uschar * data;
1188 const uschar * dkey = s;
059ec3d9 1189
8fdf20fd 1190 while (*s && *s != '=' && !isspace(*s)) s++;
059ec3d9 1191 dkeylength = s - dkey;
9ad27f49 1192 if (Uskip_whitespace(&s) == '=') while (isspace(*++s));
059ec3d9
PH
1193
1194 data = string_dequote(&s);
1195 if (length == dkeylength && strncmpic(key, dkey, length) == 0)
1196 return data;
1197
137ae145 1198 Uskip_whitespace(&s);
059ec3d9
PH
1199 }
1200
1201return NULL;
1202}
1203
1204
1205
9d1c15ef
JH
1206static var_entry *
1207find_var_ent(uschar * name)
1208{
1209int first = 0;
1210int last = var_table_size;
1211
1212while (last > first)
1213 {
1214 int middle = (first + last)/2;
1215 int c = Ustrcmp(name, var_table[middle].name);
1216
1217 if (c > 0) { first = middle + 1; continue; }
1218 if (c < 0) { last = middle; continue; }
1219 return &var_table[middle];
1220 }
1221return NULL;
1222}
059ec3d9
PH
1223
1224/*************************************************
1225* Extract numbered subfield from string *
1226*************************************************/
1227
1228/* Extracts a numbered field from a string that is divided by tokens - for
1229example a line from /etc/passwd is divided by colon characters. First field is
1230numbered one. Negative arguments count from the right. Zero returns the whole
1231string. Returns NULL if there are insufficient tokens in the string
1232
1233***WARNING***
1234Modifies final argument - this is a dynamically generated string, so that's OK.
1235
1236Arguments:
1237 field number of field to be extracted,
1238 first field = 1, whole string = 0, last field = -1
1239 separators characters that are used to break string into tokens
1240 s points to the string from which to extract the subfield
1241
1242Returns: NULL if the field was not found,
1243 a pointer to the field's data inside s (modified to add 0)
1244*/
1245
1246static uschar *
1247expand_gettokened (int field, uschar *separators, uschar *s)
1248{
1249int sep = 1;
1250int count;
1251uschar *ss = s;
1252uschar *fieldtext = NULL;
1253
1254if (field == 0) return s;
1255
1256/* Break the line up into fields in place; for field > 0 we stop when we have
1257done the number of fields we want. For field < 0 we continue till the end of
1258the string, counting the number of fields. */
1259
1260count = (field > 0)? field : INT_MAX;
1261
1262while (count-- > 0)
1263 {
1264 size_t len;
1265
1266 /* Previous field was the last one in the string. For a positive field
1267 number, this means there are not enough fields. For a negative field number,
1268 check that there are enough, and scan back to find the one that is wanted. */
1269
1270 if (sep == 0)
1271 {
1272 if (field > 0 || (-field) > (INT_MAX - count - 1)) return NULL;
1273 if ((-field) == (INT_MAX - count - 1)) return s;
1274 while (field++ < 0)
1275 {
1276 ss--;
1277 while (ss[-1] != 0) ss--;
1278 }
1279 fieldtext = ss;
1280 break;
1281 }
1282
1283 /* Previous field was not last in the string; save its start and put a
1284 zero at its end. */
1285
1286 fieldtext = ss;
1287 len = Ustrcspn(ss, separators);
1288 sep = ss[len];
1289 ss[len] = 0;
1290 ss += len + 1;
1291 }
1292
1293return fieldtext;
1294}
1295
1296
aa26e137 1297static uschar *
55414b25 1298expand_getlistele(int field, const uschar * list)
aa26e137 1299{
8fdf20fd
JH
1300const uschar * tlist = list;
1301int sep = 0;
aa26e137
JH
1302uschar dummy;
1303
8fdf20fd 1304if (field < 0)
0f0c8159 1305 {
8fdf20fd
JH
1306 for (field++; string_nextinlist(&tlist, &sep, &dummy, 1); ) field++;
1307 sep = 0;
0f0c8159 1308 }
8fdf20fd
JH
1309if (field == 0) return NULL;
1310while (--field > 0 && (string_nextinlist(&list, &sep, &dummy, 1))) ;
aa26e137
JH
1311return string_nextinlist(&list, &sep, NULL, 0);
1312}
059ec3d9 1313
9d1c15ef
JH
1314
1315/* Certificate fields, by name. Worry about by-OID later */
9e4dddbd 1316/* Names are chosen to not have common prefixes */
9d1c15ef 1317
01603eec 1318#ifndef DISABLE_TLS
9d1c15ef
JH
1319typedef struct
1320{
1321uschar * name;
9e4dddbd
JH
1322int namelen;
1323uschar * (*getfn)(void * cert, uschar * mod);
9d1c15ef
JH
1324} certfield;
1325static certfield certfields[] =
1326{ /* linear search; no special order */
9e4dddbd
JH
1327 { US"version", 7, &tls_cert_version },
1328 { US"serial_number", 13, &tls_cert_serial_number },
1329 { US"subject", 7, &tls_cert_subject },
1330 { US"notbefore", 9, &tls_cert_not_before },
1331 { US"notafter", 8, &tls_cert_not_after },
1332 { US"issuer", 6, &tls_cert_issuer },
1333 { US"signature", 9, &tls_cert_signature },
1334 { US"sig_algorithm", 13, &tls_cert_signature_algorithm },
1335 { US"subj_altname", 12, &tls_cert_subject_altname },
1336 { US"ocsp_uri", 8, &tls_cert_ocsp_uri },
1337 { US"crl_uri", 7, &tls_cert_crl_uri },
9d1c15ef
JH
1338};
1339
1340static uschar *
1341expand_getcertele(uschar * field, uschar * certvar)
1342{
1343var_entry * vp;
9d1c15ef
JH
1344
1345if (!(vp = find_var_ent(certvar)))
1346 {
94431adb 1347 expand_string_message =
9d1c15ef
JH
1348 string_sprintf("no variable named \"%s\"", certvar);
1349 return NULL; /* Unknown variable name */
1350 }
1351/* NB this stops us passing certs around in variable. Might
1352want to do that in future */
1353if (vp->type != vtype_cert)
1354 {
94431adb 1355 expand_string_message =
9d1c15ef
JH
1356 string_sprintf("\"%s\" is not a certificate", certvar);
1357 return NULL; /* Unknown variable name */
1358 }
1359if (!*(void **)vp->value)
1360 return NULL;
1361
1362if (*field >= '0' && *field <= '9')
1363 return tls_cert_ext_by_oid(*(void **)vp->value, field, 0);
1364
d7978c0f
JH
1365for (certfield * cp = certfields;
1366 cp < certfields + nelem(certfields);
1367 cp++)
9e4dddbd
JH
1368 if (Ustrncmp(cp->name, field, cp->namelen) == 0)
1369 {
1370 uschar * modifier = *(field += cp->namelen) == ','
1371 ? ++field : NULL;
1372 return (*cp->getfn)( *(void **)vp->value, modifier );
1373 }
9d1c15ef 1374
94431adb 1375expand_string_message =
9d1c15ef
JH
1376 string_sprintf("bad field selector \"%s\" for certextract", field);
1377return NULL;
1378}
01603eec 1379#endif /*DISABLE_TLS*/
9d1c15ef 1380
059ec3d9
PH
1381/*************************************************
1382* Extract a substring from a string *
1383*************************************************/
1384
1385/* Perform the ${substr or ${length expansion operations.
1386
1387Arguments:
1388 subject the input string
1389 value1 the offset from the start of the input string to the start of
1390 the output string; if negative, count from the right.
1391 value2 the length of the output string, or negative (-1) for unset
1392 if value1 is positive, unset means "all after"
1393 if value1 is negative, unset means "all before"
1394 len set to the length of the returned string
1395
1396Returns: pointer to the output string, or NULL if there is an error
1397*/
1398
1399static uschar *
1400extract_substr(uschar *subject, int value1, int value2, int *len)
1401{
1402int sublen = Ustrlen(subject);
1403
1404if (value1 < 0) /* count from right */
1405 {
1406 value1 += sublen;
1407
1408 /* If the position is before the start, skip to the start, and adjust the
1409 length. If the length ends up negative, the substring is null because nothing
1410 can precede. This falls out naturally when the length is unset, meaning "all
1411 to the left". */
1412
1413 if (value1 < 0)
1414 {
1415 value2 += value1;
1416 if (value2 < 0) value2 = 0;
1417 value1 = 0;
1418 }
1419
1420 /* Otherwise an unset length => characters before value1 */
1421
1422 else if (value2 < 0)
1423 {
1424 value2 = value1;
1425 value1 = 0;
1426 }
1427 }
1428
1429/* For a non-negative offset, if the starting position is past the end of the
1430string, the result will be the null string. Otherwise, an unset length means
1431"rest"; just set it to the maximum - it will be cut down below if necessary. */
1432
1433else
1434 {
1435 if (value1 > sublen)
1436 {
1437 value1 = sublen;
1438 value2 = 0;
1439 }
1440 else if (value2 < 0) value2 = sublen;
1441 }
1442
1443/* Cut the length down to the maximum possible for the offset value, and get
1444the required characters. */
1445
1446if (value1 + value2 > sublen) value2 = sublen - value1;
1447*len = value2;
1448return subject + value1;
1449}
1450
1451
1452
1453
1454/*************************************************
1455* Old-style hash of a string *
1456*************************************************/
1457
1458/* Perform the ${hash expansion operation.
1459
1460Arguments:
1461 subject the input string (an expanded substring)
1462 value1 the length of the output string; if greater or equal to the
1463 length of the input string, the input string is returned
1464 value2 the number of hash characters to use, or 26 if negative
1465 len set to the length of the returned string
1466
1467Returns: pointer to the output string, or NULL if there is an error
1468*/
1469
1470static uschar *
1471compute_hash(uschar *subject, int value1, int value2, int *len)
1472{
1473int sublen = Ustrlen(subject);
1474
1475if (value2 < 0) value2 = 26;
1476else if (value2 > Ustrlen(hashcodes))
1477 {
1478 expand_string_message =
1479 string_sprintf("hash count \"%d\" too big", value2);
1480 return NULL;
1481 }
1482
1483/* Calculate the hash text. We know it is shorter than the original string, so
1484can safely place it in subject[] (we know that subject is always itself an
1485expanded substring). */
1486
1487if (value1 < sublen)
1488 {
1489 int c;
1490 int i = 0;
1491 int j = value1;
1492 while ((c = (subject[j])) != 0)
1493 {
1494 int shift = (c + j++) & 7;
1495 subject[i] ^= (c << shift) | (c >> (8-shift));
1496 if (++i >= value1) i = 0;
1497 }
1498 for (i = 0; i < value1; i++)
1499 subject[i] = hashcodes[(subject[i]) % value2];
1500 }
1501else value1 = sublen;
1502
1503*len = value1;
1504return subject;
1505}
1506
1507
1508
1509
1510/*************************************************
1511* Numeric hash of a string *
1512*************************************************/
1513
1514/* Perform the ${nhash expansion operation. The first characters of the
1515string are treated as most important, and get the highest prime numbers.
1516
1517Arguments:
1518 subject the input string
1519 value1 the maximum value of the first part of the result
1520 value2 the maximum value of the second part of the result,
1521 or negative to produce only a one-part result
1522 len set to the length of the returned string
1523
1524Returns: pointer to the output string, or NULL if there is an error.
1525*/
1526
1527static uschar *
1528compute_nhash (uschar *subject, int value1, int value2, int *len)
1529{
1530uschar *s = subject;
1531int i = 0;
1532unsigned long int total = 0; /* no overflow */
1533
1534while (*s != 0)
1535 {
0539a19d 1536 if (i == 0) i = nelem(prime) - 1;
059ec3d9
PH
1537 total += prime[i--] * (unsigned int)(*s++);
1538 }
1539
1540/* If value2 is unset, just compute one number */
1541
1542if (value2 < 0)
bb07bcd3 1543 s = string_sprintf("%lu", total % value1);
059ec3d9
PH
1544
1545/* Otherwise do a div/mod hash */
1546
1547else
1548 {
1549 total = total % (value1 * value2);
bb07bcd3 1550 s = string_sprintf("%lu/%lu", total/value2, total % value2);
059ec3d9
PH
1551 }
1552
1553*len = Ustrlen(s);
1554return s;
1555}
1556
1557
1558
1559
1560
1561/*************************************************
1562* Find the value of a header or headers *
1563*************************************************/
1564
1565/* Multiple instances of the same header get concatenated, and this function
1566can also return a concatenation of all the header lines. When concatenating
1567specific headers that contain lists of addresses, a comma is inserted between
1568them. Otherwise we use a straight concatenation. Because some messages can have
1569pathologically large number of lines, there is a limit on the length that is
5d26aacd 1570returned.
059ec3d9
PH
1571
1572Arguments:
1573 name the name of the header, without the leading $header_ or $h_,
1574 or NULL if a concatenation of all headers is required
059ec3d9
PH
1575 newsize return the size of memory block that was obtained; may be NULL
1576 if exists_only is TRUE
bce15b62
JH
1577 flags FH_EXISTS_ONLY
1578 set if called from a def: test; don't need to build a string;
1579 just return a string that is not "" and not "0" if the header
1580 exists
1581 FH_WANT_RAW
5d26aacd 1582 set if called for $rh_ or $rheader_ items; no processing,
bce15b62
JH
1583 other than concatenating, will be done on the header. Also used
1584 for $message_headers_raw.
1585 FH_WANT_LIST
1586 Double colon chars in the content, and replace newline with
1587 colon between each element when concatenating; returning a
1588 colon-sep list (elements might contain newlines)
059ec3d9
PH
1589 charset name of charset to translate MIME words to; used only if
1590 want_raw is false; if NULL, no translation is done (this is
1591 used for $bh_ and $bheader_)
1592
1593Returns: NULL if the header does not exist, else a pointer to a new
1594 store block
1595*/
1596
1597static uschar *
bce15b62 1598find_header(uschar *name, int *newsize, unsigned flags, uschar *charset)
059ec3d9 1599{
bce15b62
JH
1600BOOL found = !name;
1601int len = name ? Ustrlen(name) : 0;
1602BOOL comma = FALSE;
bce15b62 1603gstring * g = NULL;
059ec3d9 1604
d7978c0f 1605for (header_line * h = header_list; h; h = h->next)
bce15b62
JH
1606 if (h->type != htype_old && h->text) /* NULL => Received: placeholder */
1607 if (!name || (len <= h->slen && strncmpic(name, h->text, len) == 0))
1608 {
1609 uschar * s, * t;
1610 size_t inc;
fd700877 1611
bce15b62
JH
1612 if (flags & FH_EXISTS_ONLY)
1613 return US"1"; /* don't need actual string */
fd700877 1614
bce15b62
JH
1615 found = TRUE;
1616 s = h->text + len; /* text to insert */
1617 if (!(flags & FH_WANT_RAW)) /* unless wanted raw, */
9ad27f49 1618 Uskip_whitespace(&s); /* remove leading white space */
bce15b62 1619 t = h->text + h->slen; /* end-point */
059ec3d9 1620
bce15b62
JH
1621 /* Unless wanted raw, remove trailing whitespace, including the
1622 newline. */
059ec3d9 1623
bce15b62
JH
1624 if (flags & FH_WANT_LIST)
1625 while (t > s && t[-1] == '\n') t--;
1626 else if (!(flags & FH_WANT_RAW))
1627 {
1628 while (t > s && isspace(t[-1])) t--;
059ec3d9 1629
bce15b62
JH
1630 /* Set comma if handling a single header and it's one of those
1631 that contains an address list, except when asked for raw headers. Only
1632 need to do this once. */
059ec3d9 1633
bce15b62
JH
1634 if (name && !comma && Ustrchr("BCFRST", h->type)) comma = TRUE;
1635 }
059ec3d9 1636
bce15b62
JH
1637 /* Trim the header roughly if we're approaching limits */
1638 inc = t - s;
ba5120a4
JH
1639 if (gstring_length(g) + inc > header_insert_maxlen)
1640 inc = header_insert_maxlen - gstring_length(g);
bce15b62
JH
1641
1642 /* For raw just copy the data; for a list, add the data as a colon-sep
1643 list-element; for comma-list add as an unchecked comma,newline sep
1644 list-elemment; for other nonraw add as an unchecked newline-sep list (we
1645 stripped trailing WS above including the newline). We ignore the potential
1646 expansion due to colon-doubling, just leaving the loop if the limit is met
1647 or exceeded. */
1648
1649 if (flags & FH_WANT_LIST)
1650 g = string_append_listele_n(g, ':', s, (unsigned)inc);
1651 else if (flags & FH_WANT_RAW)
bce15b62 1652 g = string_catn(g, s, (unsigned)inc);
bce15b62 1653 else if (inc > 0)
ba5120a4
JH
1654 g = string_append2_listele_n(g, comma ? US",\n" : US"\n",
1655 s, (unsigned)inc);
059ec3d9 1656
ba5120a4 1657 if (gstring_length(g) >= header_insert_maxlen) break;
bce15b62 1658 }
059ec3d9 1659
bce15b62
JH
1660if (!found) return NULL; /* No header found */
1661if (!g) return US"";
059ec3d9 1662
059ec3d9
PH
1663/* That's all we do for raw header expansion. */
1664
bce15b62
JH
1665*newsize = g->size;
1666if (flags & FH_WANT_RAW)
ba5120a4 1667 return string_from_gstring(g);
059ec3d9 1668
bce15b62
JH
1669/* Otherwise do RFC 2047 decoding, translating the charset if requested.
1670The rfc2047_decode2() function can return an error with decoded data if the
1671charset translation fails. If decoding fails, it returns NULL. */
059ec3d9
PH
1672
1673else
1674 {
ba5120a4
JH
1675 uschar * error, * decoded = rfc2047_decode2(string_from_gstring(g),
1676 check_rfc2047_length, charset, '?', NULL, newsize, &error);
bce15b62 1677 if (error)
059ec3d9 1678 DEBUG(D_any) debug_printf("*** error in RFC 2047 decoding: %s\n"
bce15b62 1679 " input was: %s\n", error, g->s);
ba5120a4 1680 return decoded ? decoded : string_from_gstring(g);
059ec3d9 1681 }
059ec3d9
PH
1682}
1683
1684
1685
1686
c8599aad 1687/* Append a "local" element to an Authentication-Results: header
40394cc1
JH
1688if this was a non-smtp message.
1689*/
1690
1691static gstring *
1692authres_local(gstring * g, const uschar * sysname)
1693{
8768d548 1694if (!f.authentication_local)
40394cc1
JH
1695 return g;
1696g = string_append(g, 3, US";\n\tlocal=pass (non-smtp, ", sysname, US")");
1697if (authenticated_id) g = string_append(g, 2, " u=", authenticated_id);
1698return g;
1699}
1700
1701
c8599aad 1702/* Append an "iprev" element to an Authentication-Results: header
dfbcb5ac
JH
1703if we have attempted to get the calling host's name.
1704*/
1705
1706static gstring *
1707authres_iprev(gstring * g)
1708{
1709if (sender_host_name)
61e3f250
JH
1710 g = string_append(g, 3, US";\n\tiprev=pass (", sender_host_name, US")");
1711else if (host_lookup_deferred)
1712 g = string_catn(g, US";\n\tiprev=temperror", 19);
1713else if (host_lookup_failed)
1714 g = string_catn(g, US";\n\tiprev=fail", 13);
0a682b6c 1715else
61e3f250
JH
1716 return g;
1717
1718if (sender_host_address)
99efa4cf 1719 g = string_append(g, 2, US" smtp.remote-ip=", sender_host_address);
dfbcb5ac
JH
1720return g;
1721}
1722
1723
1724
059ec3d9 1725/*************************************************
362145b5
JH
1726* Return list of recipients *
1727*************************************************/
1728/* A recipients list is available only during system message filtering,
1729during ACL processing after DATA, and while expanding pipe commands
1730generated from a system filter, but not elsewhere. */
1731
1732static uschar *
1733fn_recipients(void)
1734{
bce15b62 1735uschar * s;
acec9514 1736gstring * g = NULL;
acec9514 1737
8768d548 1738if (!f.enable_dollar_recipients) return NULL;
acec9514 1739
d7978c0f 1740for (int i = 0; i < recipients_count; i++)
362145b5 1741 {
bce15b62
JH
1742 s = recipients_list[i].address;
1743 g = string_append2_listele_n(g, US", ", s, Ustrlen(s));
362145b5 1744 }
bce15b62 1745return g ? g->s : NULL;
362145b5
JH
1746}
1747
1748
1749/*************************************************
04403ab0
JH
1750* Return size of queue *
1751*************************************************/
1752/* Ask the daemon for the queue size */
1753
1754static uschar *
1755fn_queue_size(void)
1756{
3978c243 1757struct sockaddr_un sa_un = {.sun_family = AF_UNIX};
04403ab0
JH
1758uschar buf[16];
1759int fd;
1760ssize_t len;
1761const uschar * where;
2f2dd3a5
JH
1762#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
1763uschar * sname;
1764#endif
8d2cbee4
JH
1765fd_set fds;
1766struct timeval tv;
04403ab0
JH
1767
1768if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
1769 {
1770 DEBUG(D_expand) debug_printf(" socket: %s\n", strerror(errno));
1771 return NULL;
1772 }
1773
2f2dd3a5 1774#ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
3978c243 1775sa_un.sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */
04403ab0 1776len = offsetof(struct sockaddr_un, sun_path) + 1
3978c243 1777 + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "exim_%d", getpid());
04403ab0 1778#else
2f2dd3a5 1779sname = string_sprintf("%s/p_%d", spool_directory, getpid());
04403ab0 1780len = offsetof(struct sockaddr_un, sun_path)
3978c243 1781 + snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s", sname);
04403ab0
JH
1782#endif
1783
3978c243 1784if (bind(fd, (const struct sockaddr *)&sa_un, len) < 0)
5399df80 1785 { where = US"bind"; goto bad; }
04403ab0
JH
1786
1787#ifdef notdef
2f2dd3a5 1788debug_printf("local addr '%s%s'\n",
3978c243
JH
1789 *sa_un.sun_path ? "" : "@",
1790 sa_un.sun_path + (*sa_un.sun_path ? 0 : 1));
04403ab0
JH
1791#endif
1792
2f2dd3a5 1793#ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
3978c243 1794sa_un.sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */
04403ab0 1795len = offsetof(struct sockaddr_un, sun_path) + 1
691ca88c
JH
1796 + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "%s",
1797 expand_string(notifier_socket));
2f2dd3a5
JH
1798#else
1799len = offsetof(struct sockaddr_un, sun_path)
691ca88c
JH
1800 + snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s",
1801 expand_string(notifier_socket));
2f2dd3a5 1802#endif
04403ab0 1803
3978c243 1804if (connect(fd, (const struct sockaddr *)&sa_un, len) < 0)
8d2cbee4 1805 { where = US"connect"; goto bad2; }
04403ab0
JH
1806
1807buf[0] = NOTIFY_QUEUE_SIZE_REQ;
1808if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; }
1809
8d2cbee4
JH
1810FD_ZERO(&fds); FD_SET(fd, &fds);
1811tv.tv_sec = 2; tv.tv_usec = 0;
1812if (select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv) != 1)
1813 {
1814 DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n");
1815 len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached());
1816 }
1817else if ((len = recv(fd, buf, sizeof(buf), 0)) < 0)
1818 { where = US"recv"; goto bad2; }
04403ab0
JH
1819
1820close(fd);
2f2dd3a5
JH
1821#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
1822Uunlink(sname);
1823#endif
04403ab0
JH
1824return string_copyn(buf, len);
1825
8d2cbee4
JH
1826bad2:
1827#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
1828 Uunlink(sname);
1829#endif
04403ab0
JH
1830bad:
1831 close(fd);
1832 DEBUG(D_expand) debug_printf(" %s: %s\n", where, strerror(errno));
1833 return NULL;
1834}
1835
1836
1837/*************************************************
059ec3d9
PH
1838* Find value of a variable *
1839*************************************************/
1840
1841/* The table of variables is kept in alphabetic order, so we can search it
1842using a binary chop. The "choplen" variable is nothing to do with the binary
1843chop.
1844
1845Arguments:
1846 name the name of the variable being sought
1847 exists_only TRUE if this is a def: test; passed on to find_header()
1848 skipping TRUE => skip any processing evaluation; this is not the same as
1849 exists_only because def: may test for values that are first
1850 evaluated here
1851 newsize pointer to an int which is initially zero; if the answer is in
1852 a new memory buffer, *newsize is set to its size
1853
1854Returns: NULL if the variable does not exist, or
1855 a pointer to the variable's contents, or
1856 something non-NULL if exists_only is TRUE
1857*/
1858
1859static uschar *
1860find_variable(uschar *name, BOOL exists_only, BOOL skipping, int *newsize)
1861{
9d1c15ef
JH
1862var_entry * vp;
1863uschar *s, *domain;
1864uschar **ss;
1865void * val;
059ec3d9 1866
38a0a95f
PH
1867/* Handle ACL variables, whose names are of the form acl_cxxx or acl_mxxx.
1868Originally, xxx had to be a number in the range 0-9 (later 0-19), but from
1869release 4.64 onwards arbitrary names are permitted, as long as the first 5
641cb756
PH
1870characters are acl_c or acl_m and the sixth is either a digit or an underscore
1871(this gave backwards compatibility at the changeover). There may be built-in
1872variables whose names start acl_ but they should never start in this way. This
1873slightly messy specification is a consequence of the history, needless to say.
47ca6d6c 1874
38a0a95f
PH
1875If an ACL variable does not exist, treat it as empty, unless strict_acl_vars is
1876set, in which case give an error. */
47ca6d6c 1877
641cb756
PH
1878if ((Ustrncmp(name, "acl_c", 5) == 0 || Ustrncmp(name, "acl_m", 5) == 0) &&
1879 !isalpha(name[5]))
38a0a95f 1880 {
fa7b17bd
JH
1881 tree_node * node =
1882 tree_search(name[4] == 'c' ? acl_var_c : acl_var_m, name + 4);
1883 return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
1884 }
1885else if (Ustrncmp(name, "r_", 2) == 0)
1886 {
1887 tree_node * node = tree_search(router_var, name + 2);
63df3f26 1888 return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
47ca6d6c
PH
1889 }
1890
38a0a95f 1891/* Handle $auth<n> variables. */
f78eb7c6
PH
1892
1893if (Ustrncmp(name, "auth", 4) == 0)
1894 {
1895 uschar *endptr;
1896 int n = Ustrtoul(name + 4, &endptr, 10);
1897 if (*endptr == 0 && n != 0 && n <= AUTH_VARS)
f38917cc
JH
1898 return !auth_vars[n-1] ? US"" : auth_vars[n-1];
1899 }
1900else if (Ustrncmp(name, "regex", 5) == 0)
1901 {
1902 uschar *endptr;
1903 int n = Ustrtoul(name + 5, &endptr, 10);
1904 if (*endptr == 0 && n != 0 && n <= REGEX_VARS)
1905 return !regex_vars[n-1] ? US"" : regex_vars[n-1];
f78eb7c6
PH
1906 }
1907
47ca6d6c
PH
1908/* For all other variables, search the table */
1909
9d1c15ef
JH
1910if (!(vp = find_var_ent(name)))
1911 return NULL; /* Unknown variable name */
059ec3d9 1912
9d1c15ef
JH
1913/* Found an existing variable. If in skipping state, the value isn't needed,
1914and we want to avoid processing (such as looking up the host name). */
059ec3d9 1915
9d1c15ef
JH
1916if (skipping)
1917 return US"";
059ec3d9 1918
9d1c15ef
JH
1919val = vp->value;
1920switch (vp->type)
1921 {
1922 case vtype_filter_int:
8768d548 1923 if (!f.filter_running) return NULL;
63df3f26
JH
1924 /* Fall through */
1925 /* VVVVVVVVVVVV */
9d1c15ef 1926 case vtype_int:
63df3f26
JH
1927 sprintf(CS var_buffer, "%d", *(int *)(val)); /* Integer */
1928 return var_buffer;
9d1c15ef
JH
1929
1930 case vtype_ino:
63df3f26
JH
1931 sprintf(CS var_buffer, "%ld", (long int)(*(ino_t *)(val))); /* Inode */
1932 return var_buffer;
9d1c15ef
JH
1933
1934 case vtype_gid:
63df3f26
JH
1935 sprintf(CS var_buffer, "%ld", (long int)(*(gid_t *)(val))); /* gid */
1936 return var_buffer;
9d1c15ef
JH
1937
1938 case vtype_uid:
63df3f26
JH
1939 sprintf(CS var_buffer, "%ld", (long int)(*(uid_t *)(val))); /* uid */
1940 return var_buffer;
9d1c15ef
JH
1941
1942 case vtype_bool:
63df3f26
JH
1943 sprintf(CS var_buffer, "%s", *(BOOL *)(val) ? "yes" : "no"); /* bool */
1944 return var_buffer;
9d1c15ef
JH
1945
1946 case vtype_stringptr: /* Pointer to string */
63df3f26 1947 return (s = *((uschar **)(val))) ? s : US"";
9d1c15ef
JH
1948
1949 case vtype_pid:
63df3f26
JH
1950 sprintf(CS var_buffer, "%d", (int)getpid()); /* pid */
1951 return var_buffer;
9d1c15ef
JH
1952
1953 case vtype_load_avg:
63df3f26
JH
1954 sprintf(CS var_buffer, "%d", OS_GETLOADAVG()); /* load_average */
1955 return var_buffer;
9d1c15ef
JH
1956
1957 case vtype_host_lookup: /* Lookup if not done so */
2d0dc929
JH
1958 if ( !sender_host_name && sender_host_address
1959 && !host_lookup_failed && host_name_lookup() == OK)
63df3f26 1960 host_build_sender_fullhost();
2d0dc929 1961 return sender_host_name ? sender_host_name : US"";
9d1c15ef
JH
1962
1963 case vtype_localpart: /* Get local part from address */
f3ebb786
JH
1964 if (!(s = *((uschar **)(val)))) return US"";
1965 if (!(domain = Ustrrchr(s, '@'))) return s;
63df3f26
JH
1966 if (domain - s > sizeof(var_buffer) - 1)
1967 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "local part longer than " SIZE_T_FMT
1968 " in string expansion", sizeof(var_buffer));
f3ebb786 1969 return string_copyn(s, domain - s);
9d1c15ef
JH
1970
1971 case vtype_domain: /* Get domain from address */
f3ebb786 1972 if (!(s = *((uschar **)(val)))) return US"";
63df3f26 1973 domain = Ustrrchr(s, '@');
f3ebb786 1974 return domain ? domain + 1 : US"";
9d1c15ef
JH
1975
1976 case vtype_msgheaders:
bce15b62 1977 return find_header(NULL, newsize, exists_only ? FH_EXISTS_ONLY : 0, NULL);
9d1c15ef
JH
1978
1979 case vtype_msgheaders_raw:
bce15b62
JH
1980 return find_header(NULL, newsize,
1981 exists_only ? FH_EXISTS_ONLY|FH_WANT_RAW : FH_WANT_RAW, NULL);
9d1c15ef
JH
1982
1983 case vtype_msgbody: /* Pointer to msgbody string */
1984 case vtype_msgbody_end: /* Ditto, the end of the msg */
63df3f26 1985 ss = (uschar **)(val);
d315eda1 1986 if (!*ss && deliver_datafile >= 0) /* Read body when needed */
059ec3d9 1987 {
63df3f26
JH
1988 uschar *body;
1989 off_t start_offset = SPOOL_DATA_START_OFFSET;
1990 int len = message_body_visible;
1991 if (len > message_size) len = message_size;
1992 *ss = body = store_malloc(len+1);
1993 body[0] = 0;
1994 if (vp->type == vtype_msgbody_end)
9d1c15ef 1995 {
63df3f26
JH
1996 struct stat statbuf;
1997 if (fstat(deliver_datafile, &statbuf) == 0)
1998 {
1999 start_offset = statbuf.st_size - len;
2000 if (start_offset < SPOOL_DATA_START_OFFSET)
2001 start_offset = SPOOL_DATA_START_OFFSET;
2002 }
9d1c15ef 2003 }
d4ff61d1
JH
2004 if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0)
2005 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "deliver_datafile lseek: %s",
2006 strerror(errno));
63df3f26
JH
2007 len = read(deliver_datafile, body, len);
2008 if (len > 0)
9d1c15ef 2009 {
63df3f26
JH
2010 body[len] = 0;
2011 if (message_body_newlines) /* Separate loops for efficiency */
2012 while (len > 0)
2013 { if (body[--len] == 0) body[len] = ' '; }
2014 else
2015 while (len > 0)
2016 { if (body[--len] == '\n' || body[len] == 0) body[len] = ' '; }
9d1c15ef 2017 }
059ec3d9 2018 }
d315eda1 2019 return *ss ? *ss : US"";
059ec3d9 2020
9d1c15ef 2021 case vtype_todbsdin: /* BSD inbox time of day */
63df3f26 2022 return tod_stamp(tod_bsdin);
059ec3d9 2023
9d1c15ef 2024 case vtype_tode: /* Unix epoch time of day */
63df3f26 2025 return tod_stamp(tod_epoch);
059ec3d9 2026
9d1c15ef 2027 case vtype_todel: /* Unix epoch/usec time of day */
63df3f26 2028 return tod_stamp(tod_epoch_l);
f5787926 2029
9d1c15ef 2030 case vtype_todf: /* Full time of day */
63df3f26 2031 return tod_stamp(tod_full);
059ec3d9 2032
9d1c15ef 2033 case vtype_todl: /* Log format time of day */
63df3f26 2034 return tod_stamp(tod_log_bare); /* (without timezone) */
059ec3d9 2035
9d1c15ef 2036 case vtype_todzone: /* Time zone offset only */
63df3f26 2037 return tod_stamp(tod_zone);
059ec3d9 2038
9d1c15ef 2039 case vtype_todzulu: /* Zulu time */
63df3f26 2040 return tod_stamp(tod_zulu);
059ec3d9 2041
9d1c15ef 2042 case vtype_todlf: /* Log file datestamp tod */
63df3f26 2043 return tod_stamp(tod_log_datestamp_daily);
059ec3d9 2044
9d1c15ef 2045 case vtype_reply: /* Get reply address */
bce15b62
JH
2046 s = find_header(US"reply-to:", newsize,
2047 exists_only ? FH_EXISTS_ONLY|FH_WANT_RAW : FH_WANT_RAW,
2048 headers_charset);
137ae145 2049 if (s) Uskip_whitespace(&s);
9cffa436 2050 if (!s || !*s)
63df3f26
JH
2051 {
2052 *newsize = 0; /* For the *s==0 case */
bce15b62
JH
2053 s = find_header(US"from:", newsize,
2054 exists_only ? FH_EXISTS_ONLY|FH_WANT_RAW : FH_WANT_RAW,
2055 headers_charset);
63df3f26 2056 }
9cffa436 2057 if (s)
63df3f26
JH
2058 {
2059 uschar *t;
137ae145
JH
2060 Uskip_whitespace(&s);
2061 for (t = s; *t; t++) if (*t == '\n') *t = ' ';
63df3f26
JH
2062 while (t > s && isspace(t[-1])) t--;
2063 *t = 0;
2064 }
9cffa436 2065 return s ? s : US"";
059ec3d9 2066
9d1c15ef
JH
2067 case vtype_string_func:
2068 {
6d95688d 2069 stringptr_fn_t * fn = (stringptr_fn_t *) val;
9d1c15ef
JH
2070 return fn();
2071 }
8e669ac1 2072
9d1c15ef
JH
2073 case vtype_pspace:
2074 {
2075 int inodes;
8c513105 2076 sprintf(CS var_buffer, PR_EXIM_ARITH,
9d1c15ef
JH
2077 receive_statvfs(val == (void *)TRUE, &inodes));
2078 }
2079 return var_buffer;
8e669ac1 2080
9d1c15ef
JH
2081 case vtype_pinodes:
2082 {
2083 int inodes;
2084 (void) receive_statvfs(val == (void *)TRUE, &inodes);
2085 sprintf(CS var_buffer, "%d", inodes);
2086 }
2087 return var_buffer;
80a47a2c 2088
9d1c15ef 2089 case vtype_cert:
63df3f26 2090 return *(void **)val ? US"<cert>" : US"";
80a47a2c 2091
63df3f26 2092#ifndef DISABLE_DKIM
9d1c15ef 2093 case vtype_dkim:
63df3f26
JH
2094 return dkim_exim_expand_query((int)(long)val);
2095#endif
059ec3d9 2096
9d1c15ef 2097 }
6c08476d
LM
2098
2099return NULL; /* Unknown variable. Silences static checkers. */
059ec3d9
PH
2100}
2101
2102
2103
2104
d9b2312b
JH
2105void
2106modify_variable(uschar *name, void * value)
2107{
9d1c15ef
JH
2108var_entry * vp;
2109if ((vp = find_var_ent(name))) vp->value = value;
d9b2312b
JH
2110return; /* Unknown variable name, fail silently */
2111}
2112
2113
2114
2115
2116
cf0812d5 2117
059ec3d9
PH
2118/*************************************************
2119* Read and expand substrings *
2120*************************************************/
2121
2122/* This function is called to read and expand argument substrings for various
2123expansion items. Some have a minimum requirement that is less than the maximum;
2124in these cases, the first non-present one is set to NULL.
2125
2126Arguments:
2127 sub points to vector of pointers to set
2128 n maximum number of substrings
2129 m minimum required
2130 sptr points to current string pointer
2131 skipping the skipping flag
2132 check_end if TRUE, check for final '}'
2133 name name of item, for error message
b0e85a8f
JH
2134 resetok if not NULL, pointer to flag - write FALSE if unsafe to reset
2135 the store.
059ec3d9
PH
2136
2137Returns: 0 OK; string pointer updated
2138 1 curly bracketing error (too few arguments)
2139 2 too many arguments (only if check_end is set); message set
2140 3 other error (expansion failure)
2141*/
2142
2143static int
55414b25 2144read_subs(uschar **sub, int n, int m, const uschar **sptr, BOOL skipping,
b0e85a8f 2145 BOOL check_end, uschar *name, BOOL *resetok)
059ec3d9 2146{
55414b25 2147const uschar *s = *sptr;
059ec3d9 2148
137ae145 2149Uskip_whitespace(&s);
d7978c0f 2150for (int i = 0; i < n; i++)
059ec3d9
PH
2151 {
2152 if (*s != '{')
2153 {
e47376be
JH
2154 if (i < m)
2155 {
2156 expand_string_message = string_sprintf("Not enough arguments for '%s' "
2157 "(min is %d)", name, m);
2158 return 1;
2159 }
059ec3d9
PH
2160 sub[i] = NULL;
2161 break;
2162 }
e47376be
JH
2163 if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, resetok)))
2164 return 3;
059ec3d9 2165 if (*s++ != '}') return 1;
137ae145 2166 Uskip_whitespace(&s);
059ec3d9
PH
2167 }
2168if (check_end && *s++ != '}')
2169 {
2170 if (s[-1] == '{')
2171 {
e47376be 2172 expand_string_message = string_sprintf("Too many arguments for '%s' "
059ec3d9
PH
2173 "(max is %d)", name, n);
2174 return 2;
2175 }
e47376be 2176 expand_string_message = string_sprintf("missing '}' after '%s'", name);
059ec3d9
PH
2177 return 1;
2178 }
2179
2180*sptr = s;
2181return 0;
2182}
2183
2184
2185
2186
2187/*************************************************
641cb756
PH
2188* Elaborate message for bad variable *
2189*************************************************/
2190
2191/* For the "unknown variable" message, take a look at the variable's name, and
2192give additional information about possible ACL variables. The extra information
2193is added on to expand_string_message.
2194
2195Argument: the name of the variable
2196Returns: nothing
2197*/
2198
2199static void
2200check_variable_error_message(uschar *name)
2201{
2202if (Ustrncmp(name, "acl_", 4) == 0)
2203 expand_string_message = string_sprintf("%s (%s)", expand_string_message,
2204 (name[4] == 'c' || name[4] == 'm')?
2205 (isalpha(name[5])?
2206 US"6th character of a user-defined ACL variable must be a digit or underscore" :
2207 US"strict_acl_vars is set" /* Syntax is OK, it has to be this */
2208 ) :
2209 US"user-defined ACL variables must start acl_c or acl_m");
2210}
2211
2212
2213
f60d98e8
JH
2214/*
2215Load args from sub array to globals, and call acl_check().
ef21c07d 2216Sub array will be corrupted on return.
f60d98e8
JH
2217
2218Returns: OK access is granted by an ACCEPT verb
6e3b198d 2219 DISCARD access is (apparently) granted by a DISCARD verb
f60d98e8
JH
2220 FAIL access is denied
2221 FAIL_DROP access is denied; drop the connection
2222 DEFER can't tell at the moment
2223 ERROR disaster
2224*/
2225static int
2226eval_acl(uschar ** sub, int nsub, uschar ** user_msgp)
2227{
2228int i;
ef21c07d
JH
2229int sav_narg = acl_narg;
2230int ret;
93a6fce2 2231uschar * dummy_logmsg;
faa05a93 2232extern int acl_where;
f60d98e8 2233
0539a19d 2234if(--nsub > nelem(acl_arg)) nsub = nelem(acl_arg);
ef21c07d
JH
2235for (i = 0; i < nsub && sub[i+1]; i++)
2236 {
93a6fce2 2237 uschar * tmp = acl_arg[i];
ef21c07d
JH
2238 acl_arg[i] = sub[i+1]; /* place callers args in the globals */
2239 sub[i+1] = tmp; /* stash the old args using our caller's storage */
2240 }
2241acl_narg = i;
bef3ea7f 2242while (i < nsub)
ef21c07d
JH
2243 {
2244 sub[i+1] = acl_arg[i];
2245 acl_arg[i++] = NULL;
2246 }
f60d98e8
JH
2247
2248DEBUG(D_expand)
e1d04f48 2249 debug_printf_indent("expanding: acl: %s arg: %s%s\n",
f60d98e8 2250 sub[0],
60f8e1e8
JH
2251 acl_narg>0 ? acl_arg[0] : US"<none>",
2252 acl_narg>1 ? " +more" : "");
f60d98e8 2253
93a6fce2 2254ret = acl_eval(acl_where, sub[0], user_msgp, &dummy_logmsg);
ef21c07d
JH
2255
2256for (i = 0; i < nsub; i++)
2257 acl_arg[i] = sub[i+1]; /* restore old args */
2258acl_narg = sav_narg;
2259
2260return ret;
f60d98e8
JH
2261}
2262
2263
2264
2265
7f69e814
JH
2266/* Return pointer to dewrapped string, with enclosing specified chars removed.
2267The given string is modified on return. Leading whitespace is skipped while
2268looking for the opening wrap character, then the rest is scanned for the trailing
2269(non-escaped) wrap character. A backslash in the string will act as an escape.
2270
2271A nul is written over the trailing wrap, and a pointer to the char after the
2272leading wrap is returned.
2273
2274Arguments:
2275 s String for de-wrapping
2276 wrap Two-char string, the first being the opener, second the closer wrapping
2277 character
2278Return:
2279 Pointer to de-wrapped string, or NULL on error (with expand_string_message set).
2280*/
2281
2282static uschar *
2283dewrap(uschar * s, const uschar * wrap)
2284{
2285uschar * p = s;
2286unsigned depth = 0;
2287BOOL quotesmode = wrap[0] == wrap[1];
2288
137ae145 2289if (Uskip_whitespace(&p) == *wrap)
7f69e814
JH
2290 {
2291 s = ++p;
2292 wrap++;
2293 while (*p)
2294 {
2295 if (*p == '\\') p++;
2296 else if (!quotesmode && *p == wrap[-1]) depth++;
2297 else if (*p == *wrap)
2298 if (depth == 0)
2299 {
2300 *p = '\0';
2301 return s;
2302 }
2303 else
2304 depth--;
2305 p++;
2306 }
2307 }
2308expand_string_message = string_sprintf("missing '%c'", *wrap);
2309return NULL;
2310}
2311
2312
2313/* Pull off the leading array or object element, returning
2314a copy in an allocated string. Update the list pointer.
2315
2316The element may itself be an abject or array.
2317Return NULL when the list is empty.
2318*/
2319
2320static uschar *
2321json_nextinlist(const uschar ** list)
2322{
2323unsigned array_depth = 0, object_depth = 0;
2324const uschar * s = *list, * item;
2325
9ad27f49 2326skip_whitespace(&s);
7f69e814
JH
2327
2328for (item = s;
2329 *s && (*s != ',' || array_depth != 0 || object_depth != 0);
2330 s++)
2331 switch (*s)
2332 {
2333 case '[': array_depth++; break;
2334 case ']': array_depth--; break;
2335 case '{': object_depth++; break;
2336 case '}': object_depth--; break;
2337 }
2338*list = *s ? s+1 : s;
2339if (item == s) return NULL;
2340item = string_copyn(item, s - item);
2341DEBUG(D_expand) debug_printf_indent(" json ele: '%s'\n", item);
2342return US item;
2343}
2344
2345
2346
21aa0597
JH
2347/************************************************/
2348/* Return offset in ops table, or -1 if not found.
2349Repoint to just after the operator in the string.
2350
2351Argument:
2352 ss string representation of operator
2353 opname split-out operator name
2354*/
2355
2356static int
2357identify_operator(const uschar ** ss, uschar ** opname)
2358{
2359const uschar * s = *ss;
2360uschar name[256];
2361
2362/* Numeric comparisons are symbolic */
2363
2364if (*s == '=' || *s == '>' || *s == '<')
2365 {
2366 int p = 0;
2367 name[p++] = *s++;
2368 if (*s == '=')
2369 {
2370 name[p++] = '=';
2371 s++;
2372 }
2373 name[p] = 0;
2374 }
2375
2376/* All other conditions are named */
2377
2378else
2379 s = read_name(name, sizeof(name), s, US"_");
2380*ss = s;
2381
2382/* If we haven't read a name, it means some non-alpha character is first. */
2383
2384if (!name[0])
2385 {
2386 expand_string_message = string_sprintf("condition name expected, "
2387 "but found \"%.16s\"", s);
2388 return -1;
2389 }
2390if (opname)
2391 *opname = string_copy(name);
2392
2393return chop_match(name, cond_table, nelem(cond_table));
2394}
2395
2396
641cb756 2397/*************************************************
7ef88aa0
JH
2398* Handle MD5 or SHA-1 computation for HMAC *
2399*************************************************/
2400
2401/* These are some wrapping functions that enable the HMAC code to be a bit
2402cleaner. A good compiler will spot the tail recursion.
2403
2404Arguments:
2405 type HMAC_MD5 or HMAC_SHA1
2406 remaining are as for the cryptographic hash functions
2407
2408Returns: nothing
2409*/
2410
2411static void
2412chash_start(int type, void * base)
2413{
2414if (type == HMAC_MD5)
2415 md5_start((md5 *)base);
2416else
2417 sha1_start((hctx *)base);
2418}
2419
2420static void
2421chash_mid(int type, void * base, const uschar * string)
2422{
2423if (type == HMAC_MD5)
2424 md5_mid((md5 *)base, string);
2425else
2426 sha1_mid((hctx *)base, string);
2427}
2428
2429static void
2430chash_end(int type, void * base, const uschar * string, int length,
2431 uschar * digest)
2432{
2433if (type == HMAC_MD5)
2434 md5_end((md5 *)base, string, length, digest);
2435else
2436 sha1_end((hctx *)base, string, length, digest);
2437}
2438
2439
2440
2441
f07babc0 2442#ifdef EXPERIMENTAL_SRS_NATIVE
7ef88aa0
JH
2443/* Do an hmac_md5. The result is _not_ nul-terminated, and is sized as
2444the smaller of a full hmac_md5 result (16 bytes) or the supplied output buffer.
2445
2446Arguments:
2447 key encoding key, nul-terminated
2448 src data to be hashed, nul-terminated
2449 buf output buffer
2450 len size of output buffer
2451*/
2452
2453static void
2454hmac_md5(const uschar * key, const uschar * src, uschar * buf, unsigned len)
2455{
2456md5 md5_base;
2457const uschar * keyptr;
2458uschar * p;
2459unsigned int keylen;
2460
2461#define MD5_HASHLEN 16
2462#define MD5_HASHBLOCKLEN 64
2463
2464uschar keyhash[MD5_HASHLEN];
2465uschar innerhash[MD5_HASHLEN];
2466uschar finalhash[MD5_HASHLEN];
2467uschar innerkey[MD5_HASHBLOCKLEN];
2468uschar outerkey[MD5_HASHBLOCKLEN];
2469
2470keyptr = key;
2471keylen = Ustrlen(keyptr);
2472
2473/* If the key is longer than the hash block length, then hash the key
2474first */
2475
2476if (keylen > MD5_HASHBLOCKLEN)
2477 {
2478 chash_start(HMAC_MD5, &md5_base);
2479 chash_end(HMAC_MD5, &md5_base, keyptr, keylen, keyhash);
2480 keyptr = keyhash;
2481 keylen = MD5_HASHLEN;
2482 }
2483
2484/* Now make the inner and outer key values */
2485
2486memset(innerkey, 0x36, MD5_HASHBLOCKLEN);
2487memset(outerkey, 0x5c, MD5_HASHBLOCKLEN);
2488
2489for (int i = 0; i < keylen; i++)
2490 {
2491 innerkey[i] ^= keyptr[i];
2492 outerkey[i] ^= keyptr[i];
2493 }
2494
2495/* Now do the hashes */
2496
2497chash_start(HMAC_MD5, &md5_base);
2498chash_mid(HMAC_MD5, &md5_base, innerkey);
2499chash_end(HMAC_MD5, &md5_base, src, Ustrlen(src), innerhash);
2500
2501chash_start(HMAC_MD5, &md5_base);
2502chash_mid(HMAC_MD5, &md5_base, outerkey);
2503chash_end(HMAC_MD5, &md5_base, innerhash, MD5_HASHLEN, finalhash);
2504
2505/* Encode the final hash as a hex string, limited by output buffer size */
2506
2507p = buf;
2508for (int i = 0, j = len; i < MD5_HASHLEN; i++)
2509 {
2510 if (j-- <= 0) break;
2511 *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
2512 if (j-- <= 0) break;
2513 *p++ = hex_digits[finalhash[i] & 0x0f];
2514 }
2515return;
2516}
f07babc0 2517#endif /*EXPERIMENTAL_SRS_NATIVE*/
7ef88aa0
JH
2518
2519
2520/*************************************************
059ec3d9
PH
2521* Read and evaluate a condition *
2522*************************************************/
2523
2524/*
2525Arguments:
2526 s points to the start of the condition text
b0e85a8f
JH
2527 resetok points to a BOOL which is written false if it is unsafe to
2528 free memory. Certain condition types (acl) may have side-effect
2529 allocation which must be preserved.
059ec3d9
PH
2530 yield points to a BOOL to hold the result of the condition test;
2531 if NULL, we are just reading through a condition that is
2532 part of an "or" combination to check syntax, or in a state
2533 where the answer isn't required
2534
2535Returns: a pointer to the first character after the condition, or
2536 NULL after an error
2537*/
2538
55414b25
JH
2539static const uschar *
2540eval_condition(const uschar *s, BOOL *resetok, BOOL *yield)
059ec3d9
PH
2541{
2542BOOL testfor = TRUE;
2543BOOL tempcond, combined_cond;
2544BOOL *subcondptr;
5cfd2e57 2545BOOL sub2_honour_dollar = TRUE;
7f69e814 2546BOOL is_forany, is_json, is_jsons;
56dbf856 2547int rc, cond_type, roffset;
97d17305 2548int_eximarith_t num[2];
059ec3d9 2549struct stat statbuf;
21aa0597 2550uschar * opname;
059ec3d9 2551uschar name[256];
55414b25 2552const uschar *sub[10];
059ec3d9
PH
2553
2554const pcre *re;
2555const uschar *rerror;
2556
2557for (;;)
9ad27f49 2558 if (Uskip_whitespace(&s) == '!') { testfor = !testfor; s++; } else break;
059ec3d9 2559
21aa0597 2560switch(cond_type = identify_operator(&s, &opname))
059ec3d9 2561 {
9b4768fa
PH
2562 /* def: tests for a non-empty variable, or for the existence of a header. If
2563 yield == NULL we are in a skipping state, and don't care about the answer. */
059ec3d9
PH
2564
2565 case ECOND_DEF:
059ec3d9 2566 {
bce15b62 2567 uschar * t;
059ec3d9 2568
bce15b62
JH
2569 if (*s != ':')
2570 {
2571 expand_string_message = US"\":\" expected after \"def\"";
2572 return NULL;
2573 }
059ec3d9 2574
f3ebb786 2575 s = read_name(name, sizeof(name), s+1, US"_");
059ec3d9 2576
bce15b62
JH
2577 /* Test for a header's existence. If the name contains a closing brace
2578 character, this may be a user error where the terminating colon has been
2579 omitted. Set a flag to adjust a subsequent error message in this case. */
059ec3d9 2580
bce15b62
JH
2581 if ( ( *(t = name) == 'h'
2582 || (*t == 'r' || *t == 'l' || *t == 'b') && *++t == 'h'
2583 )
2584 && (*++t == '_' || Ustrncmp(t, "eader_", 6) == 0)
2585 )
2586 {
f3ebb786 2587 s = read_header_name(name, sizeof(name), s);
bce15b62
JH
2588 /* {-for-text-editors */
2589 if (Ustrchr(name, '}') != NULL) malformed_header = TRUE;
2590 if (yield) *yield =
2591 (find_header(name, NULL, FH_EXISTS_ONLY, NULL) != NULL) == testfor;
2592 }
059ec3d9 2593
bce15b62
JH
2594 /* Test for a variable's having a non-empty value. A non-existent variable
2595 causes an expansion failure. */
2596
2597 else
059ec3d9 2598 {
bce15b62
JH
2599 if (!(t = find_variable(name, TRUE, yield == NULL, NULL)))
2600 {
f3ebb786
JH
2601 expand_string_message = name[0]
2602 ? string_sprintf("unknown variable \"%s\" after \"def:\"", name)
2603 : US"variable name omitted after \"def:\"";
bce15b62
JH
2604 check_variable_error_message(name);
2605 return NULL;
2606 }
2607 if (yield) *yield = (t[0] != 0) == testfor;
059ec3d9 2608 }
059ec3d9 2609
bce15b62
JH
2610 return s;
2611 }
059ec3d9
PH
2612
2613
2614 /* first_delivery tests for first delivery attempt */
2615
2616 case ECOND_FIRST_DELIVERY:
5694b905 2617 if (yield) *yield = f.deliver_firsttime == testfor;
059ec3d9
PH
2618 return s;
2619
2620
2621 /* queue_running tests for any process started by a queue runner */
2622
2623 case ECOND_QUEUE_RUNNING:
5694b905 2624 if (yield) *yield = (queue_run_pid != (pid_t)0) == testfor;
059ec3d9
PH
2625 return s;
2626
2627
2628 /* exists: tests for file existence
2629 isip: tests for any IP address
2630 isip4: tests for an IPv4 address
2631 isip6: tests for an IPv6 address
2632 pam: does PAM authentication
2633 radius: does RADIUS authentication
2634 ldapauth: does LDAP authentication
2635 pwcheck: does Cyrus SASL pwcheck authentication
2636 */
2637
2638 case ECOND_EXISTS:
2639 case ECOND_ISIP:
2640 case ECOND_ISIP4:
2641 case ECOND_ISIP6:
2642 case ECOND_PAM:
2643 case ECOND_RADIUS:
2644 case ECOND_LDAPAUTH:
2645 case ECOND_PWCHECK:
2646
9ad27f49 2647 if (Uskip_whitespace(&s) != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
059ec3d9 2648
b0e85a8f 2649 sub[0] = expand_string_internal(s+1, TRUE, &s, yield == NULL, TRUE, resetok);
5694b905 2650 if (!sub[0]) return NULL;
b5b871ac 2651 /* {-for-text-editors */
059ec3d9
PH
2652 if (*s++ != '}') goto COND_FAILED_CURLY_END;
2653
5694b905 2654 if (!yield) return s; /* No need to run the test if skipping */
059ec3d9
PH
2655
2656 switch(cond_type)
2657 {
2658 case ECOND_EXISTS:
2659 if ((expand_forbid & RDO_EXISTS) != 0)
2660 {
2661 expand_string_message = US"File existence tests are not permitted";
2662 return NULL;
2663 }
2664 *yield = (Ustat(sub[0], &statbuf) == 0) == testfor;
2665 break;
2666
2667 case ECOND_ISIP:
2668 case ECOND_ISIP4:
2669 case ECOND_ISIP6:
2670 rc = string_is_ip_address(sub[0], NULL);
7e66e54d 2671 *yield = ((cond_type == ECOND_ISIP)? (rc != 0) :
059ec3d9
PH
2672 (cond_type == ECOND_ISIP4)? (rc == 4) : (rc == 6)) == testfor;
2673 break;
2674
2675 /* Various authentication tests - all optionally compiled */
2676
2677 case ECOND_PAM:
2678 #ifdef SUPPORT_PAM
2679 rc = auth_call_pam(sub[0], &expand_string_message);
2680 goto END_AUTH;
2681 #else
2682 goto COND_FAILED_NOT_COMPILED;
2683 #endif /* SUPPORT_PAM */
2684
2685 case ECOND_RADIUS:
2686 #ifdef RADIUS_CONFIG_FILE
2687 rc = auth_call_radius(sub[0], &expand_string_message);
2688 goto END_AUTH;
2689 #else
2690 goto COND_FAILED_NOT_COMPILED;
2691 #endif /* RADIUS_CONFIG_FILE */
2692
2693 case ECOND_LDAPAUTH:
2694 #ifdef LOOKUP_LDAP
2695 {
2696 /* Just to keep the interface the same */
2697 BOOL do_cache;
2698 int old_pool = store_pool;
2699 store_pool = POOL_SEARCH;
2700 rc = eldapauth_find((void *)(-1), NULL, sub[0], Ustrlen(sub[0]), NULL,
2701 &expand_string_message, &do_cache);
2702 store_pool = old_pool;
2703 }
2704 goto END_AUTH;
2705 #else
2706 goto COND_FAILED_NOT_COMPILED;
2707 #endif /* LOOKUP_LDAP */
2708
2709 case ECOND_PWCHECK:
2710 #ifdef CYRUS_PWCHECK_SOCKET
2711 rc = auth_call_pwcheck(sub[0], &expand_string_message);
2712 goto END_AUTH;
2713 #else
2714 goto COND_FAILED_NOT_COMPILED;
2715 #endif /* CYRUS_PWCHECK_SOCKET */
2716
2717 #if defined(SUPPORT_PAM) || defined(RADIUS_CONFIG_FILE) || \
2718 defined(LOOKUP_LDAP) || defined(CYRUS_PWCHECK_SOCKET)
2719 END_AUTH:
2720 if (rc == ERROR || rc == DEFER) return NULL;
2721 *yield = (rc == OK) == testfor;
2722 #endif
2723 }
2724 return s;
2725
2726
333eea9c
JH
2727 /* call ACL (in a conditional context). Accept true, deny false.
2728 Defer is a forced-fail. Anything set by message= goes to $value.
f60d98e8
JH
2729 Up to ten parameters are used; we use the braces round the name+args
2730 like the saslauthd condition does, to permit a variable number of args.
2731 See also the expansion-item version EITEM_ACL and the traditional
2732 acl modifier ACLC_ACL.
fd5dad68
JH
2733 Since the ACL may allocate new global variables, tell our caller to not
2734 reclaim memory.
f60d98e8 2735 */
333eea9c
JH
2736
2737 case ECOND_ACL:
bef3ea7f 2738 /* ${if acl {{name}{arg1}{arg2}...} {yes}{no}} */
333eea9c 2739 {
55414b25 2740 uschar *sub[10];
333eea9c 2741 uschar *user_msg;
333eea9c 2742 BOOL cond = FALSE;
333eea9c 2743
9ad27f49 2744 Uskip_whitespace(&s);
6d9cfc47 2745 if (*s++ != '{') goto COND_FAILED_CURLY_START; /*}*/
333eea9c 2746
0539a19d 2747 switch(read_subs(sub, nelem(sub), 1,
48b30ae1 2748 &s, yield == NULL, TRUE, name, resetok))
333eea9c 2749 {
f60d98e8
JH
2750 case 1: expand_string_message = US"too few arguments or bracketing "
2751 "error for acl";
2752 case 2:
2753 case 3: return NULL;
333eea9c 2754 }
f60d98e8 2755
5694b905 2756 if (yield)
9e70917d 2757 {
17ccbda6 2758 int rc;
9e70917d 2759 *resetok = FALSE; /* eval_acl() might allocate; do not reclaim */
17ccbda6 2760 switch(rc = eval_acl(sub, nelem(sub), &user_msg))
f60d98e8
JH
2761 {
2762 case OK:
2763 cond = TRUE;
2764 case FAIL:
bef3ea7f 2765 lookup_value = NULL;
f60d98e8 2766 if (user_msg)
acec9514 2767 lookup_value = string_copy(user_msg);
b5b871ac 2768 *yield = cond == testfor;
f60d98e8
JH
2769 break;
2770
2771 case DEFER:
8768d548 2772 f.expand_string_forcedfail = TRUE;
6e3b198d 2773 /*FALLTHROUGH*/
f60d98e8 2774 default:
17ccbda6
JH
2775 expand_string_message = string_sprintf("%s from acl \"%s\"",
2776 rc_names[rc], sub[0]);
f60d98e8
JH
2777 return NULL;
2778 }
9e70917d 2779 }
f60d98e8 2780 return s;
333eea9c 2781 }
333eea9c
JH
2782
2783
059ec3d9
PH
2784 /* saslauthd: does Cyrus saslauthd authentication. Four parameters are used:
2785
b0e85a8f 2786 ${if saslauthd {{username}{password}{service}{realm}} {yes}{no}}
059ec3d9
PH
2787
2788 However, the last two are optional. That is why the whole set is enclosed
333eea9c 2789 in their own set of braces. */
059ec3d9
PH
2790
2791 case ECOND_SASLAUTHD:
0539a19d
JH
2792#ifndef CYRUS_SASLAUTHD_SOCKET
2793 goto COND_FAILED_NOT_COMPILED;
2794#else
059ec3d9 2795 {
0539a19d 2796 uschar *sub[4];
9ad27f49 2797 Uskip_whitespace(&s);
0539a19d 2798 if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
48b30ae1 2799 switch(read_subs(sub, nelem(sub), 2, &s, yield == NULL, TRUE, name,
0539a19d
JH
2800 resetok))
2801 {
2802 case 1: expand_string_message = US"too few arguments or bracketing "
2803 "error for saslauthd";
2804 case 2:
2805 case 3: return NULL;
2806 }
5694b905
JH
2807 if (!sub[2]) sub[3] = NULL; /* realm if no service */
2808 if (yield)
0539a19d
JH
2809 {
2810 int rc = auth_call_saslauthd(sub[0], sub[1], sub[2], sub[3],
2811 &expand_string_message);
2812 if (rc == ERROR || rc == DEFER) return NULL;
2813 *yield = (rc == OK) == testfor;
2814 }
2815 return s;
059ec3d9 2816 }
0539a19d 2817#endif /* CYRUS_SASLAUTHD_SOCKET */
059ec3d9
PH
2818
2819
2820 /* symbolic operators for numeric and string comparison, and a number of
2821 other operators, all requiring two arguments.
2822
76dca828
PP
2823 crypteq: encrypts plaintext and compares against an encrypted text,
2824 using crypt(), crypt16(), MD5 or SHA-1
2825 inlist/inlisti: checks if first argument is in the list of the second
059ec3d9
PH
2826 match: does a regular expression match and sets up the numerical
2827 variables if it succeeds
2828 match_address: matches in an address list
2829 match_domain: matches in a domain list
32d668a5 2830 match_ip: matches a host list that is restricted to IP addresses
059ec3d9 2831 match_local_part: matches in a local part list
059ec3d9
PH
2832 */
2833
059ec3d9
PH
2834 case ECOND_MATCH_ADDRESS:
2835 case ECOND_MATCH_DOMAIN:
32d668a5 2836 case ECOND_MATCH_IP:
059ec3d9 2837 case ECOND_MATCH_LOCAL_PART:
da6dbe26
PP
2838#ifndef EXPAND_LISTMATCH_RHS
2839 sub2_honour_dollar = FALSE;
2840#endif
2841 /* FALLTHROUGH */
2842
2843 case ECOND_CRYPTEQ:
2844 case ECOND_INLIST:
2845 case ECOND_INLISTI:
2846 case ECOND_MATCH:
059ec3d9
PH
2847
2848 case ECOND_NUM_L: /* Numerical comparisons */
2849 case ECOND_NUM_LE:
2850 case ECOND_NUM_E:
2851 case ECOND_NUM_EE:
2852 case ECOND_NUM_G:
2853 case ECOND_NUM_GE:
2854
2855 case ECOND_STR_LT: /* String comparisons */
2856 case ECOND_STR_LTI:
2857 case ECOND_STR_LE:
2858 case ECOND_STR_LEI:
2859 case ECOND_STR_EQ:
2860 case ECOND_STR_EQI:
2861 case ECOND_STR_GT:
2862 case ECOND_STR_GTI:
2863 case ECOND_STR_GE:
2864 case ECOND_STR_GEI:
2865
d7978c0f 2866 for (int i = 0; i < 2; i++)
059ec3d9 2867 {
da6dbe26
PP
2868 /* Sometimes, we don't expand substrings; too many insecure configurations
2869 created using match_address{}{} and friends, where the second param
2870 includes information from untrustworthy sources. */
2871 BOOL honour_dollar = TRUE;
2872 if ((i > 0) && !sub2_honour_dollar)
2873 honour_dollar = FALSE;
2874
9ad27f49 2875 if (Uskip_whitespace(&s) != '{')
059ec3d9
PH
2876 {
2877 if (i == 0) goto COND_FAILED_CURLY_START;
2878 expand_string_message = string_sprintf("missing 2nd string in {} "
21aa0597 2879 "after \"%s\"", opname);
059ec3d9
PH
2880 return NULL;
2881 }
d584cdca
JH
2882 if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, yield == NULL,
2883 honour_dollar, resetok)))
2884 return NULL;
2885 DEBUG(D_expand) if (i == 1 && !sub2_honour_dollar && Ustrchr(sub[1], '$'))
2886 debug_printf_indent("WARNING: the second arg is NOT expanded,"
2887 " for security reasons\n");
059ec3d9
PH
2888 if (*s++ != '}') goto COND_FAILED_CURLY_END;
2889
2890 /* Convert to numerical if required; we know that the names of all the
2891 conditions that compare numbers do not start with a letter. This just saves
2892 checking for them individually. */
2893
5694b905 2894 if (!isalpha(opname[0]) && yield)
5dd1517f
PH
2895 if (sub[i][0] == 0)
2896 {
2897 num[i] = 0;
2898 DEBUG(D_expand)
e1d04f48 2899 debug_printf_indent("empty string cast to zero for numerical comparison\n");
5dd1517f
PH
2900 }
2901 else
2902 {
7685ce68 2903 num[i] = expanded_string_integer(sub[i], FALSE);
5694b905 2904 if (expand_string_message) return NULL;
5dd1517f 2905 }
059ec3d9
PH
2906 }
2907
2908 /* Result not required */
2909
5694b905 2910 if (!yield) return s;
059ec3d9
PH
2911
2912 /* Do an appropriate comparison */
2913
2914 switch(cond_type)
2915 {
2916 case ECOND_NUM_E:
2917 case ECOND_NUM_EE:
b5b871ac 2918 tempcond = (num[0] == num[1]);
059ec3d9
PH
2919 break;
2920
2921 case ECOND_NUM_G:
b5b871ac 2922 tempcond = (num[0] > num[1]);
059ec3d9
PH
2923 break;
2924
2925 case ECOND_NUM_GE:
b5b871ac 2926 tempcond = (num[0] >= num[1]);
059ec3d9
PH
2927 break;
2928
2929 case ECOND_NUM_L:
b5b871ac 2930 tempcond = (num[0] < num[1]);
059ec3d9
PH
2931 break;
2932
2933 case ECOND_NUM_LE:
b5b871ac 2934 tempcond = (num[0] <= num[1]);
059ec3d9
PH
2935 break;
2936
2937 case ECOND_STR_LT:
b5b871ac 2938 tempcond = (Ustrcmp(sub[0], sub[1]) < 0);
059ec3d9
PH
2939 break;
2940
2941 case ECOND_STR_LTI:
b5b871ac 2942 tempcond = (strcmpic(sub[0], sub[1]) < 0);
059ec3d9
PH
2943 break;
2944
2945 case ECOND_STR_LE:
b5b871ac 2946 tempcond = (Ustrcmp(sub[0], sub[1]) <= 0);
059ec3d9
PH
2947 break;
2948
2949 case ECOND_STR_LEI:
b5b871ac 2950 tempcond = (strcmpic(sub[0], sub[1]) <= 0);
059ec3d9
PH
2951 break;
2952
2953 case ECOND_STR_EQ:
b5b871ac 2954 tempcond = (Ustrcmp(sub[0], sub[1]) == 0);
059ec3d9
PH
2955 break;
2956
2957 case ECOND_STR_EQI:
b5b871ac 2958 tempcond = (strcmpic(sub[0], sub[1]) == 0);
059ec3d9
PH
2959 break;
2960
2961 case ECOND_STR_GT:
b5b871ac 2962 tempcond = (Ustrcmp(sub[0], sub[1]) > 0);
059ec3d9
PH
2963 break;
2964
2965 case ECOND_STR_GTI:
b5b871ac 2966 tempcond = (strcmpic(sub[0], sub[1]) > 0);
059ec3d9
PH
2967 break;
2968
2969 case ECOND_STR_GE:
b5b871ac 2970 tempcond = (Ustrcmp(sub[0], sub[1]) >= 0);
059ec3d9
PH
2971 break;
2972
2973 case ECOND_STR_GEI:
b5b871ac 2974 tempcond = (strcmpic(sub[0], sub[1]) >= 0);
059ec3d9
PH
2975 break;
2976
2977 case ECOND_MATCH: /* Regular expression match */
3d2e82c5 2978 if (!(re = pcre_compile(CS sub[1], PCRE_COPT, CCSS &rerror,
5694b905 2979 &roffset, NULL)))
059ec3d9
PH
2980 {
2981 expand_string_message = string_sprintf("regular expression error in "
2982 "\"%s\": %s at offset %d", sub[1], rerror, roffset);
2983 return NULL;
2984 }
b5b871ac 2985 tempcond = regex_match_and_setup(re, sub[0], 0, -1);
059ec3d9
PH
2986 break;
2987
2988 case ECOND_MATCH_ADDRESS: /* Match in an address list */
2989 rc = match_address_list(sub[0], TRUE, FALSE, &(sub[1]), NULL, -1, 0, NULL);
2990 goto MATCHED_SOMETHING;
2991
2992 case ECOND_MATCH_DOMAIN: /* Match in a domain list */
2993 rc = match_isinlist(sub[0], &(sub[1]), 0, &domainlist_anchor, NULL,
2994 MCL_DOMAIN + MCL_NOEXPAND, TRUE, NULL);
2995 goto MATCHED_SOMETHING;
2996
32d668a5 2997 case ECOND_MATCH_IP: /* Match IP address in a host list */
7e66e54d 2998 if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) == 0)
32d668a5
PH
2999 {
3000 expand_string_message = string_sprintf("\"%s\" is not an IP address",
3001 sub[0]);
3002 return NULL;
3003 }
3004 else
3005 {
3006 unsigned int *nullcache = NULL;
3007 check_host_block cb;
3008
3009 cb.host_name = US"";
3010 cb.host_address = sub[0];
3011
3012 /* If the host address starts off ::ffff: it is an IPv6 address in
3013 IPv4-compatible mode. Find the IPv4 part for checking against IPv4
3014 addresses. */
3015
3016 cb.host_ipv4 = (Ustrncmp(cb.host_address, "::ffff:", 7) == 0)?
3017 cb.host_address + 7 : cb.host_address;
3018
3019 rc = match_check_list(
3020 &sub[1], /* the list */
3021 0, /* separator character */
3022 &hostlist_anchor, /* anchor pointer */
3023 &nullcache, /* cache pointer */
3024 check_host, /* function for testing */
3025 &cb, /* argument for function */
3026 MCL_HOST, /* type of check */
3027 sub[0], /* text for debugging */
3028 NULL); /* where to pass back data */
3029 }
3030 goto MATCHED_SOMETHING;
3031
059ec3d9
PH
3032 case ECOND_MATCH_LOCAL_PART:
3033 rc = match_isinlist(sub[0], &(sub[1]), 0, &localpartlist_anchor, NULL,
3034 MCL_LOCALPART + MCL_NOEXPAND, TRUE, NULL);
3035 /* Fall through */
9a26b6b2 3036 /* VVVVVVVVVVVV */
059ec3d9
PH
3037 MATCHED_SOMETHING:
3038 switch(rc)
3039 {
3040 case OK:
b5b871ac 3041 tempcond = TRUE;
059ec3d9
PH
3042 break;
3043
3044 case FAIL:
b5b871ac 3045 tempcond = FALSE;
059ec3d9
PH
3046 break;
3047
3048 case DEFER:
3049 expand_string_message = string_sprintf("unable to complete match "
3050 "against \"%s\": %s", sub[1], search_error_message);
3051 return NULL;
3052 }
3053
3054 break;
3055
3056 /* Various "encrypted" comparisons. If the second string starts with
3057 "{" then an encryption type is given. Default to crypt() or crypt16()
3058 (build-time choice). */
b5b871ac 3059 /* }-for-text-editors */
059ec3d9
PH
3060
3061 case ECOND_CRYPTEQ:
3062 #ifndef SUPPORT_CRYPTEQ
3063 goto COND_FAILED_NOT_COMPILED;
3064 #else
3065 if (strncmpic(sub[1], US"{md5}", 5) == 0)
3066 {
3067 int sublen = Ustrlen(sub[1]+5);
3068 md5 base;
3069 uschar digest[16];
3070
3071 md5_start(&base);
cfab9d68 3072 md5_end(&base, sub[0], Ustrlen(sub[0]), digest);
059ec3d9
PH
3073
3074 /* If the length that we are comparing against is 24, the MD5 digest
3075 is expressed as a base64 string. This is the way LDAP does it. However,
3076 some other software uses a straightforward hex representation. We assume
3077 this if the length is 32. Other lengths fail. */
3078
3079 if (sublen == 24)
3080 {
1f20760b 3081 uschar *coded = b64encode(CUS digest, 16);
059ec3d9
PH
3082 DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n"
3083 " subject=%s\n crypted=%s\n", coded, sub[1]+5);
b5b871ac 3084 tempcond = (Ustrcmp(coded, sub[1]+5) == 0);
059ec3d9
PH
3085 }
3086 else if (sublen == 32)
3087 {
059ec3d9 3088 uschar coded[36];
d7978c0f 3089 for (int i = 0; i < 16; i++) sprintf(CS (coded+2*i), "%02X", digest[i]);
059ec3d9
PH
3090 coded[32] = 0;
3091 DEBUG(D_auth) debug_printf("crypteq: using MD5+hex hashing\n"
3092 " subject=%s\n crypted=%s\n", coded, sub[1]+5);
b5b871ac 3093 tempcond = (strcmpic(coded, sub[1]+5) == 0);
059ec3d9
PH
3094 }
3095 else
3096 {
3097 DEBUG(D_auth) debug_printf("crypteq: length for MD5 not 24 or 32: "
3098 "fail\n crypted=%s\n", sub[1]+5);
b5b871ac 3099 tempcond = FALSE;
059ec3d9
PH
3100 }
3101 }
3102
3103 else if (strncmpic(sub[1], US"{sha1}", 6) == 0)
3104 {
3105 int sublen = Ustrlen(sub[1]+6);
5fb822fc 3106 hctx h;
059ec3d9
PH
3107 uschar digest[20];
3108
5fb822fc 3109 sha1_start(&h);
cfab9d68 3110 sha1_end(&h, sub[0], Ustrlen(sub[0]), digest);
059ec3d9
PH
3111
3112 /* If the length that we are comparing against is 28, assume the SHA1
3113 digest is expressed as a base64 string. If the length is 40, assume a
3114 straightforward hex representation. Other lengths fail. */
3115
3116 if (sublen == 28)
3117 {
1f20760b 3118 uschar *coded = b64encode(CUS digest, 20);
059ec3d9
PH
3119 DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n"
3120 " subject=%s\n crypted=%s\n", coded, sub[1]+6);
b5b871ac 3121 tempcond = (Ustrcmp(coded, sub[1]+6) == 0);
059ec3d9
PH
3122 }
3123 else if (sublen == 40)
3124 {
059ec3d9 3125 uschar coded[44];
d7978c0f 3126 for (int i = 0; i < 20; i++) sprintf(CS (coded+2*i), "%02X", digest[i]);
059ec3d9
PH
3127 coded[40] = 0;
3128 DEBUG(D_auth) debug_printf("crypteq: using SHA1+hex hashing\n"
3129 " subject=%s\n crypted=%s\n", coded, sub[1]+6);
b5b871ac 3130 tempcond = (strcmpic(coded, sub[1]+6) == 0);
059ec3d9
PH
3131 }
3132 else
3133 {
3134 DEBUG(D_auth) debug_printf("crypteq: length for SHA-1 not 28 or 40: "
3135 "fail\n crypted=%s\n", sub[1]+6);
b5b871ac 3136 tempcond = FALSE;
059ec3d9
PH
3137 }
3138 }
3139
3140 else /* {crypt} or {crypt16} and non-{ at start */
76dca828 3141 /* }-for-text-editors */
059ec3d9
PH
3142 {
3143 int which = 0;
3144 uschar *coded;
3145
3146 if (strncmpic(sub[1], US"{crypt}", 7) == 0)
3147 {
3148 sub[1] += 7;
3149 which = 1;
3150 }
3151 else if (strncmpic(sub[1], US"{crypt16}", 9) == 0)
3152 {
3153 sub[1] += 9;
3154 which = 2;
3155 }
b5b871ac 3156 else if (sub[1][0] == '{') /* }-for-text-editors */
059ec3d9
PH
3157 {
3158 expand_string_message = string_sprintf("unknown encryption mechanism "
3159 "in \"%s\"", sub[1]);
3160 return NULL;
3161 }
3162
3163 switch(which)
3164 {
3165 case 0: coded = US DEFAULT_CRYPT(CS sub[0], CS sub[1]); break;
3166 case 1: coded = US crypt(CS sub[0], CS sub[1]); break;
3167 default: coded = US crypt16(CS sub[0], CS sub[1]); break;
3168 }
3169
3170 #define STR(s) # s
3171 #define XSTR(s) STR(s)
3172 DEBUG(D_auth) debug_printf("crypteq: using %s()\n"
3173 " subject=%s\n crypted=%s\n",
9dc2b215 3174 which == 0 ? XSTR(DEFAULT_CRYPT) : which == 1 ? "crypt" : "crypt16",
059ec3d9
PH
3175 coded, sub[1]);
3176 #undef STR
3177 #undef XSTR
3178
3179 /* If the encrypted string contains fewer than two characters (for the
3180 salt), force failure. Otherwise we get false positives: with an empty
3181 string the yield of crypt() is an empty string! */
3182
9dc2b215
JH
3183 if (coded)
3184 tempcond = Ustrlen(sub[1]) < 2 ? FALSE : Ustrcmp(coded, sub[1]) == 0;
3185 else if (errno == EINVAL)
3186 tempcond = FALSE;
3187 else
3188 {
3189 expand_string_message = string_sprintf("crypt error: %s\n",
3190 US strerror(errno));
3191 return NULL;
3192 }
059ec3d9
PH
3193 }
3194 break;
3195 #endif /* SUPPORT_CRYPTEQ */
76dca828
PP
3196
3197 case ECOND_INLIST:
3198 case ECOND_INLISTI:
3199 {
55414b25 3200 const uschar * list = sub[1];
76dca828 3201 int sep = 0;
76dca828
PP
3202 uschar *save_iterate_item = iterate_item;
3203 int (*compare)(const uschar *, const uschar *);
3204
21aa0597 3205 DEBUG(D_expand) debug_printf_indent("condition: %s item: %s\n", opname, sub[0]);
82dbd376 3206
b5b871ac 3207 tempcond = FALSE;
55414b25
JH
3208 compare = cond_type == ECOND_INLISTI
3209 ? strcmpic : (int (*)(const uschar *, const uschar *)) strcmp;
76dca828 3210
55414b25 3211 while ((iterate_item = string_nextinlist(&list, &sep, NULL, 0)))
05e796ad
JH
3212 {
3213 DEBUG(D_expand) debug_printf_indent(" compare %s\n", iterate_item);
76dca828
PP
3214 if (compare(sub[0], iterate_item) == 0)
3215 {
b5b871ac 3216 tempcond = TRUE;
76dca828
PP
3217 break;
3218 }
05e796ad 3219 }
76dca828 3220 iterate_item = save_iterate_item;
76dca828
PP
3221 }
3222
059ec3d9
PH
3223 } /* Switch for comparison conditions */
3224
b5b871ac 3225 *yield = tempcond == testfor;
059ec3d9
PH
3226 return s; /* End of comparison conditions */
3227
3228
3229 /* and/or: computes logical and/or of several conditions */
3230
3231 case ECOND_AND:
3232 case ECOND_OR:
5694b905 3233 subcondptr = (yield == NULL) ? NULL : &tempcond;
059ec3d9
PH
3234 combined_cond = (cond_type == ECOND_AND);
3235
9ad27f49 3236 Uskip_whitespace(&s);
b5b871ac 3237 if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
059ec3d9
PH
3238
3239 for (;;)
3240 {
b5b871ac 3241 /* {-for-text-editors */
9ad27f49 3242 if (Uskip_whitespace(&s) == '}') break;
b5b871ac 3243 if (*s != '{') /* }-for-text-editors */
059ec3d9
PH
3244 {
3245 expand_string_message = string_sprintf("each subcondition "
21aa0597 3246 "inside an \"%s{...}\" condition must be in its own {}", opname);
059ec3d9
PH
3247 return NULL;
3248 }
3249
b0e85a8f 3250 if (!(s = eval_condition(s+1, resetok, subcondptr)))
059ec3d9
PH
3251 {
3252 expand_string_message = string_sprintf("%s inside \"%s{...}\" condition",
21aa0597 3253 expand_string_message, opname);
059ec3d9
PH
3254 return NULL;
3255 }
9ad27f49 3256 Uskip_whitespace(&s);
059ec3d9 3257
b5b871ac 3258 /* {-for-text-editors */
059ec3d9
PH
3259 if (*s++ != '}')
3260 {
b5b871ac 3261 /* {-for-text-editors */
059ec3d9 3262 expand_string_message = string_sprintf("missing } at end of condition "
21aa0597 3263 "inside \"%s\" group", opname);
059ec3d9
PH
3264 return NULL;
3265 }
3266
5694b905 3267 if (yield)
059ec3d9
PH
3268 if (cond_type == ECOND_AND)
3269 {
3270 combined_cond &= tempcond;
3271 if (!combined_cond) subcondptr = NULL; /* once false, don't */
3272 } /* evaluate any more */
3273 else
3274 {
3275 combined_cond |= tempcond;
3276 if (combined_cond) subcondptr = NULL; /* once true, don't */
3277 } /* evaluate any more */
059ec3d9
PH
3278 }
3279
5694b905 3280 if (yield) *yield = (combined_cond == testfor);
059ec3d9
PH
3281 return ++s;
3282
3283
0ce9abe6
PH
3284 /* forall/forany: iterates a condition with different values */
3285
7f69e814
JH
3286 case ECOND_FORALL: is_forany = FALSE; is_json = FALSE; is_jsons = FALSE; goto FORMANY;
3287 case ECOND_FORANY: is_forany = TRUE; is_json = FALSE; is_jsons = FALSE; goto FORMANY;
3288 case ECOND_FORALL_JSON: is_forany = FALSE; is_json = TRUE; is_jsons = FALSE; goto FORMANY;
3289 case ECOND_FORANY_JSON: is_forany = TRUE; is_json = TRUE; is_jsons = FALSE; goto FORMANY;
3290 case ECOND_FORALL_JSONS: is_forany = FALSE; is_json = TRUE; is_jsons = TRUE; goto FORMANY;
3291 case ECOND_FORANY_JSONS: is_forany = TRUE; is_json = TRUE; is_jsons = TRUE; goto FORMANY;
3292
3293 FORMANY:
0ce9abe6 3294 {
55414b25 3295 const uschar * list;
0ce9abe6 3296 int sep = 0;
282b357d 3297 uschar *save_iterate_item = iterate_item;
0ce9abe6 3298
21aa0597 3299 DEBUG(D_expand) debug_printf_indent("condition: %s\n", opname);
82dbd376 3300
9ad27f49 3301 Uskip_whitespace(&s);
b5b871ac 3302 if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
5694b905
JH
3303 if (!(sub[0] = expand_string_internal(s, TRUE, &s, yield == NULL, TRUE, resetok)))
3304 return NULL;
b5b871ac 3305 /* {-for-text-editors */
0ce9abe6
PH
3306 if (*s++ != '}') goto COND_FAILED_CURLY_END;
3307
9ad27f49 3308 Uskip_whitespace(&s);
b5b871ac 3309 if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
0ce9abe6
PH
3310
3311 sub[1] = s;
3312
3313 /* Call eval_condition once, with result discarded (as if scanning a
3314 "false" part). This allows us to find the end of the condition, because if
3315 the list it empty, we won't actually evaluate the condition for real. */
3316
b0e85a8f 3317 if (!(s = eval_condition(sub[1], resetok, NULL)))
0ce9abe6
PH
3318 {
3319 expand_string_message = string_sprintf("%s inside \"%s\" condition",
21aa0597 3320 expand_string_message, opname);
0ce9abe6
PH
3321 return NULL;
3322 }
9ad27f49 3323 Uskip_whitespace(&s);
0ce9abe6 3324
b5b871ac 3325 /* {-for-text-editors */
0ce9abe6
PH
3326 if (*s++ != '}')
3327 {
b5b871ac 3328 /* {-for-text-editors */
0ce9abe6 3329 expand_string_message = string_sprintf("missing } at end of condition "
21aa0597 3330 "inside \"%s\"", opname);
0ce9abe6
PH
3331 return NULL;
3332 }
3333
7f69e814 3334 if (yield) *yield = !testfor;
55414b25 3335 list = sub[0];
7f69e814
JH
3336 if (is_json) list = dewrap(string_copy(list), US"[]");
3337 while ((iterate_item = is_json
3338 ? json_nextinlist(&list) : string_nextinlist(&list, &sep, NULL, 0)))
0ce9abe6 3339 {
7f69e814
JH
3340 if (is_jsons)
3341 if (!(iterate_item = dewrap(iterate_item, US"\"\"")))
3342 {
3343 expand_string_message =
3344 string_sprintf("%s wrapping string result for extract jsons",
3345 expand_string_message);
3346 iterate_item = save_iterate_item;
3347 return NULL;
3348 }
3349
f3ebb786 3350 DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", opname, iterate_item);
b0e85a8f 3351 if (!eval_condition(sub[1], resetok, &tempcond))
0ce9abe6
PH
3352 {
3353 expand_string_message = string_sprintf("%s inside \"%s\" condition",
21aa0597 3354 expand_string_message, opname);
e58c13cc 3355 iterate_item = save_iterate_item;
0ce9abe6
PH
3356 return NULL;
3357 }
21aa0597 3358 DEBUG(D_expand) debug_printf_indent("%s: condition evaluated to %s\n", opname,
0ce9abe6
PH
3359 tempcond? "true":"false");
3360
7f69e814
JH
3361 if (yield) *yield = (tempcond == testfor);
3362 if (tempcond == is_forany) break;
0ce9abe6
PH
3363 }
3364
282b357d 3365 iterate_item = save_iterate_item;
0ce9abe6
PH
3366 return s;
3367 }
3368
3369
f3766eb5
NM
3370 /* The bool{} expansion condition maps a string to boolean.
3371 The values supported should match those supported by the ACL condition
3372 (acl.c, ACLC_CONDITION) so that we keep to a minimum the different ideas
3373 of true/false. Note that Router "condition" rules have a different
3374 interpretation, where general data can be used and only a few values
3375 map to FALSE.
3376 Note that readconf.c boolean matching, for boolean configuration options,
6a8de854
PP
3377 only matches true/yes/false/no.
3378 The bool_lax{} condition matches the Router logic, which is much more
3379 liberal. */
f3766eb5 3380 case ECOND_BOOL:
6a8de854 3381 case ECOND_BOOL_LAX:
f3766eb5
NM
3382 {
3383 uschar *sub_arg[1];
71265ae9 3384 uschar *t, *t2;
6a8de854 3385 uschar *ourname;
f3766eb5
NM
3386 size_t len;
3387 BOOL boolvalue = FALSE;
9ad27f49
JH
3388
3389 if (Uskip_whitespace(&s) != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
6a8de854 3390 ourname = cond_type == ECOND_BOOL_LAX ? US"bool_lax" : US"bool";
b0e85a8f 3391 switch(read_subs(sub_arg, 1, 1, &s, yield == NULL, FALSE, ourname, resetok))
f3766eb5 3392 {
6a8de854
PP
3393 case 1: expand_string_message = string_sprintf(
3394 "too few arguments or bracketing error for %s",
3395 ourname);
f3766eb5
NM
3396 /*FALLTHROUGH*/
3397 case 2:
3398 case 3: return NULL;
3399 }
3400 t = sub_arg[0];
9ad27f49
JH
3401 Uskip_whitespace(&t);
3402 if ((len = Ustrlen(t)))
71265ae9
PP
3403 {
3404 /* trailing whitespace: seems like a good idea to ignore it too */
3405 t2 = t + len - 1;
3406 while (isspace(*t2)) t2--;
3407 if (t2 != (t + len))
3408 {
3409 *++t2 = '\0';
3410 len = t2 - t;
3411 }
3412 }
f3766eb5 3413 DEBUG(D_expand)
e1d04f48 3414 debug_printf_indent("considering %s: %s\n", ourname, len ? t : US"<empty>");
6a8de854
PP
3415 /* logic for the lax case from expand_check_condition(), which also does
3416 expands, and the logic is both short and stable enough that there should
3417 be no maintenance burden from replicating it. */
f3766eb5
NM
3418 if (len == 0)
3419 boolvalue = FALSE;
51c7471d
JH
3420 else if (*t == '-'
3421 ? Ustrspn(t+1, "0123456789") == len-1
3422 : Ustrspn(t, "0123456789") == len)
6a8de854 3423 {
f3766eb5 3424 boolvalue = (Uatoi(t) == 0) ? FALSE : TRUE;
6a8de854
PP
3425 /* expand_check_condition only does a literal string "0" check */
3426 if ((cond_type == ECOND_BOOL_LAX) && (len > 1))
3427 boolvalue = TRUE;
3428 }
f3766eb5
NM
3429 else if (strcmpic(t, US"true") == 0 || strcmpic(t, US"yes") == 0)
3430 boolvalue = TRUE;
3431 else if (strcmpic(t, US"false") == 0 || strcmpic(t, US"no") == 0)
3432 boolvalue = FALSE;
6a8de854
PP
3433 else if (cond_type == ECOND_BOOL_LAX)
3434 boolvalue = TRUE;
f3766eb5
NM
3435 else
3436 {
3437 expand_string_message = string_sprintf("unrecognised boolean "
3438 "value \"%s\"", t);
3439 return NULL;
3440 }
e1d04f48 3441 DEBUG(D_expand) debug_printf_indent("%s: condition evaluated to %s\n", ourname,
c7c833c6 3442 boolvalue? "true":"false");
5694b905 3443 if (yield) *yield = (boolvalue == testfor);
f3766eb5
NM
3444 return s;
3445 }
3446
7ef88aa0
JH
3447#ifdef EXPERIMENTAL_SRS_NATIVE
3448 case ECOND_INBOUND_SRS:
3449 /* ${if inbound_srs {local_part}{secret} {yes}{no}} */
3450 {
3451 uschar * sub[2];
3452 const pcre * re;
3453 int ovec[3*(4+1)];
3454 int n;
3455 uschar cksum[4];
3456 BOOL boolvalue = FALSE;
3457
48b30ae1