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