Coverage Report

Created: 2026-04-03 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/cfgparse.c
Line
Count
Source
1
/*
2
 * Configuration parser
3
 *
4
 * Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version
9
 * 2 of the License, or (at your option) any later version.
10
 *
11
 */
12
13
/* This is to have crypt() and sched_setaffinity() defined on Linux */
14
#define _GNU_SOURCE
15
16
#ifdef USE_LIBCRYPT
17
#ifdef USE_CRYPT_H
18
/* some platforms such as Solaris need this */
19
#include <crypt.h>
20
#endif
21
#endif /* USE_LIBCRYPT */
22
23
#include <dirent.h>
24
#include <stdio.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <netdb.h>
28
#include <ctype.h>
29
#include <pwd.h>
30
#include <grp.h>
31
#include <errno.h>
32
#ifdef USE_CPU_AFFINITY
33
#include <sched.h>
34
#endif
35
#include <sys/types.h>
36
#include <sys/stat.h>
37
#include <unistd.h>
38
39
#include <import/cebis_tree.h>
40
41
#include <haproxy/acl.h>
42
#include <haproxy/action.h>
43
#include <haproxy/api.h>
44
#include <haproxy/arg.h>
45
#include <haproxy/auth.h>
46
#include <haproxy/backend.h>
47
#include <haproxy/capture.h>
48
#include <haproxy/cfgcond.h>
49
#include <haproxy/cfgparse.h>
50
#include <haproxy/channel.h>
51
#include <haproxy/check.h>
52
#include <haproxy/chunk.h>
53
#include <haproxy/clock.h>
54
#include <haproxy/counters.h>
55
#ifdef USE_CPU_AFFINITY
56
#include <haproxy/cpuset.h>
57
#include <haproxy/cpu_topo.h>
58
#endif
59
#include <haproxy/connection.h>
60
#include <haproxy/errors.h>
61
#include <haproxy/filters.h>
62
#include <haproxy/frontend.h>
63
#include <haproxy/global.h>
64
#include <haproxy/http_ana.h>
65
#include <haproxy/http_rules.h>
66
#include <haproxy/http_htx.h>
67
#include <haproxy/lb_chash.h>
68
#include <haproxy/lb_fas.h>
69
#include <haproxy/lb_fwlc.h>
70
#include <haproxy/lb_fwrr.h>
71
#include <haproxy/lb_map.h>
72
#include <haproxy/lb_ss.h>
73
#include <haproxy/listener.h>
74
#include <haproxy/log.h>
75
#include <haproxy/sink.h>
76
#include <haproxy/mailers.h>
77
#include <haproxy/namespace.h>
78
#include <haproxy/quic_cc-t.h>
79
#include <haproxy/quic_sock.h>
80
#include <haproxy/quic_tune.h>
81
#include <haproxy/obj_type-t.h>
82
#include <haproxy/openssl-compat.h>
83
#include <haproxy/peers-t.h>
84
#include <haproxy/peers.h>
85
#include <haproxy/pool.h>
86
#include <haproxy/protocol.h>
87
#include <haproxy/proxy.h>
88
#include <haproxy/resolvers.h>
89
#include <haproxy/sample.h>
90
#include <haproxy/server.h>
91
#include <haproxy/session.h>
92
#include <haproxy/stick_table.h>
93
#include <haproxy/stream.h>
94
#include <haproxy/task.h>
95
#include <haproxy/tcp_rules.h>
96
#include <haproxy/tcpcheck.h>
97
#include <haproxy/thread.h>
98
#include <haproxy/tools.h>
99
#include <haproxy/uri_auth.h>
100
101
102
/* Used to chain configuration sections definitions. This list
103
 * stores struct cfg_section
104
 */
105
struct list sections = LIST_HEAD_INIT(sections);
106
107
struct list postparsers = LIST_HEAD_INIT(postparsers);
108
109
extern struct proxy *mworker_proxy;
110
111
/* curproxy is only valid during parsing and will be NULL afterwards. */
112
struct proxy *curproxy = NULL;
113
/* last defaults section parsed, NULL after parsing */
114
struct proxy *last_defproxy = NULL;
115
116
char *cursection = NULL;
117
int cfg_maxpconn = 0;                   /* # of simultaneous connections per proxy (-N) */
118
int cfg_maxconn = 0;      /* # of simultaneous connections, (-n) */
119
char *cfg_scope = NULL;                 /* the current scope during the configuration parsing */
120
int non_global_section_parsed = 0;
121
122
/* how to handle default paths */
123
static enum default_path_mode {
124
  DEFAULT_PATH_CURRENT = 0,  /* "current": paths are relative to CWD (this is the default) */
125
  DEFAULT_PATH_CONFIG,       /* "config": paths are relative to config file */
126
  DEFAULT_PATH_PARENT,       /* "parent": paths are relative to config file's ".." */
127
  DEFAULT_PATH_ORIGIN,       /* "origin": paths are relative to default_path_origin */
128
} default_path_mode;
129
130
char initial_cwd[PATH_MAX];
131
static char current_cwd[PATH_MAX];
132
133
/* List head of all known configuration keywords */
134
struct cfg_kw_list cfg_keywords = {
135
  .list = LIST_HEAD_INIT(cfg_keywords.list)
136
};
137
138
/*
139
 * Shifts <args> one position to the left.
140
 * This function tricky preserves internal allocated structure of the
141
 * <args>. We defer the deallocation of the "shifted off" element, by
142
 * making it an empty string and moving it into the gap that appears after
143
 * the shift.
144
 */
145
static void
146
lshift_args(char **args)
147
2.23k
{
148
2.23k
  int i;
149
2.23k
  char *shifted;
150
151
2.23k
  shifted = args[0];
152
5.28k
  for (i = 0; *args[i + 1]; i++)
153
3.04k
    args[i] = args[i + 1];
154
2.23k
  *shifted = '\0';
155
2.23k
  args[i] = shifted;
156
2.23k
}
157
158
/*
159
 * converts <str> to a list of listeners which are dynamically allocated.
160
 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
161
 *  - <addr> can be empty or "*" to indicate INADDR_ANY ;
162
 *  - <port> is a numerical port from 1 to 65535 ;
163
 *  - <end> indicates to use the range from <port> to <end> instead (inclusive).
164
 * This can be repeated as many times as necessary, separated by a coma.
165
 * Function returns 1 for success or 0 if error. In case of errors, if <err> is
166
 * not NULL, it must be a valid pointer to either NULL or a freeable area that
167
 * will be replaced with an error message.
168
 */
169
int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, const char *file, int line, char **err)
170
0
{
171
0
  struct protocol *proto;
172
0
  char *next, *dupstr;
173
0
  int port, end;
174
175
0
  next = dupstr = strdup(str);
176
177
0
  while (next && *next) {
178
0
    struct sockaddr_storage *ss2;
179
0
    int fd = -1;
180
181
0
    str = next;
182
    /* 1) look for the end of the first address */
183
0
    if ((next = strchr(str, ',')) != NULL) {
184
0
      *next++ = 0;
185
0
    }
186
187
0
    ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, NULL, err,
188
0
                       (curproxy == global.cli_fe || curproxy == mworker_proxy) ? NULL : global.unix_bind.prefix,
189
0
                       NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_PORT_RANGE |
190
0
                              PA_O_SOCKET_FD | PA_O_STREAM | PA_O_XPRT);
191
0
    if (!ss2)
192
0
      goto fail;
193
194
0
    if (ss2->ss_family == AF_CUST_RHTTP_SRV) {
195
      /* Check if a previous non reverse HTTP present is
196
       * already defined. If DGRAM or STREAM is set, this
197
       * indicates that we are currently parsing the second
198
       * or more address.
199
       */
200
0
      if (bind_conf->options & (BC_O_USE_SOCK_DGRAM|BC_O_USE_SOCK_STREAM) &&
201
0
          !(bind_conf->options & BC_O_REVERSE_HTTP)) {
202
0
        memprintf(err, "Cannot mix reverse HTTP bind with others.\n");
203
0
        goto fail;
204
0
      }
205
206
0
      bind_conf->rhttp_srvname = strdup(str + strlen("rhttp@"));
207
0
      if (!bind_conf->rhttp_srvname) {
208
0
        memprintf(err, "Cannot allocate reverse HTTP bind.\n");
209
0
        goto fail;
210
0
      }
211
212
0
      bind_conf->options |= BC_O_REVERSE_HTTP;
213
0
    }
214
0
    else if (bind_conf->options & BC_O_REVERSE_HTTP) {
215
      /* Standard address mixed with a previous reverse HTTP one. */
216
0
      memprintf(err, "Cannot mix reverse HTTP bind with others.\n");
217
0
      goto fail;
218
0
    }
219
220
    /* OK the address looks correct */
221
0
    if (proto->proto_type == PROTO_TYPE_DGRAM)
222
0
      bind_conf->options |= BC_O_USE_SOCK_DGRAM;
223
0
    else
224
0
      bind_conf->options |= BC_O_USE_SOCK_STREAM;
225
226
0
    if (proto->xprt_type == PROTO_TYPE_DGRAM)
227
0
      bind_conf->options |= BC_O_USE_XPRT_DGRAM;
228
0
    else
229
0
      bind_conf->options |= BC_O_USE_XPRT_STREAM;
230
231
0
    if (!create_listeners(bind_conf, ss2, port, end, fd, proto, err)) {
232
0
      memprintf(err, "%s for address '%s'.\n", *err, str);
233
0
      goto fail;
234
0
    }
235
0
  } /* end while(next) */
236
0
  free(dupstr);
237
0
  return 1;
238
0
 fail:
239
0
  free(dupstr);
240
0
  return 0;
241
0
}
242
243
/*
244
 * converts <str> to a list of datagram-oriented listeners which are dynamically
245
 * allocated.
246
 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
247
 *  - <addr> can be empty or "*" to indicate INADDR_ANY ;
248
 *  - <port> is a numerical port from 1 to 65535 ;
249
 *  - <end> indicates to use the range from <port> to <end> instead (inclusive).
250
 * This can be repeated as many times as necessary, separated by a coma.
251
 * Function returns 1 for success or 0 if error. In case of errors, if <err> is
252
 * not NULL, it must be a valid pointer to either NULL or a freeable area that
253
 * will be replaced with an error message.
254
 */
255
int str2receiver(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, const char *file, int line, char **err)
256
0
{
257
0
  struct protocol *proto;
258
0
  char *next, *dupstr;
259
0
  int port, end;
260
261
0
  next = dupstr = strdup(str);
262
263
0
  while (next && *next) {
264
0
    struct sockaddr_storage *ss2;
265
0
    int fd = -1;
266
267
0
    str = next;
268
    /* 1) look for the end of the first address */
269
0
    if ((next = strchr(str, ',')) != NULL) {
270
0
      *next++ = 0;
271
0
    }
272
273
0
    ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, NULL, err,
274
0
                       curproxy == global.cli_fe ? NULL : global.unix_bind.prefix,
275
0
                       NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_PORT_RANGE |
276
0
                              PA_O_SOCKET_FD | PA_O_DGRAM | PA_O_XPRT);
277
0
    if (!ss2)
278
0
      goto fail;
279
280
    /* OK the address looks correct */
281
0
    if (!create_listeners(bind_conf, ss2, port, end, fd, proto, err)) {
282
0
      memprintf(err, "%s for address '%s'.\n", *err, str);
283
0
      goto fail;
284
0
    }
285
0
  } /* end while(next) */
286
0
  free(dupstr);
287
0
  return 1;
288
0
 fail:
289
0
  free(dupstr);
290
0
  return 0;
291
0
}
292
293
/*
294
 * Sends a warning if proxy <proxy> does not have at least one of the
295
 * capabilities in <cap>. An optional <hint> may be added at the end
296
 * of the warning to help the user. Returns 1 if a warning was emitted
297
 * or 0 if the condition is valid.
298
 */
299
int warnifnotcap(struct proxy *proxy, int cap, const char *file, int line, const char *arg, const char *hint)
300
0
{
301
0
  char *msg;
302
303
0
  switch (cap) {
304
0
  case PR_CAP_BE: msg = "no backend"; break;
305
0
  case PR_CAP_FE: msg = "no frontend"; break;
306
0
  case PR_CAP_BE|PR_CAP_FE: msg = "neither frontend nor backend"; break;
307
0
  default: msg = "not enough"; break;
308
0
  }
309
310
0
  if (!(proxy->cap & cap)) {
311
0
    ha_warning("parsing [%s:%d] : '%s' ignored because %s '%s' has %s capability.%s\n",
312
0
         file, line, arg, proxy_type_str(proxy), proxy->id, msg, hint ? hint : "");
313
0
    return 1;
314
0
  }
315
0
  return 0;
316
0
}
317
318
/*
319
 * Sends an alert if proxy <proxy> does not have at least one of the
320
 * capabilities in <cap>. An optional <hint> may be added at the end
321
 * of the alert to help the user. Returns 1 if an alert was emitted
322
 * or 0 if the condition is valid.
323
 */
324
int failifnotcap(struct proxy *proxy, int cap, const char *file, int line, const char *arg, const char *hint)
325
0
{
326
0
  char *msg;
327
328
0
  switch (cap) {
329
0
  case PR_CAP_BE: msg = "no backend"; break;
330
0
  case PR_CAP_FE: msg = "no frontend"; break;
331
0
  case PR_CAP_BE|PR_CAP_FE: msg = "neither frontend nor backend"; break;
332
0
  default: msg = "not enough"; break;
333
0
  }
334
335
0
  if (!(proxy->cap & cap)) {
336
0
    ha_alert("parsing [%s:%d] : '%s' not allowed because %s '%s' has %s capability.%s\n",
337
0
       file, line, arg, proxy_type_str(proxy), proxy->id, msg, hint ? hint : "");
338
0
    return 1;
339
0
  }
340
0
  return 0;
341
0
}
342
343
/*
344
 * Report an error in <msg> when there are too many arguments. This version is
345
 * intended to be used by keyword parsers so that the message will be included
346
 * into the general error message. The index is the current keyword in args.
347
 * Return 0 if the number of argument is correct, otherwise build a message and
348
 * return 1. Fill err_code with an ERR_ALERT and an ERR_FATAL if not null. The
349
 * message may also be null, it will simply not be produced (useful to check only).
350
 * <msg> and <err_code> are only affected on error.
351
 */
352
int too_many_args_idx(int maxarg, int index, char **args, char **msg, int *err_code)
353
0
{
354
0
  int i;
355
356
0
  if (!*args[index + maxarg + 1])
357
0
    return 0;
358
359
0
  if (msg) {
360
0
    *msg = NULL;
361
0
    memprintf(msg, "%s", args[0]);
362
0
    for (i = 1; i <= index; i++)
363
0
      memprintf(msg, "%s %s", *msg, args[i]);
364
365
0
    memprintf(msg, "'%s' cannot handle unexpected argument '%s'.", *msg, args[index + maxarg + 1]);
366
0
  }
367
0
  if (err_code)
368
0
    *err_code |= ERR_ALERT | ERR_FATAL;
369
370
0
  return 1;
371
0
}
372
373
/*
374
 * same as too_many_args_idx with a 0 index
375
 */
376
int too_many_args(int maxarg, char **args, char **msg, int *err_code)
377
0
{
378
0
  return too_many_args_idx(maxarg, 0, args, msg, err_code);
379
0
}
380
381
/*
382
 * Report a fatal Alert when there is too much arguments
383
 * The index is the current keyword in args
384
 * Return 0 if the number of argument is correct, otherwise emit an alert and return 1
385
 * Fill err_code with an ERR_ALERT and an ERR_FATAL
386
 */
387
int alertif_too_many_args_idx(int maxarg, int index, const char *file, int linenum, char **args, int *err_code)
388
0
{
389
0
  char *kw = NULL;
390
0
  int i;
391
392
0
  if (!*args[index + maxarg + 1])
393
0
    return 0;
394
395
0
  memprintf(&kw, "%s", args[0]);
396
0
  for (i = 1; i <= index; i++) {
397
0
    memprintf(&kw, "%s %s", kw, args[i]);
398
0
  }
399
400
0
  ha_alert("parsing [%s:%d] : '%s' cannot handle unexpected argument '%s'.\n", file, linenum, kw, args[index + maxarg + 1]);
401
0
  free(kw);
402
0
  *err_code |= ERR_ALERT | ERR_FATAL;
403
0
  return 1;
404
0
}
405
406
/*
407
 * same as alertif_too_many_args_idx with a 0 index
408
 */
409
int alertif_too_many_args(int maxarg, const char *file, int linenum, char **args, int *err_code)
410
0
{
411
0
  return alertif_too_many_args_idx(maxarg, 0, file, linenum, args, err_code);
412
0
}
413
414
415
/* Report it if a request ACL condition uses some keywords that are
416
 * incompatible with the place where the ACL is used. It returns either 0 or
417
 * ERR_WARN so that its result can be or'ed with err_code. Note that <cond> may
418
 * be NULL and then will be ignored. In case of error, <err> is dynamically
419
 * allocated to contains a description.
420
 */
421
int warnif_cond_conflicts(const struct acl_cond *cond, unsigned int where,
422
                          char **err)
423
0
{
424
0
  const struct acl *acl;
425
0
  const char *kw;
426
427
0
  if (!cond)
428
0
    return 0;
429
430
0
  acl = acl_cond_conflicts(cond, where);
431
0
  if (acl) {
432
0
    if (acl->name && *acl->name) {
433
0
      memprintf(err, "acl '%s' will never match because it only involves keywords that are incompatible with '%s'",
434
0
                acl->name, sample_ckp_names(where));
435
0
    }
436
0
    else {
437
0
      memprintf(err, "anonymous acl will never match because it uses keyword '%s' which is incompatible with '%s'",
438
0
                LIST_ELEM(acl->expr.n, struct acl_expr *, list)->kw, sample_ckp_names(where));
439
0
    }
440
0
    return ERR_WARN;
441
0
  }
442
0
  if (!acl_cond_kw_conflicts(cond, where, &acl, &kw))
443
0
    return 0;
444
445
0
  if (acl->name && *acl->name) {
446
0
    memprintf(err, "acl '%s' involves keywords '%s' which is incompatible with '%s'",
447
0
              acl->name, kw, sample_ckp_names(where));
448
0
  }
449
0
  else {
450
0
    memprintf(err, "anonymous acl involves keyword '%s' which is incompatible with '%s'",
451
0
              kw, sample_ckp_names(where));
452
0
  }
453
0
  return ERR_WARN;
454
0
}
455
456
/* Report it if an ACL uses a L6 sample fetch from an HTTP proxy.  It returns
457
 * either 0 or ERR_WARN so that its result can be or'ed with err_code. Note that
458
 * <cond> may be NULL and then will be ignored.
459
*/
460
int warnif_tcp_http_cond(const struct proxy *px, const struct acl_cond *cond)
461
0
{
462
0
  if (!cond || px->mode != PR_MODE_HTTP)
463
0
    return 0;
464
465
0
  if (cond->use & (SMP_USE_L6REQ|SMP_USE_L6RES)) {
466
0
    ha_warning("Proxy '%s': L6 sample fetches ignored on HTTP proxies (declared at %s:%d).\n",
467
0
         px->id, cond->file, cond->line);
468
0
    return ERR_WARN;
469
0
  }
470
0
  return 0;
471
0
}
472
473
/* try to find in <list> the word that looks closest to <word> by counting
474
 * transitions between letters, digits and other characters. Will return the
475
 * best matching word if found, otherwise NULL. An optional array of extra
476
 * words to compare may be passed in <extra>, but it must then be terminated
477
 * by a NULL entry. If unused it may be NULL.
478
 */
479
const char *cfg_find_best_match(const char *word, const struct list *list, int section, const char **extra)
480
0
{
481
0
  uint8_t word_sig[1024]; // 0..25=letter, 26=digit, 27=other, 28=begin, 29=end
482
0
  uint8_t list_sig[1024];
483
0
  const struct cfg_kw_list *kwl;
484
0
  int index;
485
0
  const char *best_ptr = NULL;
486
0
  int dist, best_dist = INT_MAX;
487
488
0
  make_word_fingerprint(word_sig, word);
489
0
  list_for_each_entry(kwl, list, list) {
490
0
    for (index = 0; kwl->kw[index].kw != NULL; index++) {
491
0
      if (kwl->kw[index].section != section)
492
0
        continue;
493
494
0
      make_word_fingerprint(list_sig, kwl->kw[index].kw);
495
0
      dist = word_fingerprint_distance(word_sig, list_sig);
496
0
      if (dist < best_dist) {
497
0
        best_dist = dist;
498
0
        best_ptr = kwl->kw[index].kw;
499
0
      }
500
0
    }
501
0
  }
502
503
0
  while (extra && *extra) {
504
0
    make_word_fingerprint(list_sig, *extra);
505
0
    dist = word_fingerprint_distance(word_sig, list_sig);
506
0
    if (dist < best_dist) {
507
0
      best_dist = dist;
508
0
      best_ptr = *extra;
509
0
    }
510
0
    extra++;
511
0
  }
512
513
0
  if (best_dist > 2 * strlen(word) || (best_ptr && best_dist > 2 * strlen(best_ptr)))
514
0
    best_ptr = NULL;
515
0
  return best_ptr;
516
0
}
517
518
/* Parse a string representing a process number or a set of processes. It must
519
 * be "all", "odd", "even", a number between 1 and <max> or a range with
520
 * two such numbers delimited by a dash ('-'). On success, it returns
521
 * 0. otherwise it returns 1 with an error message in <err>.
522
 *
523
 * Note: this function can also be used to parse a thread number or a set of
524
 * threads.
525
 */
526
int parse_process_number(const char *arg, unsigned long *proc, int max, int *autoinc, char **err)
527
0
{
528
0
  if (autoinc) {
529
0
    *autoinc = 0;
530
0
    if (strncmp(arg, "auto:", 5) == 0) {
531
0
      arg += 5;
532
0
      *autoinc = 1;
533
0
    }
534
0
  }
535
536
0
  if (strcmp(arg, "all") == 0)
537
0
    *proc |= ~0UL;
538
0
  else if (strcmp(arg, "odd") == 0)
539
0
    *proc |= ~0UL/3UL; /* 0x555....555 */
540
0
  else if (strcmp(arg, "even") == 0)
541
0
    *proc |= (~0UL/3UL) << 1; /* 0xAAA...AAA */
542
0
  else {
543
0
    const char *p, *dash = NULL;
544
0
    unsigned int low, high;
545
546
0
    for (p = arg; *p; p++) {
547
0
      if (*p == '-' && !dash)
548
0
        dash = p;
549
0
      else if (!isdigit((unsigned char)*p)) {
550
0
        memprintf(err, "'%s' is not a valid number/range.", arg);
551
0
        return -1;
552
0
      }
553
0
    }
554
555
0
    low = high = str2uic(arg);
556
0
    if (dash)
557
0
      high = ((!*(dash+1)) ? max : str2uic(dash + 1));
558
559
0
    if (high < low) {
560
0
      unsigned int swap = low;
561
0
      low  = high;
562
0
      high = swap;
563
0
    }
564
565
0
    if (low < 1 || low > max || high > max) {
566
0
      memprintf(err, "'%s' is not a valid number/range."
567
0
          " It supports numbers from 1 to %d.\n",
568
0
          arg, max);
569
0
      return 1;
570
0
    }
571
572
0
    for (;low <= high; low++)
573
0
      *proc |= 1UL << (low-1);
574
0
  }
575
0
  *proc &= ~0UL >> (LONGBITS - max);
576
577
0
  return 0;
578
0
}
579
580
/*
581
 * Parse a line in a <listen>, <frontend> or <backend> section.
582
 * Returns the error code, 0 if OK, or any combination of :
583
 *  - ERR_ABORT: must abort ASAP
584
 *  - ERR_FATAL: we can continue parsing but not start the service
585
 *  - ERR_WARN: a warning has been emitted
586
 *  - ERR_ALERT: an alert has been emitted
587
 * Only the two first ones can stop processing, the two others are just
588
 * indicators.
589
 */
590
int cfg_parse_mailers(const char *file, int linenum, char **args, int kwm)
591
0
{
592
0
  static struct mailers *curmailers = NULL;
593
0
  struct mailer *newmailer = NULL;
594
0
  const char *err;
595
0
  int err_code = 0;
596
0
  char *errmsg = NULL;
597
598
0
  if (strcmp(args[0], "mailers") == 0) { /* new mailers section */
599
0
    if (!*args[1]) {
600
0
      ha_alert("parsing [%s:%d] : missing name for mailers section.\n", file, linenum);
601
0
      err_code |= ERR_ALERT | ERR_ABORT;
602
0
      goto out;
603
0
    }
604
605
0
    err = invalid_char(args[1]);
606
0
    if (err) {
607
0
      ha_alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n",
608
0
         file, linenum, *err, args[0], args[1]);
609
0
      err_code |= ERR_ALERT | ERR_ABORT;
610
0
      goto out;
611
0
    }
612
613
0
    for (curmailers = mailers; curmailers != NULL; curmailers = curmailers->next) {
614
      /*
615
       * If there are two proxies with the same name only following
616
       * combinations are allowed:
617
       */
618
0
      if (strcmp(curmailers->id, args[1]) == 0) {
619
0
        ha_alert("Parsing [%s:%d]: mailers section '%s' has the same name as another mailers section declared at %s:%d.\n",
620
0
           file, linenum, args[1], curmailers->conf.file, curmailers->conf.line);
621
0
        err_code |= ERR_ALERT | ERR_FATAL;
622
0
      }
623
0
    }
624
625
0
    if ((curmailers = calloc(1, sizeof(*curmailers))) == NULL) {
626
0
      ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
627
0
      err_code |= ERR_ALERT | ERR_ABORT;
628
0
      goto out;
629
0
    }
630
631
0
    curmailers->next = mailers;
632
0
    mailers = curmailers;
633
0
    curmailers->conf.file = strdup(file);
634
0
    curmailers->conf.line = linenum;
635
0
    curmailers->id = strdup(args[1]);
636
0
    curmailers->timeout.mail = DEF_MAILALERTTIME;/* XXX: Would like to Skip to the next alert, if any, ASAP.
637
      * But need enough time so that timeouts don't occur
638
      * during tcp procssing. For now just us an arbitrary default. */
639
0
  }
640
0
  else if (strcmp(args[0], "mailer") == 0) { /* mailer definition */
641
0
    struct sockaddr_storage *sk;
642
0
    int port1, port2;
643
0
    struct protocol *proto;
644
645
0
    if (!*args[2]) {
646
0
      ha_alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
647
0
         file, linenum, args[0]);
648
0
      err_code |= ERR_ALERT | ERR_FATAL;
649
0
      goto out;
650
0
    }
651
652
0
    err = invalid_char(args[1]);
653
0
    if (err) {
654
0
      ha_alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
655
0
         file, linenum, *err, args[1]);
656
0
      err_code |= ERR_ALERT | ERR_FATAL;
657
0
      goto out;
658
0
    }
659
660
0
    if ((newmailer = calloc(1, sizeof(*newmailer))) == NULL) {
661
0
      ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
662
0
      err_code |= ERR_ALERT | ERR_ABORT;
663
0
      goto out;
664
0
    }
665
666
    /* the mailers are linked backwards first */
667
0
    curmailers->count++;
668
0
    newmailer->next = curmailers->mailer_list;
669
0
    curmailers->mailer_list = newmailer;
670
0
    newmailer->mailers = curmailers;
671
0
    newmailer->conf.file = strdup(file);
672
0
    newmailer->conf.line = linenum;
673
674
0
    newmailer->id = strdup(args[1]);
675
676
0
    sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, &proto, NULL,
677
0
                      &errmsg, NULL, NULL, NULL,
678
0
                      PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT);
679
0
    if (!sk) {
680
0
      ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
681
0
      err_code |= ERR_ALERT | ERR_FATAL;
682
0
      goto out;
683
0
    }
684
685
0
    if (proto->sock_prot != IPPROTO_TCP) {
686
0
      ha_alert("parsing [%s:%d] : '%s %s' : TCP not supported for this address family.\n",
687
0
         file, linenum, args[0], args[1]);
688
0
      err_code |= ERR_ALERT | ERR_FATAL;
689
0
      goto out;
690
0
    }
691
692
0
    newmailer->addr = *sk;
693
0
    newmailer->proto = proto;
694
0
    newmailer->xprt  = xprt_get(XPRT_RAW);
695
0
    newmailer->sock_init_arg = NULL;
696
0
  }
697
0
  else if (strcmp(args[0], "timeout") == 0) {
698
0
    if (!*args[1]) {
699
0
      ha_alert("parsing [%s:%d] : '%s' expects 'mail' and <time> as arguments.\n",
700
0
         file, linenum, args[0]);
701
0
      err_code |= ERR_ALERT | ERR_FATAL;
702
0
      goto out;
703
0
    }
704
0
    else if (strcmp(args[1], "mail") == 0) {
705
0
      const char *res;
706
0
      unsigned int timeout_mail;
707
0
      if (!*args[2]) {
708
0
        ha_alert("parsing [%s:%d] : '%s %s' expects <time> as argument.\n",
709
0
           file, linenum, args[0], args[1]);
710
0
        err_code |= ERR_ALERT | ERR_FATAL;
711
0
        goto out;
712
0
      }
713
0
      res = parse_time_err(args[2], &timeout_mail, TIME_UNIT_MS);
714
0
      if (res == PARSE_TIME_OVER) {
715
0
        ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s %s>, maximum value is 2147483647 ms (~24.8 days).\n",
716
0
           file, linenum, args[2], args[0], args[1]);
717
0
        err_code |= ERR_ALERT | ERR_FATAL;
718
0
        goto out;
719
0
      }
720
0
      else if (res == PARSE_TIME_UNDER) {
721
0
        ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s %s>, minimum non-null value is 1 ms.\n",
722
0
           file, linenum, args[2], args[0], args[1]);
723
0
        err_code |= ERR_ALERT | ERR_FATAL;
724
0
        goto out;
725
0
      }
726
0
      else if (res) {
727
0
        ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n",
728
0
           file, linenum, *res, args[0], args[1]);
729
0
        err_code |= ERR_ALERT | ERR_FATAL;
730
0
        goto out;
731
0
      }
732
0
      curmailers->timeout.mail = timeout_mail;
733
0
    } else {
734
0
      ha_alert("parsing [%s:%d] : '%s' expects 'mail' and <time> as arguments got '%s'.\n",
735
0
        file, linenum, args[0], args[1]);
736
0
      err_code |= ERR_ALERT | ERR_FATAL;
737
0
      goto out;
738
0
    }
739
0
  }
740
0
  else if (*args[0] != 0) {
741
0
    ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
742
0
    err_code |= ERR_ALERT | ERR_FATAL;
743
0
    goto out;
744
0
  }
745
746
0
out:
747
0
  free(errmsg);
748
0
  return err_code;
749
0
}
750
751
752
int
753
cfg_parse_netns(const char *file, int linenum, char **args, int kwm)
754
0
{
755
#ifdef USE_NS
756
  const char *err;
757
  const char *item = args[0];
758
759
  if (strcmp(item, "namespace_list") == 0) {
760
    return 0;
761
  }
762
  else if (strcmp(item, "namespace") == 0) {
763
    size_t idx = 1;
764
    const char *current;
765
    while (*(current = args[idx++])) {
766
      err = invalid_char(current);
767
      if (err) {
768
        ha_alert("parsing [%s:%d]: character '%c' is not permitted in '%s' name '%s'.\n",
769
           file, linenum, *err, item, current);
770
        return ERR_ALERT | ERR_FATAL;
771
      }
772
773
      if (netns_store_lookup(current, strlen(current))) {
774
        ha_alert("parsing [%s:%d]: Namespace '%s' is already added.\n",
775
           file, linenum, current);
776
        return ERR_ALERT | ERR_FATAL;
777
      }
778
      if (!netns_store_insert(current)) {
779
        ha_alert("parsing [%s:%d]: Cannot open namespace '%s'.\n",
780
           file, linenum, current);
781
        return ERR_ALERT | ERR_FATAL;
782
      }
783
    }
784
  }
785
786
  return 0;
787
#else
788
0
  ha_alert("parsing [%s:%d]: namespace support is not compiled in.",
789
0
     file, linenum);
790
0
  return ERR_ALERT | ERR_FATAL;
791
0
#endif
792
0
}
793
794
int
795
cfg_parse_users(const char *file, int linenum, char **args, int kwm)
796
0
{
797
798
0
  int err_code = 0;
799
0
  const char *err;
800
801
0
  if (strcmp(args[0], "userlist") == 0) {   /* new userlist */
802
0
    struct userlist *newul;
803
804
0
    if (!*args[1]) {
805
0
      ha_alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
806
0
         file, linenum, args[0]);
807
0
      err_code |= ERR_ALERT | ERR_FATAL;
808
0
      goto out;
809
0
    }
810
0
    if (alertif_too_many_args(1, file, linenum, args, &err_code))
811
0
      goto out;
812
813
0
    err = invalid_char(args[1]);
814
0
    if (err) {
815
0
      ha_alert("parsing [%s:%d]: character '%c' is not permitted in '%s' name '%s'.\n",
816
0
         file, linenum, *err, args[0], args[1]);
817
0
      err_code |= ERR_ALERT | ERR_FATAL;
818
0
      goto out;
819
0
    }
820
821
0
    for (newul = userlist; newul; newul = newul->next)
822
0
      if (strcmp(newul->name, args[1]) == 0) {
823
0
        ha_warning("parsing [%s:%d]: ignoring duplicated userlist '%s'.\n",
824
0
             file, linenum, args[1]);
825
0
        err_code |= ERR_WARN;
826
0
        goto out;
827
0
      }
828
829
0
    newul = calloc(1, sizeof(*newul));
830
0
    if (!newul) {
831
0
      ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
832
0
      err_code |= ERR_ALERT | ERR_ABORT;
833
0
      goto out;
834
0
    }
835
836
0
    newul->name = strdup(args[1]);
837
0
    if (!newul->name) {
838
0
      ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
839
0
      err_code |= ERR_ALERT | ERR_ABORT;
840
0
      free(newul);
841
0
      goto out;
842
0
    }
843
844
0
    newul->next = userlist;
845
0
    userlist = newul;
846
847
0
  } else {
848
0
    const struct cfg_kw_list *kwl;
849
0
    char *errmsg = NULL;
850
0
    int index;
851
852
0
    list_for_each_entry(kwl, &cfg_keywords.list, list) {
853
0
      for (index = 0; kwl->kw[index].kw; index++) {
854
0
        if ((kwl->kw[index].section & CFG_USERLIST) &&
855
0
          (strcmp(kwl->kw[index].kw, args[0]) == 0)) {
856
0
            err_code |= kwl->kw[index].parse(args, CFG_USERLIST, NULL, NULL, file, linenum, &errmsg);
857
0
            if (errmsg) {
858
0
              ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
859
0
              ha_free(&errmsg);
860
0
            }
861
0
            goto out;
862
0
          }
863
0
      }
864
0
    }
865
866
0
    ha_alert("parsing [%s:%d]: unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "userlist");
867
0
    err_code |= ERR_ALERT | ERR_FATAL;
868
0
  }
869
870
0
out:
871
0
  return err_code;
872
0
}
873
874
int cfg_parse_users_group(char **args, int section_type, struct proxy *curproxy, const struct proxy *defproxy, const char *file, int linenum, char **err)
875
0
{
876
0
  int cur_arg;
877
0
  const char *err_str;
878
0
  struct auth_groups *ag;
879
0
  int err_code = 0;
880
881
0
  if (!*args[1]) {
882
0
    ha_alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
883
0
        file, linenum, args[0]);
884
0
    err_code |= ERR_ALERT | ERR_FATAL;
885
0
    goto out;
886
0
  }
887
888
0
  err_str = invalid_char(args[1]);
889
0
  if (err_str) {
890
0
    ha_alert("parsing [%s:%d]: character '%c' is not permitted in '%s' name '%s'.\n",
891
0
        file, linenum, *err_str, args[0], args[1]);
892
0
    err_code |= ERR_ALERT | ERR_FATAL;
893
0
    goto out;
894
0
  }
895
896
0
  if (!userlist)
897
0
    goto out;
898
899
0
  for (ag = userlist->groups; ag; ag = ag->next)
900
0
    if (strcmp(ag->name, args[1]) == 0) {
901
0
      ha_warning("parsing [%s:%d]: ignoring duplicated group '%s' in userlist '%s'.\n",
902
0
          file, linenum, args[1], userlist->name);
903
0
      err_code |= ERR_ALERT;
904
0
      goto out;
905
0
    }
906
907
0
  ag = calloc(1, sizeof(*ag));
908
0
  if (!ag) {
909
0
    ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
910
0
    err_code |= ERR_ALERT | ERR_ABORT;
911
0
    goto out;
912
0
  }
913
914
0
  ag->name = strdup(args[1]);
915
0
  if (!ag->name) {
916
0
    ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
917
0
    err_code |= ERR_ALERT | ERR_ABORT;
918
0
    free(ag);
919
0
    goto out;
920
0
  }
921
922
0
  cur_arg = 2;
923
924
0
  while (*args[cur_arg]) {
925
0
    if (strcmp(args[cur_arg], "users") == 0) {
926
0
      if (ag->groupusers) {
927
0
        ha_alert("parsing [%s:%d]: 'users' option already defined in '%s' name '%s'.\n",
928
0
            file, linenum, args[0], args[1]);
929
0
        err_code |= ERR_ALERT | ERR_FATAL;
930
0
        free(ag->groupusers);
931
0
        free(ag->name);
932
0
        free(ag);
933
0
        goto out;
934
0
      }
935
0
      ag->groupusers = strdup(args[cur_arg + 1]);
936
0
      cur_arg += 2;
937
0
      continue;
938
0
    } else {
939
0
      ha_alert("parsing [%s:%d]: '%s' only supports 'users' option.\n",
940
0
          file, linenum, args[0]);
941
0
      err_code |= ERR_ALERT | ERR_FATAL;
942
0
      free(ag->groupusers);
943
0
      free(ag->name);
944
0
      free(ag);
945
0
      goto out;
946
0
    }
947
0
  }
948
949
0
  ag->next = userlist->groups;
950
0
  userlist->groups = ag;
951
952
0
out:
953
0
  return err_code;
954
0
}
955
956
int cfg_parse_users_user(char **args, int section_type, struct proxy *curproxy, const struct proxy *defproxy, const char *file, int linenum, char **err)
957
0
{
958
0
  struct auth_users *newuser;
959
0
  int cur_arg;
960
0
  int err_code = 0;
961
962
0
  if (!*args[1]) {
963
0
    ha_alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
964
0
       file, linenum, args[0]);
965
0
    err_code |= ERR_ALERT | ERR_FATAL;
966
0
    goto out;
967
0
  }
968
0
  if (!userlist)
969
0
    goto out;
970
971
0
  for (newuser = userlist->users; newuser; newuser = newuser->next)
972
0
    if (strcmp(newuser->user, args[1]) == 0) {
973
0
      ha_warning("parsing [%s:%d]: ignoring duplicated user '%s' in userlist '%s'.\n",
974
0
           file, linenum, args[1], userlist->name);
975
0
      err_code |= ERR_ALERT;
976
0
      goto out;
977
0
    }
978
979
0
  newuser = calloc(1, sizeof(*newuser));
980
0
  if (!newuser) {
981
0
    ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
982
0
    err_code |= ERR_ALERT | ERR_ABORT;
983
0
    goto out;
984
0
  }
985
986
0
  newuser->user = strdup(args[1]);
987
988
0
  newuser->next = userlist->users;
989
0
  userlist->users = newuser;
990
991
0
  cur_arg = 2;
992
993
0
  while (*args[cur_arg]) {
994
0
    if (strcmp(args[cur_arg], "password") == 0) {
995
#ifdef USE_LIBCRYPT
996
      struct timeval tv_before, tv_after;
997
      ulong ms_elapsed;
998
999
      gettimeofday(&tv_before, NULL);
1000
      if (!crypt("", args[cur_arg + 1])) {
1001
        ha_alert("parsing [%s:%d]: the encrypted password used for user '%s' is not supported by crypt(3).\n",
1002
           file, linenum, newuser->user);
1003
        err_code |= ERR_ALERT | ERR_FATAL;
1004
        goto out;
1005
      }
1006
      gettimeofday(&tv_after, NULL);
1007
      ms_elapsed = tv_ms_elapsed(&tv_before, &tv_after);
1008
      if (ms_elapsed >= 10) {
1009
        ha_warning("parsing [%s:%d]: the hash algorithm used for this password takes %lu milliseconds to verify, which can have devastating performance and stability impacts. Please hash this password using a lighter algorithm (one that is compatible with web usage).\n", file, linenum, ms_elapsed);
1010
        err_code |= ERR_WARN;
1011
      }
1012
#else
1013
0
      ha_warning("parsing [%s:%d]: no crypt(3) support compiled, encrypted passwords will not work.\n",
1014
0
           file, linenum);
1015
0
      err_code |= ERR_ALERT;
1016
0
#endif
1017
0
      newuser->pass = strdup(args[cur_arg + 1]);
1018
0
      cur_arg += 2;
1019
0
      continue;
1020
0
    } else if (strcmp(args[cur_arg], "insecure-password") == 0) {
1021
0
      newuser->pass = strdup(args[cur_arg + 1]);
1022
0
      newuser->flags |= AU_O_INSECURE;
1023
0
      cur_arg += 2;
1024
0
      continue;
1025
0
    } else if (strcmp(args[cur_arg], "groups") == 0) {
1026
0
      newuser->u.groups_names = strdup(args[cur_arg + 1]);
1027
0
      cur_arg += 2;
1028
0
      continue;
1029
0
    } else {
1030
0
      ha_alert("parsing [%s:%d]: '%s' only supports 'password', 'insecure-password' and 'groups' options.\n",
1031
0
         file, linenum, args[0]);
1032
0
      err_code |= ERR_ALERT | ERR_FATAL;
1033
0
      goto out;
1034
0
    }
1035
0
  }
1036
1037
0
out:
1038
0
  return err_code;
1039
0
}
1040
1041
int
1042
cfg_parse_scope(const char *file, int linenum, char *line)
1043
3.52k
{
1044
3.52k
  char *beg, *end, *scope = NULL;
1045
3.52k
  int err_code = 0;
1046
3.52k
  const char *err;
1047
1048
3.52k
  beg = line + 1;
1049
3.52k
  end = strchr(beg, ']');
1050
1051
  /* Detect end of scope declaration */
1052
3.52k
  if (!end || end == beg) {
1053
1.79k
    ha_alert("parsing [%s:%d] : empty scope name is forbidden.\n",
1054
1.79k
       file, linenum);
1055
1.79k
    err_code |= ERR_ALERT | ERR_FATAL;
1056
1.79k
    goto out;
1057
1.79k
  }
1058
1059
  /* Get scope name and check its validity */
1060
1.73k
  scope = my_strndup(beg, end-beg);
1061
1.73k
  err = invalid_char(scope);
1062
1.73k
  if (err) {
1063
740
    ha_alert("parsing [%s:%d] : character '%c' is not permitted in a scope name.\n",
1064
740
       file, linenum, *err);
1065
740
    err_code |= ERR_ALERT | ERR_ABORT;
1066
740
    goto out;
1067
740
  }
1068
1069
  /* Be sure to have a scope declaration alone on its line */
1070
995
  line = end+1;
1071
995
  while (isspace((unsigned char)*line))
1072
246
    line++;
1073
995
  if (*line && *line != '#' && *line != '\n' && *line != '\r') {
1074
346
    ha_alert("parsing [%s:%d] : character '%c' is not permitted after scope declaration.\n",
1075
346
       file, linenum, *line);
1076
346
    err_code |= ERR_ALERT | ERR_ABORT;
1077
346
    goto out;
1078
346
  }
1079
1080
  /* We have a valid scope declaration, save it */
1081
649
  free(cfg_scope);
1082
649
  cfg_scope = scope;
1083
649
  scope = NULL;
1084
1085
3.52k
  out:
1086
3.52k
  free(scope);
1087
3.52k
  return err_code;
1088
649
}
1089
1090
int
1091
cfg_parse_track_sc_num(unsigned int *track_sc_num,
1092
                       const char *arg, const char *end, char **errmsg)
1093
0
{
1094
0
  const char *p;
1095
0
  unsigned int num;
1096
1097
0
  p = arg;
1098
0
  num = read_uint64(&arg, end);
1099
1100
0
  if (arg != end) {
1101
0
    memprintf(errmsg, "Wrong track-sc number '%s'", p);
1102
0
    return -1;
1103
0
  }
1104
1105
0
  if (num >= global.tune.nb_stk_ctr) {
1106
0
    if (!global.tune.nb_stk_ctr)
1107
0
      memprintf(errmsg, "%u track-sc number not usable, stick-counters "
1108
0
                "are disabled by tune.stick-counters", num);
1109
0
    else
1110
0
      memprintf(errmsg, "%u track-sc number exceeding "
1111
0
                "%d (tune.stick-counters-1) value", num, global.tune.nb_stk_ctr - 1);
1112
0
    return -1;
1113
0
  }
1114
1115
0
  *track_sc_num = num;
1116
0
  return 0;
1117
0
}
1118
1119
/*
1120
 * Detect a global section after a non-global one and output a diagnostic
1121
 * warning.
1122
 */
1123
static void check_section_position(char *section_name, const char *file, int linenum)
1124
0
{
1125
0
  if (strcmp(section_name, "global") == 0) {
1126
0
    if ((global.mode & MODE_DIAG) && non_global_section_parsed == 1)
1127
0
            _ha_diag_warning("parsing [%s:%d] : global section detected after a non-global one, the prevalence of their statements is unspecified\n", file, linenum);
1128
0
  }
1129
0
  else if (non_global_section_parsed == 0) {
1130
0
    non_global_section_parsed = 1;
1131
0
  }
1132
0
}
1133
1134
/* apply the current default_path setting for config file <file>, and
1135
 * optionally replace the current path to <origin> if not NULL while the
1136
 * default-path mode is set to "origin". Errors are returned into an
1137
 * allocated string passed to <err> if it's not NULL. Returns 0 on failure
1138
 * or non-zero on success.
1139
 */
1140
static int cfg_apply_default_path(const char *file, const char *origin, char **err)
1141
2.69k
{
1142
2.69k
  const char *beg, *end;
1143
1144
  /* make path start at <beg> and end before <end>, and switch it to ""
1145
   * if no slash was passed.
1146
   */
1147
2.69k
  beg = file;
1148
2.69k
  end = strrchr(beg, '/');
1149
2.69k
  if (!end)
1150
2.69k
    end = beg;
1151
1152
2.69k
  if (!*initial_cwd) {
1153
1
    if (getcwd(initial_cwd, sizeof(initial_cwd)) == NULL) {
1154
0
      if (err)
1155
0
        memprintf(err, "Impossible to retrieve startup directory name: %s", strerror(errno));
1156
0
      return 0;
1157
0
    }
1158
1
  }
1159
2.69k
  else if (chdir(initial_cwd) == -1) {
1160
0
    if (err)
1161
0
      memprintf(err, "Impossible to get back to initial directory '%s': %s", initial_cwd, strerror(errno));
1162
0
    return 0;
1163
0
  }
1164
1165
  /* OK now we're (back) to initial_cwd */
1166
1167
2.69k
  switch (default_path_mode) {
1168
2.69k
  case DEFAULT_PATH_CURRENT:
1169
    /* current_cwd never set, nothing to do */
1170
2.69k
    return 1;
1171
1172
0
  case DEFAULT_PATH_ORIGIN:
1173
    /* current_cwd set in the config */
1174
0
    if (origin &&
1175
0
        snprintf(current_cwd, sizeof(current_cwd), "%s", origin) > sizeof(current_cwd)) {
1176
0
      if (err)
1177
0
        memprintf(err, "Absolute path too long: '%s'", origin);
1178
0
      return 0;
1179
0
    }
1180
0
    break;
1181
1182
0
  case DEFAULT_PATH_CONFIG:
1183
0
    if (end - beg >= sizeof(current_cwd)) {
1184
0
      if (err)
1185
0
        memprintf(err, "Config file path too long, cannot use for relative paths: '%s'", file);
1186
0
      return 0;
1187
0
    }
1188
0
    memcpy(current_cwd, beg, end - beg);
1189
0
    current_cwd[end - beg] = 0;
1190
0
    break;
1191
1192
0
  case DEFAULT_PATH_PARENT:
1193
0
    if (end - beg + 3 >= sizeof(current_cwd)) {
1194
0
      if (err)
1195
0
        memprintf(err, "Config file path too long, cannot use for relative paths: '%s'", file);
1196
0
      return 0;
1197
0
    }
1198
0
    memcpy(current_cwd, beg, end - beg);
1199
0
    if (end > beg)
1200
0
      memcpy(current_cwd + (end - beg), "/..\0", 4);
1201
0
    else
1202
0
      memcpy(current_cwd + (end - beg), "..\0", 3);
1203
0
    break;
1204
2.69k
  }
1205
1206
0
  if (*current_cwd && chdir(current_cwd) == -1) {
1207
0
    if (err)
1208
0
      memprintf(err, "Impossible to get back to directory '%s': %s", initial_cwd, strerror(errno));
1209
0
    return 0;
1210
0
  }
1211
1212
0
  return 1;
1213
0
}
1214
1215
/* parses a global "default-path" directive. */
1216
static int cfg_parse_global_def_path(char **args, int section_type, struct proxy *curpx,
1217
                                     const struct proxy *defpx, const char *file, int line,
1218
                                     char **err)
1219
0
{
1220
0
  int ret = -1;
1221
1222
  /* "current", "config", "parent", "origin <path>" */
1223
1224
0
  if (strcmp(args[1], "current") == 0)
1225
0
    default_path_mode = DEFAULT_PATH_CURRENT;
1226
0
  else if (strcmp(args[1], "config") == 0)
1227
0
    default_path_mode = DEFAULT_PATH_CONFIG;
1228
0
  else if (strcmp(args[1], "parent") == 0)
1229
0
    default_path_mode = DEFAULT_PATH_PARENT;
1230
0
  else if (strcmp(args[1], "origin") == 0)
1231
0
    default_path_mode = DEFAULT_PATH_ORIGIN;
1232
0
  else {
1233
0
    memprintf(err, "%s default-path mode '%s' for '%s', supported modes include 'current', 'config', 'parent', and 'origin'.", *args[1] ? "unsupported" : "missing", args[1], args[0]);
1234
0
    goto end;
1235
0
  }
1236
1237
0
  if (default_path_mode == DEFAULT_PATH_ORIGIN) {
1238
0
    if (!*args[2]) {
1239
0
      memprintf(err, "'%s %s' expects a directory as an argument.", args[0], args[1]);
1240
0
      goto end;
1241
0
    }
1242
0
    if (!cfg_apply_default_path(file, args[2], err)) {
1243
0
      memprintf(err, "couldn't set '%s' to origin '%s': %s.", args[0], args[2], *err);
1244
0
      goto end;
1245
0
    }
1246
0
  }
1247
0
  else if (!cfg_apply_default_path(file, NULL, err)) {
1248
0
    memprintf(err, "couldn't set '%s' to '%s': %s.", args[0], args[1], *err);
1249
0
    goto end;
1250
0
  }
1251
1252
  /* note that once applied, the path is immediately updated */
1253
1254
0
  ret = 0;
1255
0
 end:
1256
0
  return ret;
1257
0
}
1258
1259
/* append a copy of string <filename>, ptr to some allocated memory at the at
1260
 * the end of the list <li>.
1261
 * On failure : return 0 and <err> filled with an error message.
1262
 * The caller is responsible for freeing the <err> and <filename> copy
1263
 * memory area using free().
1264
 */
1265
int list_append_cfgfile(struct list *li, const char *filename, char **err)
1266
0
{
1267
0
  struct cfgfile *entry = NULL;
1268
1269
0
  entry = calloc(1, sizeof(*entry));
1270
0
  if (!entry) {
1271
0
    memprintf(err, "out of memory");
1272
0
    goto fail_entry;
1273
0
  }
1274
1275
0
  entry->filename = strdup(filename);
1276
0
  if (!entry->filename) {
1277
0
    memprintf(err, "out of memory");
1278
0
    goto fail_entry_name;
1279
0
  }
1280
1281
0
  LIST_APPEND(li, &entry->list);
1282
1283
0
  return 1;
1284
1285
0
fail_entry_name:
1286
0
  free(entry->filename);
1287
0
fail_entry:
1288
0
  free(entry);
1289
0
  return 0;
1290
0
}
1291
1292
/* loads the content of the given file in memory. On success, returns the number
1293
 * of bytes successfully stored at *cfg_content until EOF. On error, emits
1294
 * alerts, performs needed clean-up routines and returns -1.
1295
 */
1296
ssize_t load_cfg_in_mem(char *filename, char **cfg_content)
1297
0
{
1298
0
  size_t bytes_to_read = LINESIZE;
1299
0
  size_t chunk_size = 0;
1300
0
  size_t read_bytes = 0;
1301
0
  struct stat file_stat;
1302
0
  char *new_area;
1303
0
  size_t ret = 0;
1304
0
  FILE *f;
1305
1306
  /* let's try to obtain the size, if regular file */
1307
0
  if (stat(filename, &file_stat) != 0) {
1308
0
    ha_alert("stat() failed for configuration file %s : %s\n",
1309
0
       filename, strerror(errno));
1310
0
    return -1;
1311
0
  }
1312
1313
0
  if (file_stat.st_size > chunk_size)
1314
0
    bytes_to_read = file_stat.st_size;
1315
1316
1317
0
  if ((f = fopen(filename,"r")) == NULL) {
1318
0
    ha_alert("Could not open configuration file %s : %s\n",
1319
0
       filename, strerror(errno));
1320
0
    return -1;
1321
0
  }
1322
1323
0
  *cfg_content = NULL;
1324
1325
0
  while (1) {
1326
0
    if (!file_stat.st_size && ((read_bytes + bytes_to_read) > MAX_CFG_SIZE)) {
1327
0
      ha_alert("Loading %s: input is too large %ldMB, limited to %dMB. Exiting.\n",
1328
0
         filename, (long)(read_bytes + bytes_to_read)/(1024*1024),
1329
0
         MAX_CFG_SIZE/(1024*1024));
1330
0
      goto free_mem;
1331
0
    }
1332
1333
0
    if (read_bytes + bytes_to_read > chunk_size) {
1334
0
      chunk_size = (read_bytes + bytes_to_read) * 2;
1335
0
      new_area  = realloc(*cfg_content, chunk_size);
1336
0
      if (new_area == NULL) {
1337
0
        ha_alert("Loading %s: file too long, cannot allocate memory.\n",
1338
0
           filename);
1339
0
        goto free_mem;
1340
0
      }
1341
0
      *cfg_content = new_area;
1342
0
    }
1343
1344
0
    bytes_to_read = chunk_size - read_bytes;
1345
0
    ret = fread(*cfg_content + read_bytes, sizeof(char), bytes_to_read, f);
1346
0
    read_bytes += ret;
1347
1348
0
    if (!ret || feof(f) || ferror(f))
1349
0
      break;
1350
0
  }
1351
1352
0
  fclose(f);
1353
1354
0
  return read_bytes;
1355
1356
0
free_mem:
1357
0
  ha_free(cfg_content);
1358
0
  fclose(f);
1359
1360
0
  return -1;
1361
0
}
1362
1363
/*
1364
 * This function parses the configuration file given in the argument.
1365
 * Returns the error code, 0 if OK, -1 if we are run out of memory,
1366
 * or any combination of :
1367
 *  - ERR_ABORT: must abort ASAP
1368
 *  - ERR_FATAL: we can continue parsing but not start the service
1369
 *  - ERR_WARN: a warning has been emitted
1370
 *  - ERR_ALERT: an alert has been emitted
1371
 * Only the two first ones can stop processing, the two others are just
1372
 * indicators.
1373
 */
1374
int parse_cfg(const struct cfgfile *cfg)
1375
2.69k
{
1376
2.69k
  char *thisline = NULL;
1377
2.69k
  int linesize = LINESIZE;
1378
2.69k
  int linenum = 0;
1379
2.69k
  int err_code = 0;
1380
2.69k
  struct cfg_section *cs = NULL, *pcs = NULL;
1381
2.69k
  struct cfg_section *ics;
1382
2.69k
  int readbytes = 0;
1383
2.69k
  char *outline = NULL;
1384
2.69k
  size_t outlen = 0;
1385
2.69k
  size_t outlinesize = 0;
1386
2.69k
  int fatal = 0;
1387
2.69k
  int missing_lf = -1;
1388
2.69k
  int nested_cond_lvl = 0;
1389
2.69k
  enum nested_cond_state nested_conds[MAXNESTEDCONDS];
1390
2.69k
  char *errmsg = NULL;
1391
2.69k
  const char *cur_position = cfg->content;
1392
2.69k
  char *file = cfg->filename;
1393
1394
2.69k
  global.cfg_curr_line = 0;
1395
2.69k
  global.cfg_curr_file = file;
1396
1397
2.69k
  if ((thisline = malloc(sizeof(*thisline) * linesize)) == NULL) {
1398
0
    ha_alert("Out of memory trying to allocate a buffer for a configuration line.\n");
1399
0
    err_code = -1;
1400
0
    goto err;
1401
0
  }
1402
1403
  /* change to the new dir if required */
1404
2.69k
  if (!cfg_apply_default_path(file, NULL, &errmsg)) {
1405
0
    ha_alert("parsing [%s:%d]: failed to apply default-path: %s.\n", file, linenum, errmsg);
1406
0
    free(errmsg);
1407
0
    err_code = -1;
1408
0
    goto err;
1409
0
  }
1410
1411
41.5k
next_line:
1412
782k
  while (fgets_from_mem(thisline + readbytes, linesize - readbytes,
1413
782k
            &cur_position, cfg->content + cfg->size)) {
1414
780k
    int arg, kwm = KWM_STD;
1415
780k
    char *end;
1416
780k
    char *args[MAX_LINE_ARGS + 1];
1417
780k
    char *line = thisline;
1418
780k
    const char *errptr = NULL; /* first error from parse_line() */
1419
1420
780k
    if (missing_lf != -1) {
1421
160
      ha_alert("parsing [%s:%d]: Stray NUL character at position %d.\n",
1422
160
               file, linenum, (missing_lf + 1));
1423
160
      err_code |= ERR_ALERT | ERR_FATAL;
1424
160
      missing_lf = -1;
1425
160
      break;
1426
160
    }
1427
1428
780k
    linenum++;
1429
780k
    global.cfg_curr_line = linenum;
1430
1431
780k
    if (fatal >= 50) {
1432
16
      ha_alert("parsing [%s:%d]: too many fatal errors (%d), stopping now.\n", file, linenum, fatal);
1433
16
      break;
1434
16
    }
1435
1436
780k
    end = line + strlen(line);
1437
1438
780k
    if (end-line == linesize-1 && *(end-1) != '\n') {
1439
      /* Check if we reached the limit and the last char is not \n.
1440
       * Watch out for the last line without the terminating '\n'!
1441
       */
1442
1.53k
      char *newline;
1443
1.53k
      int newlinesize = linesize * 2;
1444
1445
1.53k
      newline = realloc(thisline, sizeof(*thisline) * newlinesize);
1446
1.53k
      if (newline == NULL) {
1447
0
        ha_alert("parsing [%s:%d]: line too long, cannot allocate memory.\n",
1448
0
           file, linenum);
1449
0
        err_code |= ERR_ALERT | ERR_FATAL;
1450
0
        fatal++;
1451
0
        linenum--;
1452
0
        continue;
1453
0
      }
1454
1455
1.53k
      readbytes = linesize - 1;
1456
1.53k
      linesize = newlinesize;
1457
1.53k
      thisline = newline;
1458
1.53k
      linenum--;
1459
1.53k
      continue;
1460
1.53k
    }
1461
1462
778k
    readbytes = 0;
1463
1464
778k
    if (end > line && *(end-1) == '\n') {
1465
      /* kill trailing LF */
1466
776k
      *(end - 1) = 0;
1467
776k
    }
1468
2.26k
    else {
1469
      /* mark this line as truncated */
1470
2.26k
      missing_lf = end - line;
1471
2.26k
    }
1472
1473
    /* skip leading spaces */
1474
778k
    while (isspace((unsigned char)*line))
1475
5.74k
      line++;
1476
1477
778k
    if (*line == '[') {/* This is the beginning if a scope */
1478
3.52k
      err_code |= cfg_parse_scope(file, linenum, line);
1479
3.52k
      goto next_line;
1480
3.52k
    }
1481
1482
777k
    while (1) {
1483
777k
      uint32_t err;
1484
1485
777k
      arg = sizeof(args) / sizeof(*args);
1486
777k
      outlen = outlinesize;
1487
777k
      errptr = NULL;
1488
777k
      err = parse_line(line, outline, &outlen, args, &arg,
1489
777k
           PARSE_OPT_ENV | PARSE_OPT_DQUOTE | PARSE_OPT_SQUOTE |
1490
777k
           PARSE_OPT_BKSLASH | PARSE_OPT_SHARP | PARSE_OPT_WORD_EXPAND,
1491
777k
           &errptr);
1492
1493
777k
      if (err & PARSE_ERR_QUOTE) {
1494
1.47k
        size_t newpos = sanitize_for_printing(line, errptr - line, 80);
1495
1496
1.47k
        ha_alert("parsing [%s:%d]: unmatched quote at position %d:\n"
1497
1.47k
           "  %s\n  %*s\n", file, linenum, (int)(errptr-thisline+1), line, (int)(newpos+1), "^");
1498
1.47k
        err_code |= ERR_ALERT | ERR_FATAL;
1499
1.47k
        fatal++;
1500
1.47k
        goto next_line;
1501
1.47k
      }
1502
1503
776k
      if (err & PARSE_ERR_BRACE) {
1504
287
        size_t newpos = sanitize_for_printing(line, errptr - line, 80);
1505
1506
287
        ha_alert("parsing [%s:%d]: unmatched brace in environment variable name at position %d:\n"
1507
287
           "  %s\n  %*s\n", file, linenum, (int)(errptr-thisline+1), line, (int)(newpos+1), "^");
1508
287
        err_code |= ERR_ALERT | ERR_FATAL;
1509
287
        fatal++;
1510
287
        goto next_line;
1511
287
      }
1512
1513
775k
      if (err & PARSE_ERR_VARNAME) {
1514
837
        size_t newpos = sanitize_for_printing(line, errptr - line, 80);
1515
1516
837
        ha_alert("parsing [%s:%d]: forbidden first char in environment variable name at position %d:\n"
1517
837
           "  %s\n  %*s\n", file, linenum, (int)(errptr-thisline+1), line, (int)(newpos+1), "^");
1518
837
        err_code |= ERR_ALERT | ERR_FATAL;
1519
837
        fatal++;
1520
837
        goto next_line;
1521
837
      }
1522
1523
774k
      if (err & PARSE_ERR_HEX) {
1524
461
        size_t newpos = sanitize_for_printing(line, errptr - line, 80);
1525
1526
461
        ha_alert("parsing [%s:%d]: truncated or invalid hexadecimal sequence at position %d:\n"
1527
461
           "  %s\n  %*s\n", file, linenum, (int)(errptr-thisline+1), line, (int)(newpos+1), "^");
1528
461
        err_code |= ERR_ALERT | ERR_FATAL;
1529
461
        fatal++;
1530
461
        goto next_line;
1531
461
      }
1532
1533
774k
      if (err & PARSE_ERR_WRONG_EXPAND) {
1534
287
        size_t newpos = sanitize_for_printing(line, errptr - line, 80);
1535
1536
287
        ha_alert("parsing [%s:%d]: truncated or invalid word expansion sequence at position %d:\n"
1537
287
           "  %s\n  %*s\n", file, linenum, (int)(errptr-thisline+1), line, (int)(newpos+1), "^");
1538
287
        err_code |= ERR_ALERT | ERR_FATAL;
1539
287
        fatal++;
1540
287
        goto next_line;
1541
287
      }
1542
1543
774k
      if (err & (PARSE_ERR_TOOLARGE|PARSE_ERR_OVERLAP)) {
1544
2.42k
        outlinesize = (outlen + 1023) & -1024;
1545
2.42k
        outline = my_realloc2(outline, outlinesize);
1546
2.42k
        if (outline == NULL) {
1547
0
          ha_alert("parsing [%s:%d]: line too long, cannot allocate memory.\n",
1548
0
             file, linenum);
1549
0
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1550
0
          fatal++;
1551
0
          outlinesize = 0;
1552
0
          goto err;
1553
0
        }
1554
        /* try again */
1555
2.42k
        continue;
1556
2.42k
      }
1557
1558
771k
      if (err & PARSE_ERR_TOOMANY) {
1559
        /* only check this *after* being sure the output is allocated */
1560
146
        ha_alert("parsing [%s:%d]: too many words, truncating after word %d, position %ld: <%s>.\n",
1561
146
           file, linenum, MAX_LINE_ARGS, (long)(args[MAX_LINE_ARGS-1] - outline + 1), args[MAX_LINE_ARGS-1]);
1562
146
        err_code |= ERR_ALERT | ERR_FATAL;
1563
146
        fatal++;
1564
146
        goto next_line;
1565
146
      }
1566
1567
      /* everything's OK */
1568
771k
      break;
1569
771k
    }
1570
1571
    /* dump cfg */
1572
771k
    if (global.mode & MODE_DUMP_CFG) {
1573
0
      if (args[0] != NULL) {
1574
0
        struct cfg_section *sect;
1575
0
        int is_sect = 0;
1576
0
        int i = 0;
1577
0
        uint32_t g_key = HA_ATOMIC_LOAD(&global.anon_key);
1578
1579
0
        if (global.mode & MODE_DUMP_NB_L)
1580
0
          qfprintf(stdout, "%d\t", linenum);
1581
1582
        /* if a word is in sections list, is_sect = 1 */
1583
0
        list_for_each_entry(sect, &sections, list) {
1584
          /* look for a section_name, but also a section_parser, because there might be
1585
           * only a post_section_parser */
1586
0
          if (strcmp(args[0], sect->section_name) == 0 &&
1587
0
              sect->section_parser) {
1588
0
            is_sect = 1;
1589
0
            break;
1590
0
          }
1591
0
        }
1592
1593
0
        if (g_key == 0) {
1594
          /* no anonymizing needed, dump the config as-is (but without comments).
1595
           * Note: tabs were lost during tokenizing, so we reinsert for non-section
1596
           * keywords.
1597
           */
1598
0
          if (!is_sect)
1599
0
            qfprintf(stdout, "\t");
1600
1601
0
          for (i = 0; i < arg; i++) {
1602
0
            qfprintf(stdout, "%s ", args[i]);
1603
0
          }
1604
0
          qfprintf(stdout, "\n");
1605
0
          continue;
1606
0
        }
1607
1608
        /* We're anonymizing */
1609
1610
0
        if (is_sect) {
1611
          /* new sections are optionally followed by an identifier */
1612
0
          if (arg >= 2) {
1613
0
            qfprintf(stdout, "%s %s\n", args[0], HA_ANON_ID(g_key, args[1]));
1614
0
          }
1615
0
          else {
1616
0
            qfprintf(stdout, "%s\n", args[0]);
1617
0
          }
1618
0
          continue;
1619
0
        }
1620
1621
        /* non-section keywords start indented */
1622
0
        qfprintf(stdout, "\t");
1623
1624
        /* some keywords deserve special treatment */
1625
0
        if (!*args[0]) {
1626
0
          qfprintf(stdout, "\n");
1627
0
        }
1628
1629
0
        else if (strcmp(args[0], "anonkey") == 0) {
1630
0
          qfprintf(stdout, "%s [...]\n", args[0]);
1631
0
        }
1632
1633
0
        else if (strcmp(args[0], "maxconn") == 0) {
1634
0
          qfprintf(stdout, "%s %s\n", args[0], args[1]);
1635
0
        }
1636
1637
0
        else if (strcmp(args[0], "stats") == 0 &&
1638
0
           (strcmp(args[1], "timeout") == 0 || strcmp(args[1], "maxconn") == 0)) {
1639
0
          qfprintf(stdout, "%s %s %s\n", args[0], args[1], args[2]);
1640
0
        }
1641
1642
0
        else if (strcmp(args[0], "stats") == 0 && strcmp(args[1], "socket") == 0) {
1643
0
          qfprintf(stdout, "%s %s ", args[0], args[1]);
1644
1645
0
          if (arg > 2) {
1646
0
            qfprintf(stdout, "%s ", hash_ipanon(g_key, args[2], 1));
1647
1648
0
            if (arg > 3) {
1649
0
              qfprintf(stdout, "[...]\n");
1650
0
            }
1651
0
            else {
1652
0
              qfprintf(stdout, "\n");
1653
0
            }
1654
0
          }
1655
0
          else {
1656
0
            qfprintf(stdout, "\n");
1657
0
          }
1658
0
        }
1659
1660
0
        else if (strcmp(args[0], "timeout") == 0) {
1661
0
          qfprintf(stdout, "%s %s %s\n", args[0], args[1], args[2]);
1662
0
        }
1663
1664
0
        else if (strcmp(args[0], "mode") == 0) {
1665
0
          qfprintf(stdout, "%s %s\n", args[0], args[1]);
1666
0
        }
1667
1668
        /* It concerns user in global section and in userlist */
1669
0
        else if (strcmp(args[0], "user") == 0) {
1670
0
          qfprintf(stdout, "%s %s ", args[0], HA_ANON_ID(g_key, args[1]));
1671
1672
0
          if (arg > 2) {
1673
0
            qfprintf(stdout, "[...]\n");
1674
0
          }
1675
0
          else {
1676
0
            qfprintf(stdout, "\n");
1677
0
          }
1678
0
        }
1679
1680
0
        else if (strcmp(args[0], "bind") == 0) {
1681
0
          qfprintf(stdout, "%s ", args[0]);
1682
0
          qfprintf(stdout, "%s ", hash_ipanon(g_key, args[1], 1));
1683
0
          if (arg > 2) {
1684
0
            qfprintf(stdout, "[...]\n");
1685
0
          }
1686
0
          else {
1687
0
            qfprintf(stdout, "\n");
1688
0
          }
1689
0
        }
1690
1691
0
        else if (strcmp(args[0], "server") == 0) {
1692
0
          qfprintf(stdout, "%s %s ", args[0], HA_ANON_ID(g_key, args[1]));
1693
1694
0
          if (arg > 2) {
1695
0
            qfprintf(stdout, "%s ", hash_ipanon(g_key, args[2], 1));
1696
0
          }
1697
0
          if (arg > 3) {
1698
0
            qfprintf(stdout, "[...]\n");
1699
0
          }
1700
0
          else {
1701
0
            qfprintf(stdout, "\n");
1702
0
          }
1703
0
        }
1704
1705
0
        else if (strcmp(args[0], "redirect") == 0) {
1706
0
          qfprintf(stdout, "%s %s ", args[0], args[1]);
1707
1708
0
          if (strcmp(args[1], "prefix") == 0 || strcmp(args[1], "location") == 0) {
1709
0
            qfprintf(stdout, "%s ", HA_ANON_PATH(g_key, args[2]));
1710
0
          }
1711
0
          else {
1712
0
            qfprintf(stdout, "%s ", args[2]);
1713
0
          }
1714
0
          if (arg > 3) {
1715
0
            qfprintf(stdout, "[...]");
1716
0
          }
1717
0
          qfprintf(stdout, "\n");
1718
0
        }
1719
1720
0
        else if (strcmp(args[0], "acl") == 0) {
1721
0
          qfprintf(stdout, "%s %s %s ", args[0], HA_ANON_ID(g_key, args[1]), args[2]);
1722
1723
0
          if (arg > 3) {
1724
0
            qfprintf(stdout, "[...]");
1725
0
          }
1726
0
          qfprintf(stdout, "\n");
1727
0
        }
1728
1729
0
        else if (strcmp(args[0], "log") == 0) {
1730
0
          qfprintf(stdout, "log ");
1731
1732
0
          if (strcmp(args[1], "global") == 0) {
1733
0
            qfprintf(stdout, "%s ", args[1]);
1734
0
          }
1735
0
          else {
1736
0
            qfprintf(stdout, "%s ", hash_ipanon(g_key, args[1], 1));
1737
0
          }
1738
0
          if (arg > 2) {
1739
0
            qfprintf(stdout, "[...]");
1740
0
          }
1741
0
          qfprintf(stdout, "\n");
1742
0
        }
1743
1744
0
        else if (strcmp(args[0], "peer") == 0) {
1745
0
          qfprintf(stdout, "%s %s ", args[0], HA_ANON_ID(g_key, args[1]));
1746
0
          qfprintf(stdout, "%s ", hash_ipanon(g_key, args[2], 1));
1747
1748
0
          if (arg > 3) {
1749
0
            qfprintf(stdout, "[...]");
1750
0
          }
1751
0
          qfprintf(stdout, "\n");
1752
0
        }
1753
1754
0
        else if (strcmp(args[0], "use_backend") == 0) {
1755
0
          qfprintf(stdout, "%s %s ", args[0], HA_ANON_ID(g_key, args[1]));
1756
1757
0
          if (arg > 2) {
1758
0
            qfprintf(stdout, "[...]");
1759
0
          }
1760
0
          qfprintf(stdout, "\n");
1761
0
        }
1762
1763
0
        else if (strcmp(args[0], "default_backend") == 0) {
1764
0
          qfprintf(stdout, "%s %s\n", args[0], HA_ANON_ID(g_key, args[1]));
1765
0
        }
1766
1767
0
        else if (strcmp(args[0], "source") == 0) {
1768
0
          qfprintf(stdout, "%s %s ", args[0], hash_ipanon(g_key, args[1], 1));
1769
1770
0
          if (arg > 2) {
1771
0
            qfprintf(stdout, "[...]");
1772
0
          }
1773
0
          qfprintf(stdout, "\n");
1774
0
        }
1775
1776
0
        else if (strcmp(args[0], "nameserver") == 0) {
1777
0
          qfprintf(stdout, "%s %s %s ", args[0],
1778
0
            HA_ANON_ID(g_key, args[1]), hash_ipanon(g_key, args[2], 1));
1779
0
          if (arg > 3) {
1780
0
            qfprintf(stdout, "[...]");
1781
0
          }
1782
0
          qfprintf(stdout, "\n");
1783
0
        }
1784
1785
0
        else if (strcmp(args[0], "http-request") == 0) {
1786
0
          qfprintf(stdout, "%s %s ", args[0], args[1]);
1787
0
          if (arg > 2)
1788
0
            qfprintf(stdout, "[...]");
1789
0
          qfprintf(stdout, "\n");
1790
0
        }
1791
1792
0
        else if (strcmp(args[0], "http-response") == 0) {
1793
0
          qfprintf(stdout, "%s %s ", args[0], args[1]);
1794
0
          if (arg > 2)
1795
0
            qfprintf(stdout, "[...]");
1796
0
          qfprintf(stdout, "\n");
1797
0
        }
1798
1799
0
        else if (strcmp(args[0], "http-after-response") == 0) {
1800
0
          qfprintf(stdout, "%s %s ", args[0], args[1]);
1801
0
          if (arg > 2)
1802
0
            qfprintf(stdout, "[...]");
1803
0
          qfprintf(stdout, "\n");
1804
0
        }
1805
1806
0
        else if (strcmp(args[0], "filter") == 0) {
1807
0
          qfprintf(stdout, "%s %s ", args[0], args[1]);
1808
0
          if (arg > 2)
1809
0
            qfprintf(stdout, "[...]");
1810
0
          qfprintf(stdout, "\n");
1811
0
        }
1812
1813
0
        else if (strcmp(args[0], "errorfile") == 0) {
1814
0
          qfprintf(stdout, "%s %s %s\n", args[0], args[1], HA_ANON_PATH(g_key, args[2]));
1815
0
        }
1816
1817
0
        else if (strcmp(args[0], "cookie") == 0) {
1818
0
          qfprintf(stdout, "%s %s ", args[0], HA_ANON_ID(g_key, args[1]));
1819
0
          if (arg > 2)
1820
0
            qfprintf(stdout, "%s ", args[2]);
1821
0
          if (arg > 3)
1822
0
            qfprintf(stdout, "[...]");
1823
0
          qfprintf(stdout, "\n");
1824
0
        }
1825
1826
0
        else if (strcmp(args[0], "stats") == 0 && strcmp(args[1], "auth") == 0) {
1827
0
          qfprintf(stdout, "%s %s %s\n", args[0], args[1], HA_ANON_STR(g_key, args[2]));
1828
0
        }
1829
1830
0
        else {
1831
          /* display up to 3 words and mask the rest which might be confidential */
1832
0
          for (i = 0; i < MIN(arg, 3); i++) {
1833
0
            qfprintf(stdout, "%s ", args[i]);
1834
0
          }
1835
0
          if (arg > 3) {
1836
0
            qfprintf(stdout, "[...]");
1837
0
          }
1838
0
          qfprintf(stdout, "\n");
1839
0
        }
1840
0
      }
1841
0
      continue;
1842
0
    }
1843
    /* end of config dump */
1844
1845
    /* empty line */
1846
771k
    if (!*args || !**args)
1847
734k
      continue;
1848
1849
    /* check for config macros */
1850
36.9k
    if (*args[0] == '.') {
1851
24.1k
      if (strcmp(args[0], ".if") == 0) {
1852
6.50k
        const char *errptr = NULL;
1853
6.50k
        char *errmsg = NULL;
1854
6.50k
        int cond;
1855
6.50k
        char *w;
1856
1857
        /* remerge all words into a single expression */
1858
9.38k
        for (w = *args; (w += strlen(w)) < outline + outlen - 1; *w = ' ')
1859
2.88k
          ;
1860
1861
6.50k
        nested_cond_lvl++;
1862
6.50k
        if (nested_cond_lvl >= MAXNESTEDCONDS) {
1863
4
          ha_alert("parsing [%s:%d]: too many nested '.if', max is %d.\n", file, linenum, MAXNESTEDCONDS);
1864
4
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1865
4
          goto err;
1866
4
        }
1867
1868
6.50k
        if (nested_cond_lvl > 1 &&
1869
4.54k
            (nested_conds[nested_cond_lvl - 1] == NESTED_COND_IF_DROP ||
1870
3.96k
             nested_conds[nested_cond_lvl - 1] == NESTED_COND_IF_SKIP ||
1871
2.70k
             nested_conds[nested_cond_lvl - 1] == NESTED_COND_ELIF_DROP ||
1872
2.42k
             nested_conds[nested_cond_lvl - 1] == NESTED_COND_ELIF_SKIP ||
1873
3.61k
             nested_conds[nested_cond_lvl - 1] == NESTED_COND_ELSE_DROP)) {
1874
3.61k
          nested_conds[nested_cond_lvl] = NESTED_COND_IF_SKIP;
1875
3.61k
          goto next_line;
1876
3.61k
        }
1877
1878
2.88k
        cond = cfg_eval_condition(args + 1, &errmsg, &errptr);
1879
2.88k
        if (cond < 0) {
1880
475
          size_t newpos = sanitize_for_printing(args[1], errptr - args[1], 76);
1881
1882
475
          ha_alert("parsing [%s:%d]: %s in '.if' at position %d:\n  .if %s\n  %*s\n",
1883
475
             file, linenum, errmsg,
1884
475
                   (int)(errptr-args[1]+1), args[1], (int)(newpos+5), "^");
1885
1886
475
          free(errmsg);
1887
475
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1888
475
          goto err;
1889
475
        }
1890
1891
2.41k
        if (cond)
1892
722
          nested_conds[nested_cond_lvl] = NESTED_COND_IF_TAKE;
1893
1.69k
        else
1894
1.69k
          nested_conds[nested_cond_lvl] = NESTED_COND_IF_DROP;
1895
1896
2.41k
        goto next_line;
1897
2.88k
      }
1898
17.6k
      else if (strcmp(args[0], ".elif") == 0) {
1899
3.06k
        const char *errptr = NULL;
1900
3.06k
        char *errmsg = NULL;
1901
3.06k
        int cond;
1902
3.06k
        char *w;
1903
1904
        /* remerge all words into a single expression */
1905
4.74k
        for (w = *args; (w += strlen(w)) < outline + outlen - 1; *w = ' ')
1906
1.67k
          ;
1907
1908
3.06k
        if (!nested_cond_lvl) {
1909
8
          ha_alert("parsing [%s:%d]: lone '.elif' with no matching '.if'.\n", file, linenum);
1910
8
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1911
8
          goto err;
1912
8
        }
1913
1914
3.05k
        if (nested_conds[nested_cond_lvl] == NESTED_COND_ELSE_TAKE ||
1915
3.05k
            nested_conds[nested_cond_lvl] == NESTED_COND_ELSE_DROP) {
1916
5
          ha_alert("parsing [%s:%d]: '.elif' after '.else' is not permitted.\n", file, linenum);
1917
5
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1918
5
          goto err;
1919
5
        }
1920
1921
3.05k
        if (nested_conds[nested_cond_lvl] == NESTED_COND_IF_TAKE ||
1922
2.82k
            nested_conds[nested_cond_lvl] == NESTED_COND_IF_SKIP ||
1923
2.31k
            nested_conds[nested_cond_lvl] == NESTED_COND_ELIF_TAKE ||
1924
1.96k
            nested_conds[nested_cond_lvl] == NESTED_COND_ELIF_SKIP) {
1925
1.66k
          nested_conds[nested_cond_lvl] = NESTED_COND_ELIF_SKIP;
1926
1.66k
          goto next_line;
1927
1.66k
        }
1928
1929
1.39k
        cond = cfg_eval_condition(args + 1, &errmsg, &errptr);
1930
1.39k
        if (cond < 0) {
1931
11
          size_t newpos = sanitize_for_printing(args[1], errptr - args[1], 74);
1932
1933
11
          ha_alert("parsing [%s:%d]: %s in '.elif' at position %d:\n  .elif %s\n  %*s\n",
1934
11
             file, linenum, errmsg,
1935
11
                   (int)(errptr-args[1]+1), args[1], (int)(newpos+7), "^");
1936
1937
11
          free(errmsg);
1938
11
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1939
11
          goto err;
1940
11
        }
1941
1942
1.37k
        if (cond)
1943
679
          nested_conds[nested_cond_lvl] = NESTED_COND_ELIF_TAKE;
1944
700
        else
1945
700
          nested_conds[nested_cond_lvl] = NESTED_COND_ELIF_DROP;
1946
1947
1.37k
        goto next_line;
1948
1.39k
      }
1949
14.5k
      else if (strcmp(args[0], ".else") == 0) {
1950
1.98k
        if (*args[1]) {
1951
7
          ha_alert("parsing [%s:%d]: Unexpected argument '%s' for '%s'.\n",
1952
7
                   file, linenum, args[1], args[0]);
1953
7
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1954
7
          break;
1955
7
        }
1956
1957
1.97k
        if (!nested_cond_lvl) {
1958
2
          ha_alert("parsing [%s:%d]: lone '.else' with no matching '.if'.\n", file, linenum);
1959
2
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1960
2
          goto err;
1961
2
        }
1962
1963
1.97k
        if (nested_conds[nested_cond_lvl] == NESTED_COND_ELSE_TAKE ||
1964
1.97k
            nested_conds[nested_cond_lvl] == NESTED_COND_ELSE_DROP) {
1965
8
          ha_alert("parsing [%s:%d]: '.else' after '.else' is not permitted.\n", file, linenum);
1966
8
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1967
8
          goto err;
1968
8
        }
1969
1970
1.96k
        if (nested_conds[nested_cond_lvl] == NESTED_COND_IF_TAKE ||
1971
1.75k
            nested_conds[nested_cond_lvl] == NESTED_COND_IF_SKIP ||
1972
768
            nested_conds[nested_cond_lvl] == NESTED_COND_ELIF_TAKE ||
1973
1.63k
            nested_conds[nested_cond_lvl] == NESTED_COND_ELIF_SKIP) {
1974
1.63k
          nested_conds[nested_cond_lvl] = NESTED_COND_ELSE_DROP;
1975
1.63k
        } else {
1976
          /* otherwise we take the "else" */
1977
331
          nested_conds[nested_cond_lvl] = NESTED_COND_ELSE_TAKE;
1978
331
        }
1979
1.96k
        goto next_line;
1980
1.97k
      }
1981
12.5k
      else if (strcmp(args[0], ".endif") == 0) {
1982
3.58k
        if (*args[1]) {
1983
9
          ha_alert("parsing [%s:%d]: Unexpected argument '%s' for '%s'.\n",
1984
9
                   file, linenum, args[1], args[0]);
1985
9
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1986
9
          break;
1987
9
        }
1988
1989
3.57k
        if (!nested_cond_lvl) {
1990
2
          ha_alert("parsing [%s:%d]: lone '.endif' with no matching '.if'.\n", file, linenum);
1991
2
          err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
1992
2
          break;
1993
2
        }
1994
3.57k
        nested_cond_lvl--;
1995
3.57k
        goto next_line;
1996
3.57k
      }
1997
24.1k
    }
1998
1999
21.8k
    if (nested_cond_lvl &&
2000
9.38k
        (nested_conds[nested_cond_lvl] == NESTED_COND_IF_DROP ||
2001
7.35k
         nested_conds[nested_cond_lvl] == NESTED_COND_IF_SKIP ||
2002
4.65k
         nested_conds[nested_cond_lvl] == NESTED_COND_ELIF_DROP ||
2003
4.21k
         nested_conds[nested_cond_lvl] == NESTED_COND_ELIF_SKIP ||
2004
8.56k
         nested_conds[nested_cond_lvl] == NESTED_COND_ELSE_DROP)) {
2005
      /* The current block is masked out by the conditions */
2006
8.56k
      goto next_line;
2007
8.56k
    }
2008
2009
    /* .warning/.error/.notice/.diag */
2010
13.2k
    if (*args[0] == '.' && !(global.mode & MODE_DISCOVERY)) {
2011
5.95k
      if (strcmp(args[0], ".alert") == 0) {
2012
596
        if (*args[2]) {
2013
594
          ha_alert("parsing [%s:%d]: Unexpected argument '%s' for '%s'. Use quotes if the message should contain spaces.\n",
2014
594
                     file, linenum, args[2], args[0]);
2015
594
          err_code |= ERR_ALERT | ERR_FATAL;
2016
594
          goto next_line;
2017
594
        }
2018
2019
2
        ha_alert("parsing [%s:%d]: '%s'.\n", file, linenum, args[1]);
2020
2
        err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
2021
2
        goto err;
2022
596
      }
2023
5.35k
      else if (strcmp(args[0], ".warning") == 0) {
2024
3.93k
        if (*args[2]) {
2025
290
          ha_alert("parsing [%s:%d]: Unexpected argument '%s' for '%s'. Use quotes if the message should contain spaces.\n",
2026
290
                     file, linenum, args[2], args[0]);
2027
290
          err_code |= ERR_ALERT | ERR_FATAL;
2028
290
          goto next_line;
2029
290
        }
2030
2031
3.64k
        ha_warning("parsing [%s:%d]: '%s'.\n", file, linenum, args[1]);
2032
3.64k
        err_code |= ERR_WARN;
2033
3.64k
        goto next_line;
2034
3.93k
      }
2035
1.42k
      else if (strcmp(args[0], ".notice") == 0) {
2036
601
        if (*args[2]) {
2037
320
          ha_alert("parsing [%s:%d]: Unexpected argument '%s' for '%s'. Use quotes if the message should contain spaces.\n",
2038
320
                   file, linenum, args[2], args[0]);
2039
320
          err_code |= ERR_ALERT | ERR_FATAL;
2040
320
          goto next_line;
2041
320
        }
2042
2043
281
        ha_notice("parsing [%s:%d]: '%s'.\n", file, linenum, args[1]);
2044
281
        goto next_line;
2045
601
      }
2046
820
      else if (strcmp(args[0], ".diag") == 0) {
2047
568
        if (*args[2]) {
2048
168
          ha_alert("parsing [%s:%d]: Unexpected argument '%s' for '%s'. Use quotes if the message should contain spaces.\n",
2049
168
                   file, linenum, args[2], args[0]);
2050
168
          err_code |= ERR_ALERT | ERR_FATAL;
2051
168
          goto next_line;
2052
168
        }
2053
2054
400
        ha_diag_warning("parsing [%s:%d]: '%s'.\n", file, linenum, args[1]);
2055
400
        goto next_line;
2056
568
      }
2057
252
      else {
2058
252
        ha_alert("parsing [%s:%d]: unknown directive '%s'.\n", file, linenum, args[0]);
2059
252
        err_code |= ERR_ALERT | ERR_FATAL;
2060
252
        fatal++;
2061
252
        break;
2062
252
      }
2063
5.95k
    }
2064
2065
    /* now check for empty args on the line. Only do that in normal
2066
     * mode to prevent double display during discovery pass. It relies
2067
     * on errptr as returned by parse_line() above.
2068
     */
2069
7.28k
    if (!(global.mode & MODE_DISCOVERY)) {
2070
7.28k
      int check_arg;
2071
2072
19.7k
      for (check_arg = 0; check_arg < arg; check_arg++) {
2073
15.4k
        if (!*args[check_arg]) {
2074
2.96k
          static int warned_empty;
2075
2.96k
          size_t newpos;
2076
2.96k
          int suggest = 0;
2077
2078
          /* if an empty arg was found, its pointer should be in <errptr>, except
2079
           * for rare cases such as '\x00' etc. We need to check errptr in any case
2080
           * and if it's not set, we'll fall back to args's position in the output
2081
           * string instead (less accurate but still useful).
2082
           */
2083
2.96k
          if (!errptr) {
2084
261
            newpos = args[check_arg] - outline;
2085
261
            if (newpos >= strlen(line))
2086
144
              newpos = 0; // impossible to report anything, start at the beginning.
2087
261
            errptr = line + newpos;
2088
2.70k
          } else if (isalnum((uchar)*errptr) || *errptr == '_') {
2089
            /* looks like an environment variable */
2090
2.60k
            suggest = 1;
2091
2.60k
          }
2092
2093
          /* sanitize input line in-place */
2094
2.96k
          newpos = sanitize_for_printing(line, errptr - line, 80);
2095
2.96k
          ha_alert("parsing [%s:%d]: argument number %d at position %d is empty and marks the end of the "
2096
2.96k
                   "argument list:\n  %s\n  %*s\n%s",
2097
2.96k
                   file, linenum, check_arg, (int)(errptr - thisline + 1), line, (int)(newpos + 1),
2098
2.96k
                   "^", (warned_empty++) ? "" :
2099
2.96k
                   ("Aborting to prevent all subsequent arguments from being silently ignored. "
2100
1
              "If this is caused by an environment variable expansion, please have a look at section "
2101
1
              "2.3 of the configuration manual to find solutions to address this.\n"));
2102
2103
2.96k
          if (suggest) {
2104
2.60k
            const char *end = errptr;
2105
2.60k
            struct ist alt;
2106
2107
3.12M
            while (isalnum((uchar)*end) || *end == '_')
2108
3.11M
              end++;
2109
2110
2.60k
            if (end > errptr) {
2111
2.53k
              alt = env_suggest(ist2(errptr, end - errptr));
2112
2.53k
              if (isttest(alt))
2113
346
                ha_notice("Hint: maybe you meant %.*s instead ?\n", (int)istlen(alt), istptr(alt));
2114
2.53k
            }
2115
2.60k
          }
2116
2117
2.96k
          err_code |= ERR_ALERT | ERR_FATAL;
2118
2.96k
          fatal++;
2119
2.96k
          goto next_line;
2120
2.96k
        }
2121
15.4k
      }
2122
7.28k
    }
2123
2124
    /* check for keyword modifiers "no" and "default" */
2125
4.32k
    if (strcmp(args[0], "no") == 0) {
2126
2.08k
      kwm = KWM_NO;
2127
2.08k
      lshift_args(args);
2128
2.08k
    }
2129
2.24k
    else if (strcmp(args[0], "default") == 0) {
2130
159
      kwm = KWM_DEF;
2131
159
      lshift_args(args);
2132
159
    }
2133
2134
4.32k
    if (kwm != KWM_STD && strcmp(args[0], "option") != 0 &&
2135
2.15k
        strcmp(args[0], "log") != 0 && strcmp(args[0], "busy-polling") != 0 &&
2136
1.90k
        strcmp(args[0], "set-dumpable") != 0 && strcmp(args[0], "strict-limits") != 0 &&
2137
1.63k
        strcmp(args[0], "insecure-fork-wanted") != 0 &&
2138
1.46k
        strcmp(args[0], "numa-cpu-mapping") != 0) {
2139
1.31k
      ha_alert("parsing [%s:%d]: negation/default currently "
2140
1.31k
         "supported only for options, log, busy-polling, "
2141
1.31k
         "set-dumpable, strict-limits, insecure-fork-wanted "
2142
1.31k
         "and numa-cpu-mapping.\n", file, linenum);
2143
1.31k
      err_code |= ERR_ALERT | ERR_FATAL;
2144
1.31k
      fatal++;
2145
1.31k
    }
2146
2147
    /* detect section start */
2148
4.32k
    list_for_each_entry(ics, &sections, list) {
2149
0
      if (strcmp(args[0], ics->section_name) == 0 && ics->section_parser) {
2150
0
        cursection = ics->section_name;
2151
0
        pcs = cs;
2152
0
        cs = ics;
2153
0
        free(global.cfg_curr_section);
2154
0
        global.cfg_curr_section = strdup(*args[1] ? args[1] : args[0]);
2155
0
        check_section_position(args[0], file, linenum);
2156
0
        break;
2157
0
      }
2158
0
    }
2159
2160
4.32k
    if (pcs) {
2161
0
      struct cfg_section *psect;
2162
0
      int status;
2163
2164
2165
      /* look for every post_section_parser for the previous section name */
2166
0
      list_for_each_entry(psect, &sections, list) {
2167
0
        if (strcmp(pcs->section_name, psect->section_name) == 0 &&
2168
0
            psect->post_section_parser) {
2169
2170
          /* don't call post_section_parser in MODE_DISCOVERY */
2171
0
          if (global.mode & MODE_DISCOVERY)
2172
0
            goto section_parser;
2173
2174
0
          status = psect->post_section_parser();
2175
0
          err_code |= status;
2176
0
          if (status & ERR_FATAL)
2177
0
            fatal++;
2178
2179
0
          if (err_code & ERR_ABORT)
2180
0
            goto err;
2181
0
        }
2182
0
      }
2183
0
    }
2184
4.32k
    pcs = NULL;
2185
2186
4.32k
section_parser:
2187
4.32k
    if (!cs) {
2188
      /* ignore unknown section names during the first read in MODE_DISCOVERY */
2189
4.32k
      if (global.mode & MODE_DISCOVERY)
2190
0
        continue;
2191
4.32k
      ha_alert("parsing [%s:%d]: unknown keyword '%s' out of section.\n", file, linenum, args[0]);
2192
4.32k
      err_code |= ERR_ALERT | ERR_FATAL;
2193
4.32k
      fatal++;
2194
4.32k
    } else {
2195
0
      int status;
2196
2197
      /* read only the "global" and "program" sections in MODE_DISCOVERY */
2198
0
      if (((global.mode & MODE_DISCOVERY) && (strcmp(cs->section_name, "global") != 0)
2199
0
           && (strcmp(cs->section_name, "program") != 0)))
2200
0
        continue;
2201
2202
0
      status = cs->section_parser(file, linenum, args, kwm);
2203
0
      err_code |= status;
2204
0
      if (status & ERR_FATAL)
2205
0
        fatal++;
2206
2207
0
      if (err_code & ERR_ABORT)
2208
0
        goto err;
2209
0
    }
2210
4.32k
  }
2211
2212
2.17k
  if (missing_lf != -1) {
2213
1.63k
    ha_alert("parsing [%s:%d]: Missing LF on last line, file might have been truncated at position %d.\n",
2214
1.63k
             file, linenum, (missing_lf + 1));
2215
1.63k
    err_code |= ERR_ALERT | ERR_FATAL;
2216
1.63k
  }
2217
2218
2.17k
  ha_free(&global.cfg_curr_section);
2219
2220
  /* call post_section_parser of the last section when there is no more lines */
2221
2.17k
  if (cs) {
2222
0
    struct cfg_section *psect;
2223
0
    int status;
2224
2225
    /* don't call post_section_parser in MODE_DISCOVERY */
2226
0
    if (!(global.mode & MODE_DISCOVERY)) {
2227
0
      list_for_each_entry(psect, &sections, list) {
2228
0
        if (strcmp(cs->section_name, psect->section_name) == 0 &&
2229
0
             psect->post_section_parser) {
2230
2231
0
          status = psect->post_section_parser();
2232
0
          if (status & ERR_FATAL)
2233
0
            fatal++;
2234
2235
0
          err_code |= status;
2236
2237
0
          if (err_code & ERR_ABORT)
2238
0
            goto err;
2239
2240
0
        }
2241
0
      }
2242
0
    }
2243
0
  }
2244
2245
2.17k
  if (nested_cond_lvl) {
2246
363
    ha_alert("parsing [%s:%d]: non-terminated '.if' block.\n", file, linenum);
2247
363
    err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
2248
363
  }
2249
2250
2.69k
err:
2251
2.69k
  ha_free(&cfg_scope);
2252
2.69k
  cursection = NULL;
2253
2.69k
  free(thisline);
2254
2.69k
  free(outline);
2255
2.69k
  global.cfg_curr_line = 0;
2256
2.69k
  global.cfg_curr_file = NULL;
2257
2258
2.69k
  return err_code;
2259
2.17k
}
2260
2261
/*
2262
 * Returns the error code, 0 if OK, or any combination of :
2263
 *  - ERR_ABORT: must abort ASAP
2264
 *  - ERR_FATAL: we can continue parsing but not start the service
2265
 *  - ERR_WARN: a warning has been emitted
2266
 *  - ERR_ALERT: an alert has been emitted
2267
 * Only the two first ones can stop processing, the two others are just
2268
 * indicators.
2269
 */
2270
int check_config_validity()
2271
0
{
2272
0
  int cfgerr = 0, ret;
2273
0
  struct proxy *init_proxies_list = NULL, *defpx;
2274
0
  struct stktable *t;
2275
0
  struct server *newsrv = NULL;
2276
0
  struct mt_list back;
2277
0
  int err_code = 0;
2278
  /* Value forced to skip '1' due to an historical bug, see below for more details. */
2279
0
  unsigned int next_pxid = 2;
2280
0
  struct bind_conf *bind_conf;
2281
0
  char *err;
2282
0
  struct cfg_postparser *postparser;
2283
0
  struct resolvers *curr_resolvers = NULL;
2284
0
  int i;
2285
2286
0
  bind_conf = NULL;
2287
  /*
2288
   * Now, check for the integrity of all that we have collected.
2289
   */
2290
2291
0
  if (!global.tune.max_http_hdr)
2292
0
    global.tune.max_http_hdr = MAX_HTTP_HDR;
2293
2294
0
  if (!global.tune.cookie_len)
2295
0
    global.tune.cookie_len = CAPTURE_LEN;
2296
2297
0
  if (!global.tune.requri_len)
2298
0
    global.tune.requri_len = REQURI_LEN;
2299
2300
0
  if (!global.thread_limit)
2301
0
    global.thread_limit = MAX_THREADS;
2302
2303
#if defined(USE_THREAD)
2304
  if (thread_cpus_enabled_at_boot > global.thread_limit)
2305
    thread_cpus_enabled_at_boot = global.thread_limit;
2306
#endif
2307
0
  if (global.nbthread > global.thread_limit) {
2308
0
    ha_warning("nbthread forced to a higher value (%d) than the configured thread-hard-limit (%d), enforcing the limit. "
2309
0
         "Please fix either value to remove this warning.\n",
2310
0
         global.nbthread, global.thread_limit);
2311
0
    global.nbthread = global.thread_limit;
2312
0
  }
2313
2314
0
  if (global.tune.bufsize_large > 0) {
2315
0
    if (global.tune.bufsize_large == global.tune.bufsize)
2316
0
      global.tune.bufsize_large = 0;
2317
0
    else if (global.tune.bufsize_large < global.tune.bufsize) {
2318
0
      ha_warning("tune.bufsize.large (%u) is lower than tune.bufsize (%u). large buffers support is disabled. "
2319
0
           "Please fix either value to remove this warning.\n",
2320
0
           global.tune.bufsize_large, global.tune.bufsize);
2321
0
      global.tune.bufsize_large = 0;
2322
0
      err_code |= ERR_WARN;
2323
0
    }
2324
0
  }
2325
2326
0
  if (global.tune.bufsize_small > 0) {
2327
0
    if (global.tune.bufsize_small == global.tune.bufsize)
2328
0
      global.tune.bufsize_small = 0;
2329
0
    else if (global.tune.bufsize_small > global.tune.bufsize) {
2330
0
      ha_warning("invalid small buffer size %d bytes which is greater to default bufsize %d bytes.\n",
2331
0
           global.tune.bufsize_small, global.tune.bufsize);
2332
0
      global.tune.bufsize_small = 0;
2333
0
      err_code |= ERR_WARN;
2334
0
    }
2335
0
  }
2336
2337
  /* in the worst case these were supposed to be set in thread_detect_count() */
2338
0
  BUG_ON(!global.nbthread);
2339
0
  BUG_ON(!global.nbtgroups);
2340
2341
0
  if (thread_map_to_groups() < 0) {
2342
0
    err_code |= ERR_ALERT | ERR_FATAL;
2343
0
    goto out;
2344
0
  }
2345
2346
0
  pool_head_requri = create_pool("requri", global.tune.requri_len , MEM_F_SHARED);
2347
2348
0
  pool_head_capture = create_pool("capture", global.tune.cookie_len, MEM_F_SHARED);
2349
2350
  /* both will have already emitted an error message if needed */
2351
0
  if (!pool_head_requri || !pool_head_capture) {
2352
0
    err_code |= ERR_ALERT | ERR_FATAL;
2353
0
    goto out;
2354
0
  }
2355
2356
  /* Post initialisation of the users and groups lists. */
2357
0
  err_code = userlist_postinit();
2358
0
  if (err_code != ERR_NONE)
2359
0
    goto out;
2360
2361
  /* first, we will invert the proxy list order */
2362
0
  curproxy = NULL;
2363
0
  while (proxies_list) {
2364
0
    struct proxy *next;
2365
2366
0
    next = proxies_list->next;
2367
0
    proxies_list->next = curproxy;
2368
0
    curproxy = proxies_list;
2369
0
    if (!next)
2370
0
      break;
2371
0
    proxies_list = next;
2372
0
  }
2373
2374
  /*
2375
   * we must finish to initialize certain things on the servers,
2376
   * as some of the fields may be accessed soon
2377
   */
2378
0
  MT_LIST_FOR_EACH_ENTRY_LOCKED(newsrv, &servers_list, global_list, back) {
2379
0
    err_code |= srv_preinit(newsrv);
2380
0
    if (err_code & ERR_CODE)
2381
0
      goto out;
2382
0
  }
2383
2384
0
  list_for_each_entry(defpx, &defaults_list, el) {
2385
    /* check validity for 'tcp-request' layer 4/5/6/7 rules */
2386
0
    cfgerr += check_action_rules(&defpx->tcp_req.l4_rules, defpx, &err_code);
2387
0
    cfgerr += check_action_rules(&defpx->tcp_req.l5_rules, defpx, &err_code);
2388
0
    cfgerr += check_action_rules(&defpx->tcp_req.inspect_rules, defpx, &err_code);
2389
0
    cfgerr += check_action_rules(&defpx->tcp_rep.inspect_rules, defpx, &err_code);
2390
0
    cfgerr += check_action_rules(&defpx->http_req_rules, defpx, &err_code);
2391
0
    cfgerr += check_action_rules(&defpx->http_res_rules, defpx, &err_code);
2392
0
    cfgerr += check_action_rules(&defpx->http_after_res_rules, defpx, &err_code);
2393
#ifdef USE_QUIC
2394
    cfgerr += check_action_rules(&defpx->quic_init_rules, defpx, &err_code);
2395
#endif
2396
2397
0
    err = NULL;
2398
0
    i = smp_resolve_args(defpx, &err);
2399
0
    cfgerr += i;
2400
0
    if (i) {
2401
0
      indent_msg(&err, 8);
2402
0
      ha_alert("%s%s\n", i > 1 ? "multiple argument resolution errors:" : "", err);
2403
0
      ha_free(&err);
2404
0
    }
2405
0
    else {
2406
0
      cfgerr += acl_find_targets(defpx);
2407
0
    }
2408
2409
0
    err_code |= proxy_check_http_errors(defpx);
2410
0
  }
2411
2412
  /* starting to initialize the main proxies list */
2413
0
  init_proxies_list = proxies_list;
2414
2415
0
init_proxies_list_stage1:
2416
0
  for (curproxy = init_proxies_list; curproxy; curproxy = curproxy->next) {
2417
0
    proxy_init_per_thr(curproxy);
2418
2419
    /* Assign automatic UUID if unset except for internal proxies.
2420
     *
2421
     * WARNING proxy UUID initialization is buggy as value '1' is
2422
     * skipped if not explicitly used. This is an historical bug
2423
     * and should not be corrected to prevent breakage on future
2424
     * versions.
2425
     */
2426
0
    if (!(curproxy->cap & PR_CAP_INT) && curproxy->uuid < 0) {
2427
0
      next_pxid = proxy_get_next_id(next_pxid);
2428
0
      curproxy->uuid = next_pxid;
2429
0
      proxy_index_id(curproxy);
2430
0
      next_pxid++;
2431
0
    }
2432
2433
0
    if (curproxy->mode == PR_MODE_HTTP && global.tune.bufsize >= (256 << 20) && ONLY_ONCE()) {
2434
0
      ha_alert("global.tune.bufsize must be below 256 MB when HTTP is in use (current value = %d).\n",
2435
0
         global.tune.bufsize);
2436
0
      cfgerr++;
2437
0
    }
2438
0
    if (curproxy->mode == PR_MODE_HTTP && global.tune.bufsize_large >= (256 << 20) && ONLY_ONCE()) {
2439
0
      ha_alert("global.tune.bufsize_large must be below 256 MB when HTTP is in use (current value = %d).\n",
2440
0
         global.tune.bufsize_large);
2441
0
      cfgerr++;
2442
0
    }
2443
2444
0
    if (curproxy->flags & PR_FL_DISABLED) {
2445
      /* ensure we don't keep listeners uselessly bound. We
2446
       * can't disable their listeners yet (fdtab not
2447
       * allocated yet) but let's skip them.
2448
       */
2449
0
      if (curproxy->table) {
2450
0
        ha_free(&curproxy->table->peers.name);
2451
0
        curproxy->table->peers.p = NULL;
2452
0
      }
2453
0
      continue;
2454
0
    }
2455
2456
0
    ret = proxy_finalize(curproxy, &err_code);
2457
0
    if (ret) {
2458
0
      cfgerr += ret;
2459
0
      if (err_code & ERR_FATAL)
2460
0
        goto out;
2461
0
    }
2462
0
  }
2463
2464
  /* Dynamic proxies IDs will never be lowered than this value. */
2465
0
  dynpx_next_id = next_pxid;
2466
2467
  /*
2468
   * We have just initialized the main proxies list
2469
   * we must also configure the log-forward proxies list
2470
   */
2471
0
  if (init_proxies_list == proxies_list) {
2472
0
    init_proxies_list = cfg_log_forward;
2473
    /* check if list is not null to avoid infinite loop */
2474
0
    if (init_proxies_list)
2475
0
      goto init_proxies_list_stage1;
2476
0
  }
2477
2478
0
  if (init_proxies_list == cfg_log_forward) {
2479
0
    init_proxies_list = sink_proxies_list;
2480
    /* check if list is not null to avoid infinite loop */
2481
0
    if (init_proxies_list)
2482
0
      goto init_proxies_list_stage1;
2483
0
  }
2484
2485
  /***********************************************************/
2486
  /* At this point, target names have already been resolved. */
2487
  /***********************************************************/
2488
2489
0
  idle_conn_task = task_new_anywhere();
2490
0
  if (!idle_conn_task) {
2491
0
    ha_alert("parsing : failed to allocate global idle connection task.\n");
2492
0
    cfgerr++;
2493
0
  }
2494
0
  else {
2495
0
    idle_conn_task->process = srv_cleanup_idle_conns;
2496
0
    idle_conn_task->context = NULL;
2497
2498
0
    for (i = 0; i < global.nbthread; i++) {
2499
0
      idle_conns[i].cleanup_task = task_new_on(i);
2500
0
      if (!idle_conns[i].cleanup_task) {
2501
0
        ha_alert("parsing : failed to allocate idle connection tasks for thread '%d'.\n", i);
2502
0
        cfgerr++;
2503
0
        break;
2504
0
      }
2505
2506
0
      idle_conns[i].cleanup_task->process = srv_cleanup_toremove_conns;
2507
0
      idle_conns[i].cleanup_task->context = NULL;
2508
0
      HA_SPIN_INIT(&idle_conns[i].idle_conns_lock);
2509
0
      MT_LIST_INIT(&idle_conns[i].toremove_conns);
2510
0
    }
2511
0
  }
2512
2513
  /* perform the final checks before creating tasks */
2514
2515
  /* starting to initialize the main proxies list */
2516
0
  init_proxies_list = proxies_list;
2517
2518
0
init_proxies_list_stage2:
2519
0
  for (curproxy = init_proxies_list; curproxy; curproxy = curproxy->next) {
2520
0
    struct listener *listener;
2521
0
    unsigned int next_id;
2522
2523
    /* Configure SSL for each bind line.
2524
     * Note: if configuration fails at some point, the ->ctx member
2525
     * remains NULL so that listeners can later detach.
2526
     */
2527
0
    list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) {
2528
0
      if (bind_conf->xprt->prepare_bind_conf &&
2529
0
          bind_conf->xprt->prepare_bind_conf(bind_conf) < 0)
2530
0
        cfgerr++;
2531
0
      bind_conf->analysers |= curproxy->fe_req_ana;
2532
0
      if (!bind_conf->maxaccept)
2533
0
        bind_conf->maxaccept = global.tune.maxaccept ? global.tune.maxaccept : MAX_ACCEPT;
2534
0
      bind_conf->accept = session_accept_fd;
2535
0
      if (curproxy->options & PR_O_TCP_NOLING)
2536
0
        bind_conf->options |= BC_O_NOLINGER;
2537
2538
      /* smart accept mode is automatic in HTTP mode */
2539
0
      if ((curproxy->options2 & PR_O2_SMARTACC) ||
2540
0
          ((curproxy->mode == PR_MODE_HTTP || (bind_conf->options & BC_O_USE_SSL)) &&
2541
0
           !(curproxy->no_options2 & PR_O2_SMARTACC)))
2542
0
        bind_conf->options |= BC_O_NOQUICKACK;
2543
0
    }
2544
2545
    /* adjust this proxy's listeners */
2546
0
    bind_conf = NULL;
2547
0
    next_id = 1;
2548
0
    list_for_each_entry(listener, &curproxy->conf.listeners, by_fe) {
2549
0
      if (!listener->luid) {
2550
        /* listener ID not set, use automatic numbering with first
2551
         * spare entry starting with next_luid.
2552
         */
2553
0
        if (listener->by_fe.p != &curproxy->conf.listeners) {
2554
0
          struct listener *prev_li = LIST_PREV(&listener->by_fe, typeof(prev_li), by_fe);
2555
0
          if (prev_li->luid)
2556
0
            next_id = prev_li->luid + 1;
2557
0
        }
2558
0
        next_id = listener_get_next_id(curproxy, next_id);
2559
0
        listener->luid = next_id;
2560
0
        listener_index_id(curproxy, listener);
2561
0
      }
2562
0
      next_id++;
2563
2564
      /* enable separate counters */
2565
0
      if (curproxy->options2 & PR_O2_SOCKSTAT) {
2566
0
        listener->counters = calloc(1, sizeof(*listener->counters));
2567
0
        if (!listener->name)
2568
0
          memprintf(&listener->name, "sock-%d", listener->luid);
2569
0
      }
2570
2571
#ifdef USE_QUIC
2572
      if (listener->bind_conf->xprt == xprt_get(XPRT_QUIC)) {
2573
        /* quic_conn are counted against maxconn. */
2574
        listener->bind_conf->options |= BC_O_XPRT_MAXCONN;
2575
        listener->rx.quic_curr_handshake = 0;
2576
        listener->rx.quic_curr_accept = 0;
2577
2578
# ifdef USE_QUIC_OPENSSL_COMPAT
2579
        /* store the last checked bind_conf in bind_conf */
2580
        if (!(quic_tune.fe.opts & QUIC_TUNE_FE_LISTEN_OFF) &&
2581
            !(global.tune.options & GTUNE_LIMITED_QUIC) &&
2582
            listener->bind_conf != bind_conf) {
2583
          bind_conf = listener->bind_conf;
2584
          ha_alert("Binding [%s:%d] for %s %s: this SSL library does not support the "
2585
             "QUIC protocol. A limited compatibility layer may be enabled using "
2586
             "the \"limited-quic\" global option if desired.\n",
2587
             listener->bind_conf->file, listener->bind_conf->line,
2588
             proxy_type_str(curproxy), curproxy->id);
2589
          cfgerr++;
2590
        }
2591
# endif
2592
2593
        li_init_per_thr(listener);
2594
      }
2595
#endif
2596
0
    }
2597
2598
    /* Release unused SSL configs */
2599
0
    list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) {
2600
0
      if (!(bind_conf->options & BC_O_USE_SSL) && bind_conf->xprt->destroy_bind_conf)
2601
0
        bind_conf->xprt->destroy_bind_conf(bind_conf);
2602
0
    }
2603
2604
    /* Create the task associated with the proxy. Only necessary
2605
     * for frontend or if a stick-table is defined.
2606
     */
2607
0
    if ((curproxy->cap & PR_CAP_FE) || (curproxy->table && curproxy->table->current)) {
2608
0
      curproxy->task = task_new_anywhere();
2609
0
      if (curproxy->task) {
2610
0
        curproxy->task->context = curproxy;
2611
0
        curproxy->task->process = manage_proxy;
2612
0
      }
2613
0
      else {
2614
0
        ha_alert("Proxy '%s': no more memory when trying to allocate the management task\n",
2615
0
           curproxy->id);
2616
0
        cfgerr++;
2617
0
      }
2618
0
    }
2619
0
  }
2620
2621
  /*
2622
   * We have just initialized the main proxies list
2623
   * we must also configure the log-forward proxies list
2624
   */
2625
0
  if (init_proxies_list == proxies_list) {
2626
0
    init_proxies_list = cfg_log_forward;
2627
    /* check if list is not null to avoid infinite loop */
2628
0
    if (init_proxies_list)
2629
0
      goto init_proxies_list_stage2;
2630
0
  }
2631
2632
0
  if (init_proxies_list == cfg_log_forward) {
2633
0
    init_proxies_list = sink_proxies_list;
2634
    /* check if list is not null to avoid infinite loop */
2635
0
    if (init_proxies_list)
2636
0
      goto init_proxies_list_stage2;
2637
0
  }
2638
2639
  /*
2640
   * Recount currently required checks.
2641
   */
2642
2643
0
  for (curproxy=proxies_list; curproxy; curproxy=curproxy->next) {
2644
0
    int optnum;
2645
2646
0
    for (optnum = 0; cfg_opts[optnum].name; optnum++)
2647
0
      if (curproxy->options & cfg_opts[optnum].val)
2648
0
        global.last_checks |= cfg_opts[optnum].checks;
2649
2650
0
    for (optnum = 0; cfg_opts2[optnum].name; optnum++)
2651
0
      if (curproxy->options2 & cfg_opts2[optnum].val)
2652
0
        global.last_checks |= cfg_opts2[optnum].checks;
2653
0
  }
2654
2655
0
  if (cfg_peers) {
2656
0
    struct peers *curpeers = cfg_peers, **last;
2657
0
    struct peer *p, *pb;
2658
2659
    /* Remove all peers sections which don't have a valid listener,
2660
     * which are not used by any table, or which are bound to more
2661
     * than one process.
2662
     */
2663
0
    last = &cfg_peers;
2664
0
    while (*last) {
2665
0
      struct peer *peer;
2666
0
      struct stktable *t;
2667
0
      curpeers = *last;
2668
2669
0
      if (curpeers->disabled) {
2670
        /* the "disabled" keyword was present */
2671
0
        if (curpeers->peers_fe)
2672
0
          stop_proxy(curpeers->peers_fe);
2673
0
        curpeers->peers_fe = NULL;
2674
0
      }
2675
0
      else if (!curpeers->peers_fe || !curpeers->peers_fe->id) {
2676
0
        ha_warning("Removing incomplete section 'peers %s' (no peer named '%s').\n",
2677
0
             curpeers->id, localpeer);
2678
0
        if (curpeers->peers_fe)
2679
0
          stop_proxy(curpeers->peers_fe);
2680
0
        curpeers->peers_fe = NULL;
2681
0
      }
2682
0
      else {
2683
        /* Initializes the transport layer of the server part of all the peers belonging to
2684
         * <curpeers> section if required.
2685
         * Note that ->srv is used by the local peer of a new process to connect to the local peer
2686
         * of an old process.
2687
         */
2688
0
        p = curpeers->remote;
2689
0
        while (p) {
2690
0
          struct peer *other_peer;
2691
2692
0
          for (other_peer = curpeers->remote; other_peer && other_peer != p; other_peer = other_peer->next) {
2693
0
            if (strcmp(other_peer->id, p->id) == 0) {
2694
0
              ha_alert("Peer section '%s' [%s:%d]: another peer named '%s' was already defined at line %s:%d, please use distinct names.\n",
2695
0
                 curpeers->peers_fe->id,
2696
0
                 p->conf.file, p->conf.line,
2697
0
                 other_peer->id, other_peer->conf.file, other_peer->conf.line);
2698
0
              cfgerr++;
2699
0
              break;
2700
0
            }
2701
0
          }
2702
2703
0
          if (p->srv) {
2704
0
            if (p->srv->use_ssl == 1 && xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->prepare_srv)
2705
0
              cfgerr += xprt_get(XPRT_SSL)->prepare_srv(p->srv);
2706
0
          }
2707
0
          p = p->next;
2708
0
        }
2709
        /* Configure the SSL bindings of the local peer if required. */
2710
0
        if (!LIST_ISEMPTY(&curpeers->peers_fe->conf.bind)) {
2711
0
          struct list *l;
2712
0
          struct bind_conf *bind_conf;
2713
2714
0
          l = &curpeers->peers_fe->conf.bind;
2715
0
          bind_conf = LIST_ELEM(l->n, typeof(bind_conf), by_fe);
2716
2717
0
          if (curpeers->local->srv) {
2718
0
            if (curpeers->local->srv->use_ssl == 1 && !(bind_conf->options & BC_O_USE_SSL)) {
2719
0
              ha_warning("Peers section '%s': local peer have a non-SSL listener and a SSL server configured at line %s:%d.\n",
2720
0
                   curpeers->peers_fe->id, curpeers->local->conf.file, curpeers->local->conf.line);
2721
0
            }
2722
0
            else if (curpeers->local->srv->use_ssl != 1 && (bind_conf->options & BC_O_USE_SSL)) {
2723
0
              ha_warning("Peers section '%s': local peer have a SSL listener and a non-SSL server configured at line %s:%d.\n",
2724
0
                   curpeers->peers_fe->id, curpeers->local->conf.file, curpeers->local->conf.line);
2725
0
            }
2726
0
          }
2727
2728
          /* finish the bind setup */
2729
0
          ret = bind_complete_thread_setup(bind_conf, &err_code);
2730
0
          if (ret != 0) {
2731
0
            cfgerr += ret;
2732
0
            if (err_code & ERR_FATAL)
2733
0
              goto out;
2734
0
          }
2735
2736
0
          if (bind_conf->xprt->prepare_bind_conf &&
2737
0
            bind_conf->xprt->prepare_bind_conf(bind_conf) < 0)
2738
0
            cfgerr++;
2739
0
        }
2740
0
        if (!peers_init_sync(curpeers) || !peers_alloc_dcache(curpeers)) {
2741
0
          ha_alert("Peers section '%s': out of memory, giving up on peers.\n",
2742
0
             curpeers->id);
2743
0
          cfgerr++;
2744
0
          break;
2745
0
        }
2746
0
        last = &curpeers->next;
2747
2748
        /* Ignore the peer shard greater than the number of peer shard for this section.
2749
         * Also ignore the peer shard of the local peer.
2750
         */
2751
0
        for (peer = curpeers->remote; peer; peer = peer->next) {
2752
0
          if (peer == curpeers->local) {
2753
0
            if (peer->srv->shard) {
2754
0
              ha_warning("Peers section '%s': shard ignored for '%s' local peer\n",
2755
0
                     curpeers->id, peer->id);
2756
0
              peer->srv->shard = 0;
2757
0
            }
2758
0
          }
2759
0
          else if (peer->srv->shard > curpeers->nb_shards) {
2760
0
            ha_warning("Peers section '%s': shard ignored for '%s' local peer because "
2761
0
                   "%d shard value is greater than the section number of shards (%d)\n",
2762
0
                   curpeers->id, peer->id, peer->srv->shard, curpeers->nb_shards);
2763
0
            peer->srv->shard = 0;
2764
0
          }
2765
0
        }
2766
2767
0
        continue;
2768
0
      }
2769
2770
      /* clean what has been detected above */
2771
0
      p = curpeers->remote;
2772
0
      while (p) {
2773
0
        pb = p->next;
2774
0
        free(p->id);
2775
0
        free(p);
2776
0
        p = pb;
2777
0
      }
2778
2779
      /* Destroy and unlink this curpeers section.
2780
       * Note: curpeers is backed up into *last.
2781
       */
2782
0
      free(curpeers->id);
2783
0
      curpeers = curpeers->next;
2784
      /* Reset any refereance to this peers section in the list of stick-tables */
2785
0
      for (t = stktables_list; t; t = t->next) {
2786
0
        if (t->peers.p && t->peers.p == *last)
2787
0
          t->peers.p = NULL;
2788
0
      }
2789
0
      free(*last);
2790
0
      *last = curpeers;
2791
0
    }
2792
0
  }
2793
2794
0
  for (t = stktables_list; t; t = t->next) {
2795
0
    if (t->proxy)
2796
0
      continue;
2797
0
    err = NULL;
2798
0
    if (!stktable_init(t, &err)) {
2799
0
      ha_alert("Parsing [%s:%d]: failed to initialize '%s' stick-table: %s.\n", t->conf.file, t->conf.line, t->id, err);
2800
0
      ha_free(&err);
2801
0
      cfgerr++;
2802
0
    }
2803
0
  }
2804
2805
  /* initialize stick-tables on backend capable proxies. This must not
2806
   * be done earlier because the data size may be discovered while parsing
2807
   * other proxies.
2808
   */
2809
0
  for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
2810
0
    if ((curproxy->flags & PR_FL_DISABLED) || !curproxy->table)
2811
0
      continue;
2812
2813
0
    err = NULL;
2814
0
    if (!stktable_init(curproxy->table, &err)) {
2815
0
      ha_alert("Proxy '%s': failed to initialize stick-table: %s.\n", curproxy->id, err);
2816
0
      ha_free(&err);
2817
0
      cfgerr++;
2818
0
    }
2819
0
  }
2820
2821
0
  if (mailers) {
2822
0
    struct mailers *curmailers = mailers, **last;
2823
0
    struct mailer *m, *mb;
2824
2825
    /* Remove all mailers sections which don't have a valid listener.
2826
     * This can happen when a mailers section is never referenced.
2827
     */
2828
0
    last = &mailers;
2829
0
    while (*last) {
2830
0
      curmailers = *last;
2831
0
      if (curmailers->users) {
2832
0
        last = &curmailers->next;
2833
0
        continue;
2834
0
      }
2835
2836
0
      ha_warning("Removing incomplete section 'mailers %s'.\n",
2837
0
           curmailers->id);
2838
2839
0
      m = curmailers->mailer_list;
2840
0
      while (m) {
2841
0
        mb = m->next;
2842
0
        free(m->id);
2843
0
        free(m);
2844
0
        m = mb;
2845
0
      }
2846
2847
      /* Destroy and unlink this curmailers section.
2848
       * Note: curmailers is backed up into *last.
2849
       */
2850
0
      free(curmailers->id);
2851
0
      curmailers = curmailers->next;
2852
0
      free(*last);
2853
0
      *last = curmailers;
2854
0
    }
2855
0
  }
2856
2857
  /* Update server_state_file_name to backend name if backend is supposed to use
2858
   * a server-state file locally defined and none has been provided */
2859
0
  for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
2860
0
    if (curproxy->load_server_state_from_file == PR_SRV_STATE_FILE_LOCAL &&
2861
0
        curproxy->server_state_file_name == NULL)
2862
0
      curproxy->server_state_file_name = strdup(curproxy->id);
2863
0
  }
2864
2865
0
  list_for_each_entry(curr_resolvers, &sec_resolvers, list) {
2866
0
    if (LIST_ISEMPTY(&curr_resolvers->nameservers)) {
2867
0
      ha_warning("resolvers '%s' [%s:%d] has no nameservers configured!\n",
2868
0
           curr_resolvers->id, curr_resolvers->conf.file,
2869
0
           curr_resolvers->conf.line);
2870
0
      err_code |= ERR_WARN;
2871
0
    }
2872
0
  }
2873
2874
0
  list_for_each_entry(postparser, &postparsers, list) {
2875
0
    if (postparser->func)
2876
0
      cfgerr += postparser->func();
2877
0
  }
2878
2879
0
  if (experimental_directives_allowed &&
2880
0
      !(get_tainted() & TAINTED_CONFIG_EXP_KW_DECLARED)) {
2881
0
    ha_warning("Option 'expose-experimental-directives' is set in the global section but is "
2882
0
               "no longer used. It is strongly recommended to remove it in order to avoid "
2883
0
               "using an experimental directive by accident in the future.\n");
2884
0
    err_code |= ERR_WARN;
2885
0
  }
2886
2887
0
  if (cfgerr > 0)
2888
0
    err_code |= ERR_ALERT | ERR_FATAL;
2889
0
 out:
2890
0
  return err_code;
2891
0
}
2892
2893
/*
2894
 * Registers the CFG keyword list <kwl> as a list of valid keywords for next
2895
 * parsing sessions.
2896
 */
2897
void cfg_register_keywords(struct cfg_kw_list *kwl)
2898
0
{
2899
0
  LIST_APPEND(&cfg_keywords.list, &kwl->list);
2900
0
}
2901
2902
/*
2903
 * Unregisters the CFG keyword list <kwl> from the list of valid keywords.
2904
 */
2905
void cfg_unregister_keywords(struct cfg_kw_list *kwl)
2906
0
{
2907
0
  LIST_DELETE(&kwl->list);
2908
0
  LIST_INIT(&kwl->list);
2909
0
}
2910
2911
/* this function register new section in the haproxy configuration file.
2912
 * <section_name> is the name of this new section and <section_parser>
2913
 * is the called parser. If two section declaration have the same name,
2914
 * only the first declared is used.
2915
 */
2916
int cfg_register_section(char *section_name,
2917
                         int (*section_parser)(const char *, int, char **, int),
2918
                         int (*post_section_parser)())
2919
0
{
2920
0
  struct cfg_section *cs;
2921
2922
0
  if (section_parser) {
2923
    /* only checks if we register a section parser, not a post section callback */
2924
0
    list_for_each_entry(cs, &sections, list) {
2925
0
      if (strcmp(cs->section_name, section_name) == 0 && cs->section_parser) {
2926
0
        ha_alert("register section '%s': already registered.\n", section_name);
2927
0
        return 0;
2928
0
      }
2929
0
    }
2930
0
  }
2931
2932
0
  cs = calloc(1, sizeof(*cs));
2933
0
  if (!cs) {
2934
0
    ha_alert("register section '%s': out of memory.\n", section_name);
2935
0
    return 0;
2936
0
  }
2937
2938
0
  cs->section_name = section_name;
2939
0
  cs->section_parser = section_parser;
2940
0
  cs->post_section_parser = post_section_parser;
2941
2942
0
  LIST_APPEND(&sections, &cs->list);
2943
2944
0
  return 1;
2945
0
}
2946
2947
/* this function register a new function which will be called once the haproxy
2948
 * configuration file has been parsed. It's useful to check dependencies
2949
 * between sections or to resolve items once everything is parsed.
2950
 */
2951
int cfg_register_postparser(char *name, int (*func)())
2952
0
{
2953
0
  struct cfg_postparser *cp;
2954
2955
0
  cp = calloc(1, sizeof(*cp));
2956
0
  if (!cp) {
2957
0
    ha_alert("register postparser '%s': out of memory.\n", name);
2958
0
    return 0;
2959
0
  }
2960
0
  cp->name = name;
2961
0
  cp->func = func;
2962
2963
0
  LIST_APPEND(&postparsers, &cp->list);
2964
2965
0
  return 1;
2966
0
}
2967
2968
/*
2969
 * free all config section entries
2970
 */
2971
void cfg_unregister_sections(void)
2972
0
{
2973
0
  struct cfg_section *cs, *ics;
2974
2975
0
  list_for_each_entry_safe(cs, ics, &sections, list) {
2976
0
    LIST_DELETE(&cs->list);
2977
0
    free(cs);
2978
0
  }
2979
0
}
2980
2981
void cfg_backup_sections(struct list *backup_sections)
2982
0
{
2983
0
  struct cfg_section *cs, *ics;
2984
2985
0
  list_for_each_entry_safe(cs, ics, &sections, list) {
2986
0
    LIST_DELETE(&cs->list);
2987
0
    LIST_APPEND(backup_sections, &cs->list);
2988
0
  }
2989
0
}
2990
2991
void cfg_restore_sections(struct list *backup_sections)
2992
0
{
2993
0
  struct cfg_section *cs, *ics;
2994
2995
0
  list_for_each_entry_safe(cs, ics, backup_sections, list) {
2996
0
    LIST_DELETE(&cs->list);
2997
0
    LIST_APPEND(&sections, &cs->list);
2998
0
  }
2999
0
}
3000
3001
/* dumps all registered keywords by section on stdout */
3002
void cfg_dump_registered_keywords()
3003
0
{
3004
  /*                             CFG_GLOBAL, CFG_LISTEN, CFG_USERLIST, CFG_PEERS, CFG_CRTLIST, CFG_CRTSTORE, CFG_TRACES, CFG_ACME */
3005
0
  const char* sect_names[] = { "", "global", "listen", "userlist", "peers", "crt-list", "crt-store", "traces", "acme", 0 };
3006
0
  int section;
3007
0
  int index;
3008
3009
0
  for (section = 1; sect_names[section]; section++) {
3010
0
    struct cfg_kw_list *kwl;
3011
0
    const struct cfg_keyword *kwp, *kwn;
3012
3013
0
    printf("%s\n", sect_names[section]);
3014
3015
0
    for (kwn = kwp = NULL;; kwp = kwn) {
3016
0
      list_for_each_entry(kwl, &cfg_keywords.list, list) {
3017
0
        for (index = 0; kwl->kw[index].kw != NULL; index++)
3018
0
          if (kwl->kw[index].section == section &&
3019
0
              strordered(kwp ? kwp->kw : NULL, kwl->kw[index].kw, kwn != kwp ? kwn->kw : NULL))
3020
0
            kwn = &kwl->kw[index];
3021
0
      }
3022
0
      if (kwn == kwp)
3023
0
        break;
3024
0
      printf("\t%s\n", kwn->kw);
3025
0
    }
3026
3027
0
    if (section == CFG_LISTEN) {
3028
      /* there are plenty of other keywords there */
3029
0
      extern struct list tcp_req_conn_keywords, tcp_req_sess_keywords,
3030
0
        tcp_req_cont_keywords, tcp_res_cont_keywords;
3031
0
      extern struct bind_kw_list bind_keywords;
3032
0
      extern struct srv_kw_list srv_keywords;
3033
0
      struct bind_kw_list *bkwl;
3034
0
      struct srv_kw_list *skwl;
3035
0
      const struct bind_kw *bkwp, *bkwn;
3036
0
      const struct srv_kw *skwp, *skwn;
3037
0
      const struct cfg_opt *coptp, *coptn;
3038
3039
      /* display the non-ssl keywords */
3040
0
      for (bkwn = bkwp = NULL;; bkwp = bkwn) {
3041
0
        list_for_each_entry(bkwl, &bind_keywords.list, list) {
3042
0
          if (strcmp(bkwl->scope, "SSL") == 0) /* skip SSL keywords */
3043
0
            continue;
3044
0
          for (index = 0; bkwl->kw[index].kw != NULL; index++) {
3045
0
            if (strordered(bkwp ? bkwp->kw : NULL,
3046
0
                     bkwl->kw[index].kw,
3047
0
                     bkwn != bkwp ? bkwn->kw : NULL))
3048
0
              bkwn = &bkwl->kw[index];
3049
0
          }
3050
0
        }
3051
0
        if (bkwn == bkwp)
3052
0
          break;
3053
3054
0
        if (!bkwn->skip)
3055
0
          printf("\tbind <addr> %s\n", bkwn->kw);
3056
0
        else
3057
0
          printf("\tbind <addr> %s +%d\n", bkwn->kw, bkwn->skip);
3058
0
      }
3059
#if defined(USE_OPENSSL)
3060
      /* displays the "ssl" keywords */
3061
      for (bkwn = bkwp = NULL;; bkwp = bkwn) {
3062
        list_for_each_entry(bkwl, &bind_keywords.list, list) {
3063
          if (strcmp(bkwl->scope, "SSL") != 0) /* skip non-SSL keywords */
3064
            continue;
3065
          for (index = 0; bkwl->kw[index].kw != NULL; index++) {
3066
            if (strordered(bkwp ? bkwp->kw : NULL,
3067
                           bkwl->kw[index].kw,
3068
                           bkwn != bkwp ? bkwn->kw : NULL))
3069
              bkwn = &bkwl->kw[index];
3070
          }
3071
        }
3072
        if (bkwn == bkwp)
3073
          break;
3074
3075
        if (strcmp(bkwn->kw, "ssl") == 0) /* skip "bind <addr> ssl ssl" */
3076
          continue;
3077
3078
        if (!bkwn->skip)
3079
          printf("\tbind <addr> ssl %s\n", bkwn->kw);
3080
        else
3081
          printf("\tbind <addr> ssl %s +%d\n", bkwn->kw, bkwn->skip);
3082
      }
3083
#endif
3084
0
      for (skwn = skwp = NULL;; skwp = skwn) {
3085
0
        list_for_each_entry(skwl, &srv_keywords.list, list) {
3086
0
          for (index = 0; skwl->kw[index].kw != NULL; index++)
3087
0
            if (strordered(skwp ? skwp->kw : NULL,
3088
0
                     skwl->kw[index].kw,
3089
0
                     skwn != skwp ? skwn->kw : NULL))
3090
0
              skwn = &skwl->kw[index];
3091
0
        }
3092
0
        if (skwn == skwp)
3093
0
          break;
3094
3095
0
        if (!skwn->skip)
3096
0
          printf("\tserver <name> <addr> %s\n", skwn->kw);
3097
0
        else
3098
0
          printf("\tserver <name> <addr> %s +%d\n", skwn->kw, skwn->skip);
3099
0
      }
3100
3101
0
      for (coptn = coptp = NULL;; coptp = coptn) {
3102
0
        for (index = 0; cfg_opts[index].name; index++)
3103
0
          if (strordered(coptp ? coptp->name : NULL,
3104
0
                   cfg_opts[index].name,
3105
0
                   coptn != coptp ? coptn->name : NULL))
3106
0
            coptn = &cfg_opts[index];
3107
3108
0
        for (index = 0; cfg_opts2[index].name; index++)
3109
0
          if (strordered(coptp ? coptp->name : NULL,
3110
0
                   cfg_opts2[index].name,
3111
0
                   coptn != coptp ? coptn->name : NULL))
3112
0
            coptn = &cfg_opts2[index];
3113
0
        if (coptn == coptp)
3114
0
          break;
3115
3116
0
        printf("\toption %s [ ", coptn->name);
3117
0
        if (coptn->cap & PR_CAP_FE)
3118
0
          printf("FE ");
3119
0
        if (coptn->cap & PR_CAP_BE)
3120
0
          printf("BE ");
3121
0
        if (coptn->mode == PR_MODE_HTTP)
3122
0
          printf("HTTP ");
3123
0
        printf("]\n");
3124
0
      }
3125
3126
0
      dump_act_rules(&tcp_req_conn_keywords,        "\ttcp-request connection ");
3127
0
      dump_act_rules(&tcp_req_sess_keywords,        "\ttcp-request session ");
3128
0
      dump_act_rules(&tcp_req_cont_keywords,        "\ttcp-request content ");
3129
0
      dump_act_rules(&tcp_res_cont_keywords,        "\ttcp-response content ");
3130
0
      dump_act_rules(&http_req_keywords.list,       "\thttp-request ");
3131
0
      dump_act_rules(&http_res_keywords.list,       "\thttp-response ");
3132
0
      dump_act_rules(&http_after_res_keywords.list, "\thttp-after-response ");
3133
0
    }
3134
0
    if (section == CFG_PEERS) {
3135
0
      struct peers_kw_list *pkwl;
3136
0
      const struct peers_keyword *pkwp, *pkwn;
3137
0
      for (pkwn = pkwp = NULL;; pkwp = pkwn) {
3138
0
        list_for_each_entry(pkwl, &peers_keywords.list, list) {
3139
0
          for (index = 0; pkwl->kw[index].kw != NULL; index++) {
3140
0
            if (strordered(pkwp ? pkwp->kw : NULL,
3141
0
                           pkwl->kw[index].kw,
3142
0
                           pkwn != pkwp ? pkwn->kw : NULL))
3143
0
              pkwn = &pkwl->kw[index];
3144
0
          }
3145
0
        }
3146
0
        if (pkwn == pkwp)
3147
0
          break;
3148
0
        printf("\t%s\n", pkwn->kw);
3149
0
      }
3150
0
    }
3151
0
    if (section == CFG_CRTLIST) {
3152
      /* displays the keyword available for the crt-lists */
3153
0
      extern struct ssl_crtlist_kw ssl_crtlist_kws[] __maybe_unused;
3154
0
      const struct ssl_crtlist_kw *sbkwp __maybe_unused, *sbkwn __maybe_unused;
3155
3156
#if defined(USE_OPENSSL)
3157
      for (sbkwn = sbkwp = NULL;; sbkwp = sbkwn) {
3158
        for (index = 0; ssl_crtlist_kws[index].kw != NULL; index++) {
3159
          if (strordered(sbkwp ? sbkwp->kw : NULL,
3160
                   ssl_crtlist_kws[index].kw,
3161
                   sbkwn != sbkwp ? sbkwn->kw : NULL))
3162
            sbkwn = &ssl_crtlist_kws[index];
3163
        }
3164
        if (sbkwn == sbkwp)
3165
          break;
3166
        if (!sbkwn->skip)
3167
          printf("\t%s\n", sbkwn->kw);
3168
        else
3169
          printf("\t%s +%d\n", sbkwn->kw, sbkwn->skip);
3170
      }
3171
#endif
3172
3173
0
    }
3174
0
  }
3175
0
}
3176
3177
/* these are the config sections handled by default */
3178
REGISTER_CONFIG_SECTION("listen",         cfg_parse_listen,    NULL);
3179
REGISTER_CONFIG_SECTION("frontend",       cfg_parse_listen,    NULL);
3180
REGISTER_CONFIG_SECTION("backend",        cfg_parse_listen,    NULL);
3181
REGISTER_CONFIG_SECTION("defaults",       cfg_parse_listen,    NULL);
3182
REGISTER_CONFIG_SECTION("global",         cfg_parse_global,    NULL);
3183
REGISTER_CONFIG_SECTION("userlist",       cfg_parse_users,     NULL);
3184
REGISTER_CONFIG_SECTION("mailers",        cfg_parse_mailers,   NULL);
3185
REGISTER_CONFIG_SECTION("namespace_list", cfg_parse_netns,     NULL);
3186
REGISTER_CONFIG_SECTION("traces",         cfg_parse_traces,    NULL);
3187
3188
static struct cfg_kw_list cfg_kws = {{ },{
3189
  { CFG_GLOBAL, "default-path",     cfg_parse_global_def_path },
3190
  { CFG_USERLIST, "group", cfg_parse_users_group },
3191
  { CFG_USERLIST, "user", cfg_parse_users_user },
3192
  { /* END */ }
3193
}};
3194
3195
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
3196
3197
/*
3198
 * Local variables:
3199
 *  c-indent-level: 8
3200
 *  c-basic-offset: 8
3201
 * End:
3202
 */