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