summaryrefslogtreecommitdiffstats
path: root/src/global/attr_override.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/global/attr_override.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/global/attr_override.c b/src/global/attr_override.c
new file mode 100644
index 0000000..bff2954
--- /dev/null
+++ b/src/global/attr_override.c
@@ -0,0 +1,190 @@
+/*++
+/* NAME
+/* attr_override 3
+/* SUMMARY
+/* apply name=value settings from string
+/* SYNOPSIS
+/* #include <attr_override.h>
+/*
+/* void attr_override(bp, delimiters, parens, ... CA_ATTR_OVER_END);
+/* char *bp;
+/* const char *delimiters;
+/* const char *parens;
+/* DESCRIPTION
+/* This routine updates the values of known in-memory variables
+/* based on the name=value specifications from an input string.
+/* The input format supports parentheses around name=value to
+/* allow whitespace around "=" and within values.
+/*
+/* This may be used, for example, with client endpoint
+/* specifications or with policy tables to allow selective
+/* overrides of global main.cf parameter settings (timeouts,
+/* fall-back policies, etc.).
+/*
+/* Arguments:
+/* .IP bp
+/* Pointer to input string. The input is modified.
+/* .IP "delimiters, parens"
+/* See mystrtok(3) for description. Typical values are
+/* CHARS_COMMA_SP and CHARS_BRACE, respectively.
+/* .PP
+/* The parens argument is followed by a list of macros
+/* with arguments. Each macro may appear only once. The list
+/* must be terminated with CA_ATTR_OVER_END which has no argument.
+/* The following describes the expected values.
+/* .IP "CA_ATTR_OVER_STR_TABLE(const ATTR_OVER_STR *)"
+/* The macro argument specifies a null-terminated table with
+/* attribute names, assignment targets, and range limits which
+/* should be the same as for the corresponding main.cf parameters.
+/* .IP "CA_ATTR_OVER_TIME_TABLE(const ATTR_OVER_TIME *)"
+/* The macro argument specifies a null-terminated table with
+/* attribute names, their default time units (leading digits
+/* are skipped), assignment targets, and range limits which
+/* should be the same as for the corresponding main.cf parameters.
+/* .IP "CA_ATTR_OVER_INT_TABLE(const ATTR_OVER_INT *)"
+/* The macro argument specifies a null-terminated table with
+/* attribute names, assignment targets, and range limits which
+/* should be the same as for the corresponding main.cf parameters.
+/* SEE ALSO
+/* mystrtok(3), safe tokenizer
+/* extpar(3), extract text from parentheses
+/* split_nameval(3), name-value splitter
+/* DIAGNOSTICS
+/* Panic: interface violations.
+/*
+/* Fatal errors: memory allocation problem, syntax error,
+/* out-of-range error.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h> /* strtol() */
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <stringops.h>
+
+ /*
+ * Global library.
+ */
+#include <mail_conf.h>
+#include <conv_time.h>
+#include <attr_override.h>
+
+/* attr_override - apply settings from list of attribute=value pairs */
+
+void attr_override(char *cp, const char *sep, const char *parens,...)
+{
+ static const char myname[] = "attr_override";
+ va_list ap;
+ int idx;
+ char *nameval;
+ const ATTR_OVER_INT *int_table = 0;
+ const ATTR_OVER_STR *str_table = 0;
+ const ATTR_OVER_TIME *time_table = 0;
+
+ /*
+ * Get the lookup tables and assignment targets.
+ */
+ va_start(ap, parens);
+ while ((idx = va_arg(ap, int)) != ATTR_OVER_END) {
+ switch (idx) {
+ case ATTR_OVER_INT_TABLE:
+ if (int_table)
+ msg_panic("%s: multiple ATTR_OVER_INT_TABLE", myname);
+ int_table = va_arg(ap, const ATTR_OVER_INT *);
+ break;
+ case ATTR_OVER_STR_TABLE:
+ if (str_table)
+ msg_panic("%s: multiple ATTR_OVER_STR_TABLE", myname);
+ str_table = va_arg(ap, const ATTR_OVER_STR *);
+ break;
+ case ATTR_OVER_TIME_TABLE:
+ if (time_table)
+ msg_panic("%s: multiple ATTR_OVER_TIME_TABLE", myname);
+ time_table = va_arg(ap, const ATTR_OVER_TIME *);
+ break;
+ default:
+ msg_panic("%s: unknown argument type: %d", myname, idx);
+ }
+ }
+ va_end(ap);
+
+ /*
+ * Process each attribute=value override in the input string.
+ */
+ while ((nameval = mystrtokq(&cp, sep, parens)) != 0) {
+ int found = 0;
+ char *key;
+ char *value;
+ const char *err;
+ const ATTR_OVER_INT *ip;
+ const ATTR_OVER_STR *sp;
+ const ATTR_OVER_TIME *tp;
+ int int_val;
+ int def_unit;
+ char *end;
+ long longval;
+
+ /*
+ * Split into name and value.
+ */
+ /* { name = value } */
+ if (*nameval == parens[0]
+ && (err = extpar(&nameval, parens, EXTPAR_FLAG_NONE)) != 0)
+ msg_fatal("%s in \"%s\"", err, nameval);
+ if ((err = split_nameval(nameval, &key, &value)) != 0)
+ msg_fatal("malformed option: %s: \"...%s...\"", err, nameval);
+
+ /*
+ * Look up the name and apply the value.
+ */
+ for (sp = str_table; sp != 0 && found == 0 && sp->name != 0; sp++) {
+ if (strcmp(sp->name, key) != 0)
+ continue;
+ check_mail_conf_str(sp->name, value, sp->min, sp->max);
+ sp->target[0] = value;
+ found = 1;
+ }
+ for (ip = int_table; ip != 0 && found == 0 && ip->name != 0; ip++) {
+ if (strcmp(ip->name, key) != 0)
+ continue;
+ /* XXX Duplicated from mail_conf_int(3). */
+ errno = 0;
+ int_val = longval = strtol(value, &end, 10);
+ if (*value == 0 || *end != 0 || errno == ERANGE
+ || longval != int_val)
+ msg_fatal("bad numerical configuration: %s = %s", key, value);
+ check_mail_conf_int(key, int_val, ip->min, ip->max);
+ ip->target[0] = int_val;
+ found = 1;
+ }
+ for (tp = time_table; tp != 0 && found == 0 && tp->name != 0; tp++) {
+ if (strcmp(tp->name, key) != 0)
+ continue;
+ def_unit = tp->defval[strspn(tp->defval, "0123456789")];
+ if (conv_time(value, &int_val, def_unit) == 0)
+ msg_fatal("%s: bad time value or unit: %s", key, value);
+ check_mail_conf_time(key, int_val, tp->min, tp->max);
+ tp->target[0] = int_val;
+ found = 1;
+ }
+ if (found == 0)
+ msg_fatal("unknown option: \"%s = %s\"", key, value);
+ }
+}