Coverage Report

Created: 2026-05-16 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-var-expand/var-expand.h
Line
Count
Source
1
#ifndef VAR_EXPAND_NEW_H
2
#define VAR_EXPAND_NEW_H
3
4
/** Variable expansion programs **
5
6
  A variable expansion program is a set of filters delineated with %{},
7
  or a literal-only program which expands to the string it contains.
8
  See https://doc.dovecot.org/latest/core/settings/syntax.html#variable-expansion.
9
10
  The normal usage is to call t_var_expand() to get rendition of a program from
11
  data stack memory, or var_expand() if you want to provide the string yourself.
12
  The string is appended to, or truncated to where it was on starting on failure.
13
14
  If you need to expand the program multiple times, you should use
15
  var_expand_program_create() to create a reusable program chain and then call
16
  var_expand_program_execute() to expand it. Since parameters are given to execute
17
  you can get the same program executed with different parameters, so you don't
18
  have to rebuild the program if your variables are changed.
19
20
  The function var_expand_program_create() parses a string that can contain
21
  one or more programs, and chains them together. This is usually what is wanted.
22
23
  There are some cases though when you need to deal with programs one by one,
24
  and this is handled by 'var-expand-split.h', and there are a few functions here
25
  that do not seem to make much sense alone:
26
27
  The var_expand_program_execute_one() and var_expand_program_has_variable() are
28
  such ones. The execute_one() only makes sense to use with individual programs
29
  that can be extracted with var_expand_program_template() or
30
  var_expand_program_split(), which are in their own header as they have
31
  array.h dependency.
32
33
  The var_expand_program_has_variable() can be used for generic purposes too
34
  by leaving the first_program_only as FALSE.
35
*/
36
37
/* Used for getting either prefix:key values, or dynamic values for keys
38
   in value tables.
39
40
   Gets key and context, needs to return -1 on error (with error_r set)
41
   or 0 on success. value_r *must* be non-null on success.
42
43
   Prefix is removed before calling the function.
44
*/
45
typedef int value_provider_func_t(const char *key, const char **value_r,
46
          void *context, const char **error_r);
47
/* Used for escaping values, gets given string to escape and context,
48
   must return escaped string. */
49
typedef const char *var_expand_escape_func_t(const char *str, void *context);
50
51
struct var_expand_parser_state;
52
struct var_expand_program;
53
54
#define VAR_EXPAND_TABLE_END { .key = NULL }
55
#define VAR_EXPAND_CONTEXTS_END (void*)var_expand_contexts_end
56
57
struct var_expand_table {
58
  /* Key name, as in %{key} */
59
  const char *key;
60
  /* Value to expand into */
61
  const char *value;
62
  /* Or function that provides the value */
63
  value_provider_func_t *func;
64
};
65
66
struct var_expand_provider {
67
  /* key as in %{key:name} */
68
  const char *key;
69
  /* function to call to get value */
70
  value_provider_func_t *func;
71
};
72
73
extern const void *const var_expand_contexts_end;
74
75
struct var_expand_params {
76
  /* Variables to use, must end with VAR_EXPAND_TABLE_END,
77
     asserts that tables_arr is non-NULL. */
78
  const struct var_expand_table *table;
79
  /* Providers to use, must end with VAR_EXPAND_TABLE_END,
80
     asserts that providers_arr is non-NULL. */
81
  const struct var_expand_provider *providers;
82
  /* Multiple var expand tables, must be NULL terminated */
83
  const struct var_expand_table *const *tables_arr;
84
  /* Multiple var expand providers, must be NULL terminated */
85
  const struct var_expand_provider *const *providers_arr;
86
  /* Function that gets called to escape values */
87
  var_expand_escape_func_t *escape_func;
88
  /* Context for escape function */
89
  void *escape_context;
90
  /* Contexts for table functions and providers, can be
91
     set to NULL if no multiple contexts are needed, then context
92
     is defaulted to.
93
94
     Asserts that contexts ends with VAR_EXPAND_CONTEXTS_END.
95
  */
96
  void *const *contexts;
97
  /* Context for table functions and providers. */
98
  void *context;
99
  /* Event for %{event:} expansion, can be NULL. Global event
100
     will be attempted if this is NULL. */
101
  struct event *event;
102
};
103
104
/* Creates a new expansion program for reusing */
105
int var_expand_program_create(const char *str, struct var_expand_program **program_r,
106
            const char **error_r);
107
/* Lists all seen variables in a program */
108
const char *const *var_expand_program_variables(const struct var_expand_program *program);
109
/* Checks if the program has a variable, if first_program_only is set, checks the
110
  first program only, otherwise it checks the variables using var_expand_program_variables().
111
112
  The check is done to all filters and parameters on the first program, so it can detect
113
  if the variable is used anywhere in the program.
114
*/
115
bool var_expand_program_has_variable(const struct var_expand_program *program,
116
             const char *variable, bool first_program_only);
117
/* Dumps the program into a dest for debugging */
118
void var_expand_program_dump(const struct var_expand_program *program, string_t *dest);
119
/* Executes the program with given params. Params can be left NULL, in which case
120
   empty parameters are used. */
121
int var_expand_program_execute(string_t *dest, const struct var_expand_program *program,
122
             const struct var_expand_params *params,
123
             const char **error_r) ATTR_NULL(3);
124
/* Execute the first program only */
125
int var_expand_program_execute_one(string_t *dest, const struct var_expand_program *program,
126
           const struct var_expand_params *params,
127
           const char **error_r);
128
/* Free up program */
129
void var_expand_program_free(struct var_expand_program **_program);
130
131
/* Creates a new program, executes it and frees it. Params can be left NULL, in which
132
   case empty parameters are used. */
133
int var_expand(string_t *dest, const char *str, const struct var_expand_params *params,
134
         const char **error_r) ATTR_NULL(3);
135
136
/* Wrapper for var_expand(), places the result into result_r. */
137
int t_var_expand(const char *str, const struct var_expand_params *params,
138
     const char **result_r, const char **error_r);
139
140
/* Merge two tables together, keys in table a will be overwritten with keys
141
 * from table b in collision. */
142
struct var_expand_table *
143
var_expand_merge_tables(pool_t pool, const struct var_expand_table *a,
144
      const struct var_expand_table *b);
145
146
/* Returns true if provider is a built-in provider */
147
bool var_expand_provider_is_builtin(const char *prefix);
148
149
/* Provides size of a table */
150
static inline size_t ATTR_PURE
151
var_expand_table_size(const struct var_expand_table *table)
152
0
{
153
0
  size_t n = 0;
154
0
  while (table != NULL && table[n].key != NULL)
155
0
     n++;
156
0
  return n;
157
0
}
Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_size
Unexecuted instantiation: expansion-program.c:var_expand_table_size
Unexecuted instantiation: var-expand.c:var_expand_table_size
Unexecuted instantiation: var-expand-parser.c:var_expand_table_size
Unexecuted instantiation: var-expand-lexer.c:var_expand_table_size
Unexecuted instantiation: expansion-parameter.c:var_expand_table_size
Unexecuted instantiation: expansion-statement.c:var_expand_table_size
Unexecuted instantiation: expansion-filter.c:var_expand_table_size
Unexecuted instantiation: expansion-filter-if.c:var_expand_table_size
Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_size
158
159
/* Get table entry by name. Returns NULL if not found. */
160
static inline struct var_expand_table *
161
var_expand_table_get(struct var_expand_table *table, const char *key)
162
0
{
163
0
  for (size_t i = 0; table[i].key != NULL; i++) {
164
0
    if (strcmp(table[i].key, key) == 0) {
165
0
      return &(table[i]);
166
0
    }
167
0
  }
168
0
  return NULL;
169
0
}
Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_get
Unexecuted instantiation: expansion-program.c:var_expand_table_get
Unexecuted instantiation: var-expand.c:var_expand_table_get
Unexecuted instantiation: var-expand-parser.c:var_expand_table_get
Unexecuted instantiation: var-expand-lexer.c:var_expand_table_get
Unexecuted instantiation: expansion-parameter.c:var_expand_table_get
Unexecuted instantiation: expansion-statement.c:var_expand_table_get
Unexecuted instantiation: expansion-filter.c:var_expand_table_get
Unexecuted instantiation: expansion-filter-if.c:var_expand_table_get
Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_get
170
171
/* Set table variable to value. Asserts that key is found. */
172
static inline void var_expand_table_set_value(struct var_expand_table *table,
173
                const char *key, const char *value,
174
                const char *file, unsigned int line)
175
0
{
176
0
  struct var_expand_table *entry = var_expand_table_get(table, key);
177
0
  if (entry != NULL) {
178
0
    i_assert(entry->func == NULL);
179
0
    entry->value = value;
180
0
  } else
181
0
    i_panic("%s:%u No key '%s' in table", file, line, key);
182
0
}
Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_set_value
Unexecuted instantiation: expansion-program.c:var_expand_table_set_value
Unexecuted instantiation: var-expand.c:var_expand_table_set_value
Unexecuted instantiation: var-expand-parser.c:var_expand_table_set_value
Unexecuted instantiation: var-expand-lexer.c:var_expand_table_set_value
Unexecuted instantiation: expansion-parameter.c:var_expand_table_set_value
Unexecuted instantiation: expansion-statement.c:var_expand_table_set_value
Unexecuted instantiation: expansion-filter.c:var_expand_table_set_value
Unexecuted instantiation: expansion-filter-if.c:var_expand_table_set_value
Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_set_value
183
#define var_expand_table_set_value(table, key, value) \
184
  var_expand_table_set_value((table), (key), (value), __FILE__, __LINE__);
185
186
/* Set table variable function. Asserts that key is found. */
187
static inline void var_expand_table_set_func(struct var_expand_table *table,
188
               const char *key,
189
               value_provider_func_t *func,
190
               const char *file, unsigned int line)
191
0
{
192
0
  struct var_expand_table *entry = var_expand_table_get(table, key);
193
0
  if (entry != NULL) {
194
0
    i_assert(entry->value == NULL);
195
0
    entry->func = func;
196
0
  } else
197
0
    i_panic("%s:%u No key '%s' in table", file, line, key);
198
0
}
Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_set_func
Unexecuted instantiation: expansion-program.c:var_expand_table_set_func
Unexecuted instantiation: var-expand.c:var_expand_table_set_func
Unexecuted instantiation: var-expand-parser.c:var_expand_table_set_func
Unexecuted instantiation: var-expand-lexer.c:var_expand_table_set_func
Unexecuted instantiation: expansion-parameter.c:var_expand_table_set_func
Unexecuted instantiation: expansion-statement.c:var_expand_table_set_func
Unexecuted instantiation: expansion-filter.c:var_expand_table_set_func
Unexecuted instantiation: expansion-filter-if.c:var_expand_table_set_func
Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_set_func
199
#define var_expand_table_set_func(table, key, func) \
200
  var_expand_table_set_func((table), (key), (func), __FILE__, __LINE__);
201
202
/* Set key_b variable to key_a. Copies func and value.
203
   Asserts that both are found. */
204
static inline void var_expand_table_copy(struct var_expand_table *table,
205
           const char *key_b, const char *key_a)
206
0
{
207
0
  struct var_expand_table *entry_a = var_expand_table_get(table, key_a);
208
0
  struct var_expand_table *entry_b = var_expand_table_get(table, key_b);
209
0
210
0
  i_assert(entry_a != NULL && entry_b != NULL);
211
0
  entry_b->value = entry_a->value;
212
0
  entry_b->func = entry_a->func;
213
0
}
Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_copy
Unexecuted instantiation: expansion-program.c:var_expand_table_copy
Unexecuted instantiation: var-expand.c:var_expand_table_copy
Unexecuted instantiation: var-expand-parser.c:var_expand_table_copy
Unexecuted instantiation: var-expand-lexer.c:var_expand_table_copy
Unexecuted instantiation: expansion-parameter.c:var_expand_table_copy
Unexecuted instantiation: expansion-statement.c:var_expand_table_copy
Unexecuted instantiation: expansion-filter.c:var_expand_table_copy
Unexecuted instantiation: expansion-filter-if.c:var_expand_table_copy
Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_copy
214
215
/* Export variable expand program to a portable string.
216
217
   Output format is a list of programs. Each program is catenated after
218
   the previous program.
219
   If there is only literal: \x01 <literal>
220
   <literal>: tab-escaped string \r
221
   Otherwise:
222
   <program>: \x02 <function> \x01 <list-of-parameters> \t <list-of-variables> \t
223
   <function>: string
224
   <list-of-parameters>: <parameter> \x01 <parameter> \x01 ..
225
      Note that last parameter has no \x01 at the end.
226
   <parameter>: <key> \x01 <type> <value>
227
   <key>: string
228
   <type>: s = string, i = intmax, v = variable
229
   <value>: <encoded-number> | tab-escaped string \r
230
   <encoded-number>:
231
     The number is expressed in 7-bit bytes and 8th bit indicates the
232
     presence of next byte. The number is in little-endian ordering.
233
   <list-of-variables>: <variable-name> \x01 <variable-name> \x01 ..
234
     Note that last variable has no \x01 at the end.
235
*/
236
237
const char *var_expand_program_export(const struct var_expand_program *program);
238
void var_expand_program_export_append(string_t *dest,
239
              const struct var_expand_program *program);
240
241
/* Reconstruct var_expand program */
242
const char *var_expand_program_to_string_one(const struct var_expand_program *program);
243
const char *var_expand_program_to_string(const struct var_expand_program *program);
244
void var_expand_program_to_string_append_one(string_t *dest,
245
           const struct var_expand_program *program);
246
void var_expand_program_to_string_append(string_t *dest,
247
           const struct var_expand_program *program);
248
249
/* Imports a variable expansion program exported by var_expand_program_export(). */
250
251
int var_expand_program_import(const char *data,
252
            struct var_expand_program **program_r,
253
            const char **error_r);
254
int var_expand_program_import_sized(const char *data, size_t size,
255
            struct var_expand_program **program_r,
256
            const char **error_r);
257
258
void var_expand_crypt_load(void);
259
260
#endif