X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/254e032f97775a5331fdeb3ba0df9a96f52494d7..d7d7b7b91dd75cec636fc144da7e27eed860f971:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index 92e342d37..4ff6e5043 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/expand.c,v 1.39 2005/08/01 15:01:12 ph10 Exp $ */ +/* $Cambridge: exim/src/src/expand.c,v 1.53 2006/02/07 11:19:00 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2006 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -298,26 +298,6 @@ enum { /* This table must be kept in alphabetical order. */ static var_entry var_table[] = { - { "acl_c0", vtype_stringptr, &acl_var[0] }, - { "acl_c1", vtype_stringptr, &acl_var[1] }, - { "acl_c2", vtype_stringptr, &acl_var[2] }, - { "acl_c3", vtype_stringptr, &acl_var[3] }, - { "acl_c4", vtype_stringptr, &acl_var[4] }, - { "acl_c5", vtype_stringptr, &acl_var[5] }, - { "acl_c6", vtype_stringptr, &acl_var[6] }, - { "acl_c7", vtype_stringptr, &acl_var[7] }, - { "acl_c8", vtype_stringptr, &acl_var[8] }, - { "acl_c9", vtype_stringptr, &acl_var[9] }, - { "acl_m0", vtype_stringptr, &acl_var[10] }, - { "acl_m1", vtype_stringptr, &acl_var[11] }, - { "acl_m2", vtype_stringptr, &acl_var[12] }, - { "acl_m3", vtype_stringptr, &acl_var[13] }, - { "acl_m4", vtype_stringptr, &acl_var[14] }, - { "acl_m5", vtype_stringptr, &acl_var[15] }, - { "acl_m6", vtype_stringptr, &acl_var[16] }, - { "acl_m7", vtype_stringptr, &acl_var[17] }, - { "acl_m8", vtype_stringptr, &acl_var[18] }, - { "acl_m9", vtype_stringptr, &acl_var[19] }, { "acl_verify_message", vtype_stringptr, &acl_verify_message }, { "address_data", vtype_stringptr, &deliver_address_data }, { "address_file", vtype_stringptr, &address_file }, @@ -482,7 +462,8 @@ static var_entry var_table[] = { { "sender_rcvhost", vtype_stringptr, &sender_rcvhost }, { "sender_verify_failure",vtype_stringptr, &sender_verify_failure }, { "smtp_active_hostname", vtype_stringptr, &smtp_active_hostname }, - { "smtp_command_argument", vtype_stringptr, &smtp_command_argument }, + { "smtp_command", vtype_stringptr, &smtp_cmd_buffer }, + { "smtp_command_argument", vtype_stringptr, &smtp_cmd_argument }, { "sn0", vtype_filter_int, &filter_sn[0] }, { "sn1", vtype_filter_int, &filter_sn[1] }, { "sn2", vtype_filter_int, &filter_sn[2] }, @@ -1204,7 +1185,8 @@ else uschar *decoded, *error; while (ptr > yield && isspace(ptr[-1])) ptr--; *ptr = 0; - decoded = rfc2047_decode2(yield, TRUE, charset, '?', NULL, newsize, &error); + decoded = rfc2047_decode2(yield, check_rfc2047_length, charset, '?', NULL, + newsize, &error); if (error != NULL) { DEBUG(D_any) debug_printf("*** error in RFC 2047 decoding: %s\n" @@ -1247,6 +1229,38 @@ find_variable(uschar *name, BOOL exists_only, BOOL skipping, int *newsize) int first = 0; int last = var_table_size; +/* Handle ACL variables, which are not in the table because their number may +vary depending on a build-time setting. If the variable's name is not of the +form acl_mddd or acl_cddd, where the d's are digits, fall through to look for +other names that start with acl_. */ + +if (Ustrncmp(name, "acl_", 4) == 0) + { + uschar *endptr; + int offset = -1; + int max = 0; + + if (name[4] == 'm') + { + offset = ACL_CVARS; + max = ACL_MVARS; + } + else if (name[4] == 'c') + { + offset = 0; + max = ACL_CVARS; + } + + if (offset >= 0) + { + int n = Ustrtoul(name + 5, &endptr, 10); + if (*endptr == 0 && n < max) + return (acl_var[offset + n] == NULL)? US"" : acl_var[offset + n]; + } + } + +/* For all other variables, search the table */ + while (last > first) { uschar *s, *domain; @@ -1258,7 +1272,7 @@ while (last > first) if (c < 0) { last = middle; continue; } /* Found an existing variable. If in skipping state, the value isn't needed, - and we want to avoid processing (such as looking up up the host name). */ + and we want to avoid processing (such as looking up the host name). */ if (skipping) return US""; @@ -1424,10 +1438,22 @@ while (last > first) return tod_stamp(tod_log_datestamp); case vtype_reply: /* Get reply address */ - s = find_header(US"reply-to:", exists_only, newsize, FALSE, + s = find_header(US"reply-to:", exists_only, newsize, TRUE, headers_charset); + if (s != NULL) while (isspace(*s)) s++; if (s == NULL || *s == 0) - s = find_header(US"from:", exists_only, newsize, FALSE, headers_charset); + { + *newsize = 0; /* For the *s==0 case */ + s = find_header(US"from:", exists_only, newsize, TRUE, headers_charset); + } + if (s != NULL) + { + uschar *t; + while (isspace(*s)) s++; + for (t = s; *t != 0; t++) if (*t == '\n') *t = ' '; + while (t > s && isspace(t[-1])) t--; + *t = 0; + } return (s == NULL)? US"" : s; /* A recipients list is available only during system message filtering, @@ -1708,7 +1734,7 @@ switch(cond_type) case ECOND_ISIP4: case ECOND_ISIP6: rc = string_is_ip_address(sub[0], NULL); - *yield = ((cond_type == ECOND_ISIP)? (rc > 0) : + *yield = ((cond_type == ECOND_ISIP)? (rc != 0) : (cond_type == ECOND_ISIP4)? (rc == 4) : (rc == 6)) == testfor; break; @@ -1968,7 +1994,7 @@ switch(cond_type) goto MATCHED_SOMETHING; case ECOND_MATCH_IP: /* Match IP address in a host list */ - if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) <= 0) + if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) == 0) { expand_string_message = string_sprintf("\"%s\" is not an IP address", sub[0]); @@ -2746,12 +2772,14 @@ uschar *s = *sptr; int x = eval_term(&s, decimal, error); if (*error == NULL) { - while (*s == '*' || *s == '/') + while (*s == '*' || *s == '/' || *s == '%') { int op = *s++; int y = eval_term(&s, decimal, error); if (*error != NULL) break; - if (op == '*') x *= y; else x /= y; + if (op == '*') x *= y; + else if (op == '/') x /= y; + else x %= y; } } *sptr = s; @@ -3354,15 +3382,24 @@ while (*s != 0) domain = Ustrrchr(sub_arg[0],'@'); if ( (domain == NULL) || (domain == sub_arg[0]) || (Ustrlen(domain) == 1) ) { - expand_string_message = US"first parameter must be a qualified email address"; + expand_string_message = US"prvs first argument must be a qualified email address"; + goto EXPAND_FAILED; + } + + /* Calculate the hash. The second argument must be a single-digit + key number, or unset. */ + + if (sub_arg[2] != NULL && + (!isdigit(sub_arg[2][0]) || sub_arg[2][1] != 0)) + { + expand_string_message = US"prvs second argument must be a single digit"; goto EXPAND_FAILED; } - /* Calculate the hash */ p = prvs_hmac_sha1(sub_arg[0],sub_arg[1],sub_arg[2],prvs_daystamp(7)); if (p == NULL) { - expand_string_message = US"hmac-sha1 conversion failed"; + expand_string_message = US"prvs hmac-sha1 conversion failed"; goto EXPAND_FAILED; } @@ -3389,18 +3426,23 @@ while (*s != 0) int mysize = 0, myptr = 0; const pcre *re; uschar *p; - /* Ugliness: We want to expand parameter 1 first, then set + + /* TF: Ugliness: We want to expand parameter 1 first, then set up expansion variables that are used in the expansion of parameter 2. So we clone the string for the first - expansion, where we only expand paramter 1. */ - uschar *s_backup = string_copy(s); + expansion, where we only expand parameter 1. + + PH: Actually, that isn't necessary. The read_subs() function is + designed to work this way for the ${if and ${lookup expansions. I've + tidied the code. + */ /* Reset expansion variables */ prvscheck_result = NULL; prvscheck_address = NULL; prvscheck_keynum = NULL; - switch(read_subs(sub_arg, 1, 1, &s_backup, skipping, FALSE, US"prvs")) + switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, US"prvs")) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -3410,7 +3452,8 @@ while (*s != 0) re = regex_must_compile(US"^prvs\\=(.+)\\/([0-9])([0-9]{3})([A-F0-9]{6})\\@(.+)$", TRUE,FALSE); - if (regex_match_and_setup(re,sub_arg[0],0,-1)) { + if (regex_match_and_setup(re,sub_arg[0],0,-1)) + { uschar *local_part = string_copyn(expand_nstring[1],expand_nlength[1]); uschar *key_num = string_copyn(expand_nstring[2],expand_nlength[2]); uschar *daystamp = string_copyn(expand_nstring[3],expand_nlength[3]); @@ -3430,21 +3473,19 @@ while (*s != 0) prvscheck_address[myptr] = '\0'; prvscheck_keynum = string_copy(key_num); - /* Now re-expand all arguments in the usual manner */ - switch(read_subs(sub_arg, 3, 3, &s, skipping, TRUE, US"prvs")) + /* Now expand the second argument */ + switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, US"prvs")) { case 1: goto EXPAND_FAILED_CURLY; case 2: case 3: goto EXPAND_FAILED; } - if (*sub_arg[2] == '\0') - yield = string_cat(yield,&size,&ptr,prvscheck_address,Ustrlen(prvscheck_address)); - else - yield = string_cat(yield,&size,&ptr,sub_arg[2],Ustrlen(sub_arg[2])); - /* Now we have the key and can check the address. */ - p = prvs_hmac_sha1(prvscheck_address, sub_arg[1], prvscheck_keynum, daystamp); + + p = prvs_hmac_sha1(prvscheck_address, sub_arg[0], prvscheck_keynum, + daystamp); + if (p == NULL) { expand_string_message = US"hmac-sha1 conversion failed"; @@ -3453,6 +3494,7 @@ while (*s != 0) DEBUG(D_expand) debug_printf("prvscheck: received hash is %s\n", hash); DEBUG(D_expand) debug_printf("prvscheck: own hash is %s\n", p); + if (Ustrcmp(p,hash) == 0) { /* Success, valid BATV address. Now check the expiry date. */ @@ -3482,12 +3524,35 @@ while (*s != 0) prvscheck_result = NULL; DEBUG(D_expand) debug_printf("prvscheck: hash failure, $pvrs_result unset\n"); } - } + + /* Now expand the final argument. We leave this till now so that + it can include $prvscheck_result. */ + + switch(read_subs(sub_arg, 1, 0, &s, skipping, TRUE, US"prvs")) + { + case 1: goto EXPAND_FAILED_CURLY; + case 2: + case 3: goto EXPAND_FAILED; + } + + if (sub_arg[0] == NULL || *sub_arg[0] == '\0') + yield = string_cat(yield,&size,&ptr,prvscheck_address,Ustrlen(prvscheck_address)); + else + yield = string_cat(yield,&size,&ptr,sub_arg[0],Ustrlen(sub_arg[0])); + + /* Reset the "internal" variables afterwards, because they are in + dynamic store that will be reclaimed if the expansion succeeded. */ + + prvscheck_address = NULL; + prvscheck_keynum = NULL; + } else { /* Does not look like a prvs encoded address, return the empty string. - We need to make sure all subs are expanded first. */ - switch(read_subs(sub_arg, 3, 3, &s, skipping, TRUE, US"prvs")) + We need to make sure all subs are expanded first, so as to skip over + the entire item. */ + + switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, US"prvs")) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -4352,6 +4417,8 @@ while (*s != 0) continue; } + /* Note that for Darwin and Cygwin, BASE_62 actually has the value 36 */ + case EOP_BASE62D: { uschar buf[16]; @@ -4363,10 +4430,11 @@ while (*s != 0) if (t == NULL) { expand_string_message = string_sprintf("argument for base62d " - "operator is \"%s\", which is not a base 62 number", sub); + "operator is \"%s\", which is not a base %d number", sub, + BASE_62); goto EXPAND_FAILED; } - n = n * 62 + (t - base62_chars); + n = n * BASE_62 + (t - base62_chars); } (void)sprintf(CS buf, "%ld", n); yield = string_cat(yield, &size, &ptr, buf, Ustrlen(buf));