/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-only */
/* Code for handling Access Control Lists (ACLs) */
}
+static BOOL
+acl_varname_to_cond(const uschar ** sp, acl_condition_block * cond, uschar ** error)
+{
+const uschar * s = *sp, * endptr;
+
+#ifndef DISABLE_DKIM
+if ( Ustrncmp(s, "dkim_verify_status", 18) == 0
+ || Ustrncmp(s, "dkim_verify_reason", 18) == 0)
+ {
+ endptr = s+18;
+ if (isalnum(*endptr))
+ {
+ *error = string_sprintf("invalid variable name after \"set\" in ACL "
+ "modifier \"set %s\" "
+ "(only \"dkim_verify_status\" or \"dkim_verify_reason\" permitted)",
+ s);
+ return FALSE;
+ }
+ cond->u.varname = string_copyn(s, 18);
+ }
+else
+#endif
+ {
+ if (Ustrncmp(s, "acl_c", 5) != 0 && Ustrncmp(s, "acl_m", 5) != 0)
+ {
+ *error = string_sprintf("invalid variable name after \"set\" in ACL "
+ "modifier \"set %s\" (must start \"acl_c\" or \"acl_m\")", s);
+ return FALSE;
+ }
+
+ endptr = s + 5;
+ if (!isdigit(*endptr) && *endptr != '_')
+ {
+ *error = string_sprintf("invalid variable name after \"set\" in ACL "
+ "modifier \"set %s\" (digit or underscore must follow acl_c or acl_m)",
+ s);
+ return FALSE;
+ }
+
+ for ( ; *endptr && *endptr != '=' && !isspace(*endptr); endptr++)
+ if (!isalnum(*endptr) && *endptr != '_')
+ {
+ *error = string_sprintf("invalid character \"%c\" in variable name "
+ "in ACL modifier \"set %s\"", *endptr, s);
+ return FALSE;
+ }
+
+ cond->u.varname = string_copyn(s + 4, endptr - s - 4);
+ }
+s = endptr;
+Uskip_whitespace(&s);
+*sp = s;
+return TRUE;
+}
+
+
+static BOOL
+acl_data_to_cond(const uschar * s, acl_condition_block * cond,
+ const uschar * name, uschar ** error)
+{
+if (*s++ != '=')
+ {
+ *error = string_sprintf("\"=\" missing after ACL \"%s\" %s", name,
+ conditions[cond->type].is_modifier ? US"modifier" : US"condition");
+ return FALSE;;
+ }
+Uskip_whitespace(&s);
+cond->arg = string_copy(s);
+return TRUE;
+}
+
+
/*************************************************
* Read and parse one ACL *
*************************************************/
acl_block *this = NULL;
acl_condition_block *cond;
acl_condition_block **condp = NULL;
-uschar * s;
+const uschar * s;
*error = NULL;
{
int v, c;
BOOL negated = FALSE;
- uschar *saveline = s;
+ const uschar * saveline = s;
uschar name[EXIM_DRIVERNAME_MAX];
/* Conditions (but not verbs) are allowed to be negated by an initial
*error = string_sprintf("malformed ACL line \"%s\"", saveline);
return NULL;
}
- this = store_get(sizeof(acl_block), GET_UNTAINTED);
- *lastp = this;
- lastp = &(this->next);
+ *lastp = this = store_get(sizeof(acl_block), GET_UNTAINTED);
+ lastp = &this->next;
this->next = NULL;
this->condition = NULL;
this->verb = v;
this->srcline = config_lineno; /* for debug output */
this->srcfile = config_filename; /**/
- condp = &(this->condition);
- if (*s == 0) continue; /* No condition on this line */
+ condp = &this->condition;
+ if (!*s) continue; /* No condition on this line */
if (*s == '!')
{
negated = TRUE;
cond->u.negated = negated;
*condp = cond;
- condp = &(cond->next);
+ condp = &cond->next;
/* The "set" modifier is different in that its argument is "name=value"
rather than just a value, and we can check the validity of the name, which
compatibility. */
if (c == ACLC_SET)
-#ifndef DISABLE_DKIM
- if ( Ustrncmp(s, "dkim_verify_status", 18) == 0
- || Ustrncmp(s, "dkim_verify_reason", 18) == 0)
- {
- uschar * endptr = s+18;
-
- if (isalnum(*endptr))
- {
- *error = string_sprintf("invalid variable name after \"set\" in ACL "
- "modifier \"set %s\" "
- "(only \"dkim_verify_status\" or \"dkim_verify_reason\" permitted)",
- s);
- return NULL;
- }
- cond->u.varname = string_copyn(s, 18);
- s = endptr;
- Uskip_whitespace(&s);
- }
- else
-#endif
- {
- uschar *endptr;
-
- if (Ustrncmp(s, "acl_c", 5) != 0 && Ustrncmp(s, "acl_m", 5) != 0)
- {
- *error = string_sprintf("invalid variable name after \"set\" in ACL "
- "modifier \"set %s\" (must start \"acl_c\" or \"acl_m\")", s);
- return NULL;
- }
-
- endptr = s + 5;
- if (!isdigit(*endptr) && *endptr != '_')
- {
- *error = string_sprintf("invalid variable name after \"set\" in ACL "
- "modifier \"set %s\" (digit or underscore must follow acl_c or acl_m)",
- s);
- return NULL;
- }
-
- while (*endptr && *endptr != '=' && !isspace(*endptr))
- {
- if (!isalnum(*endptr) && *endptr != '_')
- {
- *error = string_sprintf("invalid character \"%c\" in variable name "
- "in ACL modifier \"set %s\"", *endptr, s);
- return NULL;
- }
- endptr++;
- }
-
- cond->u.varname = string_copyn(s + 4, endptr - s - 4);
- s = endptr;
- Uskip_whitespace(&s);
- }
+ if (!acl_varname_to_cond(&s, cond, error)) return NULL;
/* For "set", we are now positioned for the data. For the others, only
"endpass" has no data */
if (c != ACLC_ENDPASS)
- {
- if (*s++ != '=')
- {
- *error = string_sprintf("\"=\" missing after ACL \"%s\" %s", name,
- conditions[c].is_modifier ? US"modifier" : US"condition");
- return NULL;
- }
- Uskip_whitespace(&s);
- cond->arg = string_copy(s);
- }
+ if (!acl_data_to_cond(s, cond, name, error)) return NULL;
}
return yield;
address_item *addr, int level, BOOL *epp, uschar **user_msgptr,
uschar **log_msgptr, int *basic_errno)
{
-uschar *user_message = NULL;
-uschar *log_message = NULL;
+uschar * user_message = NULL;
+uschar * log_message = NULL;
int rc = OK;
-#ifdef WITH_CONTENT_SCAN
-int sep = -'/';
-#endif
for (; cb; cb = cb->next)
{
break;
}
- #ifdef EXPERIMENTAL_DCC
+#ifdef EXPERIMENTAL_DCC
case ACLC_DCC:
{
/* Separate the regular expression and any optional parameters. */
const uschar * list = arg;
- uschar *ss = string_nextinlist(&list, &sep, NULL, 0);
+ int sep = -'/';
+ uschar * ss = string_nextinlist(&list, &sep, NULL, 0);
/* Run the dcc backend. */
rc = dcc_process(&ss);
/* Modify return code based upon the existence of options. */
rc = FAIL; /* FAIL so that the message is passed to the next ACL */
break;
}
- #endif
+#endif
- #ifdef WITH_CONTENT_SCAN
+#ifdef WITH_CONTENT_SCAN
case ACLC_DECODE:
rc = mime_decode(&arg);
break;
- #endif
+#endif
case ACLC_DELAY:
{
case ACLC_LOG_REJECT_TARGET:
{
- int logbits = 0;
- int sep = 0;
- const uschar *s = arg;
- uschar * ss;
- while ((ss = string_nextinlist(&s, &sep, NULL, 0)))
+ int logbits = 0, sep = 0;
+ const uschar * s = arg;
+
+ for (uschar * ss; ss = string_nextinlist(&s, &sep, NULL, 0); )
{
if (Ustrcmp(ss, "main") == 0) logbits |= LOG_MAIN;
else if (Ustrcmp(ss, "panic") == 0) logbits |= LOG_PANIC;
break;
}
- #ifdef WITH_CONTENT_SCAN
+#ifdef WITH_CONTENT_SCAN
case ACLC_MALWARE: /* Run the malware backend. */
{
/* Separate the regular expression and any optional parameters. */
const uschar * list = arg;
- uschar * ss = string_nextinlist(&list, &sep, NULL, 0);
- uschar * opt;
BOOL defer_ok = FALSE;
- int timeout = 0;
+ int timeout = 0, sep = -'/';
+ uschar * ss = string_nextinlist(&list, &sep, NULL, 0);
- while ((opt = string_nextinlist(&list, &sep, NULL, 0)))
+ for (uschar * opt; opt = string_nextinlist(&list, &sep, NULL, 0); )
if (strcmpic(opt, US"defer_ok") == 0)
defer_ok = TRUE;
else if ( strncmpic(opt, US"tmo=", 4) == 0
case ACLC_MIME_REGEX:
rc = mime_regex(&arg, textonly);
break;
- #endif
+#endif
case ACLC_QUEUE:
if (is_tainted(arg))
{
/* Separate the regular expression and any optional parameters. */
const uschar * list = arg;
- uschar *ss = string_nextinlist(&list, &sep, NULL, 0);
+ int sep = -'/';
+ uschar * ss = string_nextinlist(&list, &sep, NULL, 0);
rc = spam(CUSS &ss);
/* Modify return code based upon the existence of options. */
fprintf(f, "acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
}
+
+
+
+uschar *
+acl_standalone_setvar(const uschar * s)
+{
+acl_condition_block * cond = store_get(sizeof(acl_condition_block), GET_UNTAINTED);
+uschar * errstr = NULL, * log_msg = NULL;
+BOOL endpass_seen;
+int e;
+
+cond->next = NULL;
+cond->type = ACLC_SET;
+if (!acl_varname_to_cond(&s, cond, &errstr)) return errstr;
+if (!acl_data_to_cond(s, cond, US"'-be'", &errstr)) return errstr;
+
+if (acl_check_condition(ACL_WARN, cond, ACL_WHERE_UNKNOWN,
+ NULL, 0, &endpass_seen, &errstr, &log_msg, &e) != OK)
+ return string_sprintf("oops: %s", errstr);
+return string_sprintf("variable %s set", cond->u.varname);
+}
+
+
#endif /* !MACRO_PREDEF */
/* vi: aw ai sw=2
*/