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