xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/attr_override.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
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