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
attr_override(char * cp,const char * sep,const char * parens,...)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