1 /* $NetBSD: attr_override.c,v 1.2 2017/02/14 01:16:45 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* attr_override 3 6 /* SUMMARY 7 /* apply name=value settings from string 8 /* SYNOPSIS 9 /* #include <attr_override.h> 10 /* 11 /* void attr_override(bp, delimiters, parens, ... CA_ATTR_OVER_END); 12 /* char *bp; 13 /* const char *delimiters; 14 /* const char *parens; 15 /* DESCRIPTION 16 /* This routine updates the values of known in-memory variables 17 /* based on the name=value specifications from an input string. 18 /* The input format supports parentheses around name=value to 19 /* allow whitespace around "=" and within values. 20 /* 21 /* This may be used, for example, with client endpoint 22 /* specifications or with policy tables to allow selective 23 /* overrides of global main.cf parameter settings (timeouts, 24 /* fall-back policies, etc.). 25 /* 26 /* Arguments: 27 /* .IP bp 28 /* Pointer to input string. The input is modified. 29 /* .IP "delimiters, parens" 30 /* See mystrtok(3) for description. Typical values are 31 /* CHARS_COMMA_SP and CHARS_BRACE, respectively. 32 /* .PP 33 /* The parens argument is followed by a list of macros 34 /* with arguments. Each macro may appear only once. The list 35 /* must be terminated with CA_ATTR_OVER_END which has no argument. 36 /* The following describes the expected values. 37 /* .IP "CA_ATTR_OVER_STR_TABLE(const ATTR_OVER_STR *)" 38 /* The macro argument specifies a null-terminated table with 39 /* attribute names, assignment targets, and range limits which 40 /* should be the same as for the corresponding main.cf parameters. 41 /* .IP "CA_ATTR_OVER_TIME_TABLE(const ATTR_OVER_TIME *)" 42 /* The macro argument specifies a null-terminated table with 43 /* attribute names, their default time units (leading digits 44 /* are skipped), assignment targets, and range limits which 45 /* should be the same as for the corresponding main.cf parameters. 46 /* .IP "CA_ATTR_OVER_INT_TABLE(const ATTR_OVER_INT *)" 47 /* The macro argument specifies a null-terminated table with 48 /* attribute names, assignment targets, and range limits which 49 /* should be the same as for the corresponding main.cf parameters. 50 /* SEE ALSO 51 /* mystrtok(3), safe tokenizer 52 /* extpar(3), extract text from parentheses 53 /* split_nameval(3), name-value splitter 54 /* DIAGNOSTICS 55 /* Panic: interface violations. 56 /* 57 /* Fatal errors: memory allocation problem, syntax error, 58 /* out-of-range error. 59 /* LICENSE 60 /* .ad 61 /* .fi 62 /* The Secure Mailer license must be distributed with this software. 63 /* AUTHOR(S) 64 /* Wietse Venema 65 /* IBM T.J. Watson Research 66 /* P.O. Box 704 67 /* Yorktown Heights, NY 10598, USA 68 /*--*/ 69 70 /* 71 * System library. 72 */ 73 #include <sys_defs.h> 74 #include <errno.h> 75 #include <string.h> 76 #include <stdlib.h> /* strtol() */ 77 78 /* 79 * Utility library. 80 */ 81 #include <msg.h> 82 #include <stringops.h> 83 84 /* 85 * Global library. 86 */ 87 #include <mail_conf.h> 88 #include <conv_time.h> 89 #include <attr_override.h> 90 91 /* attr_override - apply settings from list of attribute=value pairs */ 92 93 void attr_override(char *cp, const char *sep, const char *parens,...) 94 { 95 static const char myname[] = "attr_override"; 96 va_list ap; 97 int idx; 98 char *nameval; 99 const ATTR_OVER_INT *int_table = 0; 100 const ATTR_OVER_STR *str_table = 0; 101 const ATTR_OVER_TIME *time_table = 0; 102 103 /* 104 * Get the lookup tables and assignment targets. 105 */ 106 va_start(ap, parens); 107 while ((idx = va_arg(ap, int)) != ATTR_OVER_END) { 108 switch (idx) { 109 case ATTR_OVER_INT_TABLE: 110 if (int_table) 111 msg_panic("%s: multiple ATTR_OVER_INT_TABLE", myname); 112 int_table = va_arg(ap, const ATTR_OVER_INT *); 113 break; 114 case ATTR_OVER_STR_TABLE: 115 if (str_table) 116 msg_panic("%s: multiple ATTR_OVER_STR_TABLE", myname); 117 str_table = va_arg(ap, const ATTR_OVER_STR *); 118 break; 119 case ATTR_OVER_TIME_TABLE: 120 if (time_table) 121 msg_panic("%s: multiple ATTR_OVER_TIME_TABLE", myname); 122 time_table = va_arg(ap, const ATTR_OVER_TIME *); 123 break; 124 default: 125 msg_panic("%s: unknown argument type: %d", myname, idx); 126 } 127 } 128 va_end(ap); 129 130 /* 131 * Process each attribute=value override in the input string. 132 */ 133 while ((nameval = mystrtokq(&cp, sep, parens)) != 0) { 134 int found = 0; 135 char *key; 136 char *value; 137 const char *err; 138 const ATTR_OVER_INT *ip; 139 const ATTR_OVER_STR *sp; 140 const ATTR_OVER_TIME *tp; 141 int int_val; 142 int def_unit; 143 char *end; 144 long longval; 145 146 /* 147 * Split into name and value. 148 */ 149 /* { name = value } */ 150 if (*nameval == parens[0] 151 && (err = extpar(&nameval, parens, EXTPAR_FLAG_NONE)) != 0) 152 msg_fatal("%s in \"%s\"", err, nameval); 153 if ((err = split_nameval(nameval, &key, &value)) != 0) 154 msg_fatal("malformed option: %s: \"...%s...\"", err, nameval); 155 156 /* 157 * Look up the name and apply the value. 158 */ 159 for (sp = str_table; sp != 0 && found == 0 && sp->name != 0; sp++) { 160 if (strcmp(sp->name, key) != 0) 161 continue; 162 check_mail_conf_str(sp->name, value, sp->min, sp->max); 163 sp->target[0] = value; 164 found = 1; 165 } 166 for (ip = int_table; ip != 0 && found == 0 && ip->name != 0; ip++) { 167 if (strcmp(ip->name, key) != 0) 168 continue; 169 /* XXX Duplicated from mail_conf_int(3). */ 170 errno = 0; 171 int_val = longval = strtol(value, &end, 10); 172 if (*value == 0 || *end != 0 || errno == ERANGE 173 || longval != int_val) 174 msg_fatal("bad numerical configuration: %s = %s", key, value); 175 check_mail_conf_int(key, int_val, ip->min, ip->max); 176 ip->target[0] = int_val; 177 found = 1; 178 } 179 for (tp = time_table; tp != 0 && found == 0 && tp->name != 0; tp++) { 180 if (strcmp(tp->name, key) != 0) 181 continue; 182 def_unit = tp->defval[strspn(tp->defval, "0123456789")]; 183 if (conv_time(value, &int_val, def_unit) == 0) 184 msg_fatal("%s: bad time value or unit: %s", key, value); 185 check_mail_conf_time(key, int_val, tp->min, tp->max); 186 tp->target[0] = int_val; 187 found = 1; 188 } 189 if (found == 0) 190 msg_fatal("unknown option: \"%s = %s\"", key, value); 191 } 192 } 193