/*++ /* NAME /* attr_override 3 /* SUMMARY /* apply name=value settings from string /* SYNOPSIS /* #include /* /* 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 #include #include #include /* strtol() */ /* * Utility library. */ #include #include /* * Global library. */ #include #include #include /* 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); } }