Skip to content
This repository
Browse code

Merge pull request #69 from bfg/config_file

Added configuration file support.
  • Loading branch information...
commit 8cff14c941795ef2ee2b7a7c329ec7b685c50c40 2 parents 17918b7 + 8f8c65b
Jamie Turner authored February 24, 2012
6  .gitignore
... ...
@@ -1,2 +1,6 @@
1  
-conf*
  1
+conf
2 2
 ebtree*
  3
+core
  4
+core.*
  5
+*.o
  6
+stud
7  Makefile
@@ -9,7 +9,7 @@ MANDIR  = $(PREFIX)/share/man
9 9
 
10 10
 CFLAGS  = -O2 -g -std=c99 -fno-strict-aliasing -Wall -W -D_GNU_SOURCE
11 11
 LDFLAGS = -lssl -lcrypto -lev
12  
-OBJS    = stud.o ringbuffer.o
  12
+OBJS    = stud.o ringbuffer.o configuration.o
13 13
 
14 14
 all: realall
15 15
 
@@ -28,6 +28,11 @@ ebtree:
28 28
 		exit 1 )
29 29
 endif
30 30
 
  31
+# No config file support?
  32
+ifneq ($(NO_CONFIG_FILE),)
  33
+CFLAGS += -DNO_CONFIG_FILE
  34
+endif
  35
+
31 36
 ALL += stud
32 37
 realall: $(ALL)
33 38
 
1,178  configuration.c
... ...
@@ -0,0 +1,1178 @@
  1
+/**
  2
+ * configuration.c
  3
+ *
  4
+ * Author: Brane F. Gracnar
  5
+ */
  6
+
  7
+#include <stdio.h>
  8
+#include <string.h>
  9
+#include <errno.h>
  10
+#include <stdarg.h>
  11
+#include <stdlib.h>
  12
+#include <ctype.h>
  13
+#include <unistd.h>
  14
+#include <getopt.h>
  15
+#include <libgen.h>
  16
+#include <sys/types.h>
  17
+#include <pwd.h>
  18
+#include <grp.h>
  19
+#include <sys/stat.h>
  20
+
  21
+#include "configuration.h"
  22
+#include "version.h"
  23
+
  24
+#define ADDR_LEN 150
  25
+#define PORT_LEN 6
  26
+#define CFG_BOOL_ON "on"
  27
+
  28
+// BEGIN: configuration parameters
  29
+#define CFG_CIPHERS "ciphers"
  30
+#define CFG_SSL_ENGINE "ssl-engine"
  31
+#define CFG_PREFER_SERVER_CIPHERS "prefer-server-ciphers"
  32
+#define CFG_BACKEND "backend"
  33
+#define CFG_FRONTEND "frontend"
  34
+#define CFG_WORKERS "workers"
  35
+#define CFG_BACKLOG "backlog"
  36
+#define CFG_KEEPALIVE "keepalive"
  37
+#define CFG_CHROOT "chroot"
  38
+#define CFG_USER "user"
  39
+#define CFG_GROUP "group"
  40
+#define CFG_QUIET "quiet"
  41
+#define CFG_SYSLOG "syslog"
  42
+#define CFG_DAEMON "daemon"
  43
+#define CFG_WRITE_IP "write-ip"
  44
+#define CFG_WRITE_PROXY "write-proxy"
  45
+#define CFG_PEM_FILE "pem-file"
  46
+
  47
+#ifdef USE_SHARED_CACHE
  48
+  #define CFG_SHARED_CACHE "shared-cache"
  49
+  #define CFG_SHARED_CACHE_LISTEN "shared-cache-listen"
  50
+  #define CFG_SHARED_CACHE_PEER "shared-cache-peer"
  51
+  #define CFG_SHARED_CACHE_MCASTIF "shared-cache-if"
  52
+#endif
  53
+
  54
+#ifndef NO_CONFIG_FILE
  55
+  #define FMT_STR "%s = %s\n"
  56
+  #define FMT_QSTR "%s = \"%s\"\n"
  57
+  #define FMT_ISTR "%s = %d\n"
  58
+  
  59
+  #define CONFIG_MAX_LINES 10000
  60
+  #define CONFIG_BUF_SIZE 1024
  61
+  #define CFG_PARAM_CFGFILE 10000
  62
+  #define CFG_PARAM_DEFCFG 10001
  63
+
  64
+  #define CFG_CONFIG "config"
  65
+  #define CFG_CONFIG_DEFAULT "default-config"
  66
+#endif
  67
+// END: configuration parameters
  68
+
  69
+static char var_buf[CONFIG_BUF_SIZE];
  70
+static char val_buf[CONFIG_BUF_SIZE];
  71
+static char error_buf[CONFIG_BUF_SIZE];
  72
+static char tmp_buf[150];
  73
+
  74
+// for testing configuration only
  75
+SSL_CTX * init_openssl();
  76
+
  77
+static void config_error_set (char *fmt, ...) {
  78
+  memset(error_buf, '\0', sizeof(error_buf));
  79
+  va_list args;
  80
+  va_start(args, fmt);
  81
+  vsnprintf(error_buf, (sizeof(error_buf) - 1), fmt, args);
  82
+  va_end(args);
  83
+}
  84
+
  85
+char * config_error_get (void) {
  86
+  return error_buf;
  87
+}
  88
+
  89
+void config_die (char *fmt, ...) {
  90
+  va_list args;
  91
+  va_start(args, fmt);
  92
+  vfprintf(stderr, fmt, args);
  93
+  va_end(args);
  94
+  fprintf(stderr, "\n");
  95
+
  96
+  exit(1);
  97
+}
  98
+
  99
+stud_config * config_new (void) {
  100
+  stud_config *r = NULL;
  101
+  r = malloc(sizeof(stud_config));
  102
+  if (r == NULL) {
  103
+    config_error_set("Unable to allocate memory for configuration structure: %s", strerror(errno));
  104
+    return NULL;
  105
+  }
  106
+  
  107
+  // set default values
  108
+
  109
+  r->ETYPE              = ENC_TLS;
  110
+  r->WRITE_IP_OCTET     = 0;
  111
+  r->WRITE_PROXY_LINE   = 0;
  112
+  r->CHROOT             = NULL;
  113
+  r->UID                = 0;
  114
+  r->GID                = 0;
  115
+  r->FRONT_IP           = NULL;
  116
+  r->FRONT_PORT         = strdup("8443");
  117
+  r->BACK_IP            = strdup("127.0.0.1");
  118
+  r->BACK_PORT          = strdup("8000");
  119
+  r->NCORES             = 1;
  120
+  r->CERT_FILE          = NULL;
  121
+  r->CIPHER_SUITE       = NULL;
  122
+  r->ENGINE             = NULL;
  123
+  r->BACKLOG            = 100;
  124
+
  125
+#ifdef USE_SHARED_CACHE
  126
+  r->SHARED_CACHE       = 0;
  127
+  r->SHCUPD_IP          = NULL;
  128
+  r->SHCUPD_PORT        = NULL;
  129
+  
  130
+  for (int i = 0 ; i < MAX_SHCUPD_PEERS; i++)
  131
+    memset(&r->SHCUPD_PEERS[i], 0, sizeof(shcupd_peer_opt));
  132
+  
  133
+  r->SHCUPD_MCASTIF     = NULL;
  134
+  r->SHCUPD_MCASTTTL    = NULL;
  135
+#endif
  136
+
  137
+  r->QUIET              = 0;
  138
+  r->SYSLOG             = 0;
  139
+  r->TCP_KEEPALIVE_TIME = 3600;
  140
+  r->DAEMONIZE          = 0;
  141
+  r->PREFER_SERVER_CIPHERS = 0;
  142
+
  143
+  return r;
  144
+}
  145
+
  146
+void config_destroy (stud_config *cfg) {
  147
+  // printf("config_destroy() in pid %d: %p\n", getpid(), cfg);
  148
+  if (cfg == NULL) return;
  149
+
  150
+  // free all members!
  151
+  if (cfg->CHROOT != NULL) free(cfg->CHROOT);
  152
+  if (cfg->FRONT_IP != NULL) free(cfg->FRONT_IP);
  153
+  if (cfg->FRONT_PORT != NULL) free(cfg->FRONT_PORT);
  154
+  if (cfg->BACK_IP != NULL) free(cfg->BACK_IP);
  155
+  if (cfg->BACK_PORT != NULL) free(cfg->BACK_PORT);
  156
+  if (cfg->CERT_FILE != NULL) free(cfg->CERT_FILE);
  157
+  if (cfg->CIPHER_SUITE != NULL) free(cfg->CIPHER_SUITE);
  158
+  if (cfg->ENGINE != NULL) free(cfg->ENGINE);
  159
+
  160
+#ifdef USE_SHARED_CACHE
  161
+  if (cfg->SHCUPD_IP != NULL) free(cfg->SHCUPD_IP);
  162
+  if (cfg->SHCUPD_PORT != NULL) free(cfg->SHCUPD_PORT);
  163
+
  164
+  for (int i = 0; i < MAX_SHCUPD_PEERS; i++) {
  165
+    if (cfg->SHCUPD_PEERS[i].ip != NULL)
  166
+      free(cfg->SHCUPD_PEERS[i].ip);
  167
+    if (cfg->SHCUPD_PEERS[i].port != NULL)
  168
+      free(cfg->SHCUPD_PEERS[i].port);    
  169
+  }
  170
+
  171
+  if (cfg->SHCUPD_MCASTIF != NULL) free(cfg->SHCUPD_MCASTIF);
  172
+  if (cfg->SHCUPD_MCASTTTL != NULL) free(cfg->SHCUPD_MCASTTTL);
  173
+#endif
  174
+
  175
+  free(cfg);
  176
+}
  177
+
  178
+char * config_get_param (char *str) {
  179
+  char *ptr;
  180
+  int i;
  181
+
  182
+  if (str == NULL) return NULL;
  183
+  /** empty string? */
  184
+  if (strlen(str) < 1 || str[0] == '\n' || strcmp(str, "\r\n") == 0) return NULL;
  185
+
  186
+  ptr = str;
  187
+
  188
+  /** comments? */
  189
+  if (str[0] == '#') return NULL;
  190
+  /** first alpha character */
  191
+  while (ptr != NULL && ! isalpha(*ptr))
  192
+    ptr++;
  193
+
  194
+  /** overwrite alpha chars */
  195
+  memset(var_buf, '\0', sizeof(var_buf));
  196
+  i = 0;
  197
+  while(ptr != NULL && (isalnum(*ptr) || *ptr == '-')) {
  198
+    var_buf[i] = *ptr;
  199
+    i++;
  200
+    ptr++;
  201
+  }
  202
+
  203
+  if (strlen(var_buf) < 1) return NULL;
  204
+  return var_buf;
  205
+}
  206
+
  207
+char * config_get_value (char *str) {
  208
+  char *ptr;
  209
+  int i = 0;
  210
+
  211
+  if (str == NULL) return NULL;
  212
+  if (strlen(str) < 1) return NULL;
  213
+
  214
+  /** find '=' char */
  215
+  ptr = str;
  216
+  while (ptr != NULL && (*ptr) != '=')
  217
+    ptr++;
  218
+  ptr++;
  219
+
  220
+  /** skip whitespaces **/
  221
+  while (ptr != NULL && ! isgraph(*ptr))
  222
+    ptr++;
  223
+
  224
+  /** no value found? */
  225
+  if (ptr == NULL) return NULL;
  226
+
  227
+  /** overwrite alpha chars */
  228
+  memset(val_buf, '\0', sizeof(val_buf));
  229
+  while(ptr != NULL && isgraph(*ptr)) {
  230
+    val_buf[i++] = *ptr;
  231
+    ptr++;
  232
+  }
  233
+
  234
+  if (strlen(val_buf) < 1) return NULL;
  235
+  return val_buf;
  236
+}
  237
+
  238
+char * str_rtrim(char *str) {
  239
+  char *ptr;
  240
+  int   len;
  241
+ 
  242
+  len = strlen(str);
  243
+  ptr = str + len - 1;
  244
+  while (ptr >= str && (isspace((int)*ptr ) || (char) *ptr == '"' || (char) *ptr == '\'')) --ptr;
  245
+ 
  246
+  ptr[1] = '\0';
  247
+ 
  248
+  return str;
  249
+}
  250
+ 
  251
+char * str_ltrim(char *str) {
  252
+  char *ptr;
  253
+  int  len;
  254
+ 
  255
+  for (ptr = str; (*ptr && (isspace((int)*ptr) || (char) *ptr == '"' || (char) *ptr == '\'')); ++ptr);
  256
+ 
  257
+  len = strlen(ptr);
  258
+  memmove(str, ptr, len + 1);
  259
+ 
  260
+  return str;
  261
+}
  262
+ 
  263
+char * str_trim(char *str) {
  264
+  char *ptr;
  265
+  ptr = str_rtrim(str);
  266
+  str = str_ltrim(ptr);
  267
+  return str;
  268
+}
  269
+
  270
+char * config_assign_str (char **dst, char *v) {
  271
+  if (*dst == NULL) {
  272
+    if (v != NULL && strlen(v) > 0)
  273
+      *dst = strdup(v);
  274
+  } else {
  275
+    if (v != NULL && strlen(v) > 0) {
  276
+      // we assume that there is enough room for v in *dst
  277
+      memset(*dst, '\0', strlen(v) + 1);
  278
+      memcpy(*dst, v, strlen(v));
  279
+    }
  280
+    else
  281
+      free(*dst);
  282
+  }
  283
+  return *dst;
  284
+}
  285
+
  286
+int config_param_val_bool (char *val, int *res) {
  287
+  if (val == NULL) return 0;
  288
+  if (
  289
+    strcasecmp(val, CFG_BOOL_ON) == 0 ||
  290
+    strcasecmp(val, "yes") == 0 ||
  291
+    strcasecmp(val, "y") == 0 ||
  292
+    strcasecmp(val, "true") == 0 ||
  293
+    strcasecmp(val, "t") == 0 ||
  294
+    strcasecmp(val, "1") == 0) {
  295
+    *res = 1;
  296
+  }
  297
+  
  298
+  return 1;
  299
+}
  300
+
  301
+char * config_param_val_str (char *val) {
  302
+  return strdup(val);
  303
+}
  304
+
  305
+int config_param_host_port_wildcard (char *str, char **addr, char **port, int wildcard_okay) {
  306
+  int len = (str != NULL) ? strlen(str) : 0;
  307
+  if (str == NULL || ! len) {
  308
+    config_error_set("Invalid/unset host/port string.");
  309
+    return 0;
  310
+  }
  311
+
  312
+  // address/port buffers
  313
+  char port_buf[PORT_LEN];
  314
+  char addr_buf[ADDR_LEN];
  315
+  
  316
+  memset(port_buf, '\0', sizeof(port_buf));
  317
+  memset(addr_buf, '\0', sizeof(addr_buf));
  318
+  
  319
+  // NEW FORMAT: [address]:port
  320
+  if (*str == '[') {
  321
+    char *ptr = str + 1;
  322
+    char *x = strrchr(ptr, ']');
  323
+    if (x == NULL) {
  324
+      config_error_set("Invalid address '%s'.", str);
  325
+      return 0;
  326
+    }
  327
+    
  328
+    // address
  329
+    memcpy(addr_buf, ptr, (x - ptr));
  330
+    
  331
+    // port
  332
+    x += 2;
  333
+    memcpy(port_buf, x, sizeof(port_buf) - 1);
  334
+  }
  335
+  // OLD FORMAT: address,port
  336
+  else {
  337
+    char *x = strrchr(str, ',');
  338
+    if (x == NULL) {
  339
+      config_error_set("Invalid address string '%s'", str);
  340
+      return 0;
  341
+    }
  342
+    // addr
  343
+    int addr_len = x - str;
  344
+    memcpy(addr_buf, str, addr_len);
  345
+    // port
  346
+    memcpy(port_buf, (++x), sizeof(port_buf));
  347
+  }
  348
+  
  349
+  // printf("PARSED ADDR '%s', PORT '%s'\n", addr_buf, port_buf);
  350
+  
  351
+  // check port
  352
+  int p = atoi(port_buf);
  353
+  if (p < 1 || p > 65536) {
  354
+    config_error_set("Invalid port number '%s'", port_buf);
  355
+    return 0;
  356
+  }
  357
+  
  358
+  // write
  359
+  if (strcmp(addr_buf, "*") == 0) {
  360
+    if (wildcard_okay)
  361
+      free(*addr);
  362
+    else {
  363
+      config_error_set("Invalid address: wildcards are not allowed.");
  364
+      return 0;
  365
+    }
  366
+  } else {
  367
+    //if (*addr != NULL) free(*addr);
  368
+    *addr = strdup(addr_buf);
  369
+  }
  370
+  // if (**port != NULL) free(*port);
  371
+  *port = strdup(port_buf);
  372
+  
  373
+  // printf("ADDR FINAL: '%s', '%s'\n", *addr, *port);
  374
+  
  375
+  return 1;
  376
+}
  377
+
  378
+int config_param_host_port (char *str, char **addr, char **port) {
  379
+  return config_param_host_port_wildcard(str, addr, port, 0);
  380
+}
  381
+
  382
+int config_param_val_int (char *str, int *dst) {
  383
+  *dst = (str != NULL) ? atoi(str) : 0;
  384
+  return 1;
  385
+}
  386
+
  387
+int config_param_val_int_pos (char *str, int *dst) {
  388
+  int num = 0;
  389
+  if (str != NULL)
  390
+    num = atoi(str);
  391
+  
  392
+  if (num < 1) {
  393
+    config_error_set("Not a positive number.");
  394
+    return 0;
  395
+  }
  396
+  
  397
+  *dst = num;
  398
+  return 1;
  399
+}
  400
+
  401
+int config_param_val_intl (char *str, long int *dst) {
  402
+  *dst = (str != NULL) ? atol(str) : 0;
  403
+  return 1;
  404
+}
  405
+
  406
+int config_param_val_intl_pos (char *str, long int *dst) {
  407
+  long int num = 0;
  408
+  if (str != NULL)
  409
+    num = atol(str);
  410
+  
  411
+  if (num < 1) {
  412
+    config_error_set("Not a positive number.");
  413
+    return 0;
  414
+  }
  415
+  
  416
+  *dst = num;
  417
+  return 1;
  418
+}
  419
+
  420
+#ifdef USE_SHARED_CACHE
  421
+/* Parse mcast and ttl options */
  422
+int config_param_shcupd_mcastif (char *str, char **iface, char **ttl) {
  423
+    char buf[150];
  424
+    char *sp;
  425
+
  426
+    if (strlen(str) >= sizeof buf) {
  427
+      config_error_set("Invalid option for IFACE[,TTL]");
  428
+      return 0;
  429
+    }
  430
+
  431
+    sp = strchr(str, ',');
  432
+    if (!sp) {
  433
+        if (!strcmp(str, "*"))
  434
+            *iface = NULL;
  435
+        else
  436
+            *iface = str;
  437
+        *ttl = NULL;
  438
+        return 1;
  439
+    }
  440
+    else if (!strncmp(str, "*", sp - str)) {
  441
+        *iface = NULL;
  442
+    }
  443
+    else {
  444
+        *sp = 0;
  445
+        *iface = str;
  446
+    }
  447
+    *ttl = sp + 1;
  448
+    
  449
+    return 1;
  450
+}
  451
+
  452
+int config_param_shcupd_peer (char *str, stud_config *cfg) {
  453
+  if (cfg == NULL) {
  454
+    config_error_set("Configuration pointer is NULL.");
  455
+    return 0;
  456
+  }
  457
+  
  458
+  // parse result
  459
+  int r = 1;
  460
+
  461
+  // find place for new peer
  462
+  int offset = 0;
  463
+  int i = 0;
  464
+  for (i = 0; i < MAX_SHCUPD_PEERS; i++) {
  465
+    if (cfg->SHCUPD_PEERS[i].ip == NULL && cfg->SHCUPD_PEERS[i].port == NULL) {
  466
+      offset = i;
  467
+      break;
  468
+    }
  469
+  }
  470
+  if (i >= MAX_SHCUPD_PEERS) {
  471
+    config_error_set(
  472
+      "Reached maximum number of shared cache update peers (%d).",
  473
+      MAX_SHCUPD_PEERS
  474
+    );
  475
+    return 0;
  476
+  }
  477
+  
  478
+  // create place for new peer
  479
+  char *addr = malloc(ADDR_LEN);
  480
+  if (addr == NULL) {
  481
+    config_error_set(
  482
+      "Unable to allocate memory for new shared cache update peer address: %s",
  483
+      strerror(errno)
  484
+    );
  485
+    r = 0;
  486
+    goto outta_parse_peer;
  487
+  }
  488
+  memset(addr, '\0', ADDR_LEN);
  489
+  char *port = malloc(PORT_LEN);
  490
+  if (port == NULL) {
  491
+    config_error_set(
  492
+      "Unable to allocate memory for new shared cache update peer port: %s",
  493
+      strerror(errno)
  494
+    );
  495
+    r = 0;
  496
+    goto outta_parse_peer;
  497
+  }
  498
+  memset(port, '\0', PORT_LEN);
  499
+  
  500
+  // try to parse address
  501
+  if (! config_param_host_port(str, &addr, &port)) {
  502
+    r = 0;
  503
+    goto outta_parse_peer;
  504
+  }
  505
+  
  506
+  outta_parse_peer:
  507
+
  508
+  if (! r) {
  509
+    if (addr != NULL) free(addr);
  510
+    if (port != NULL) free(port);
  511
+  } else {
  512
+    cfg->SHCUPD_PEERS[offset].ip = addr;
  513
+    cfg->SHCUPD_PEERS[offset].port = port;
  514
+  }
  515
+  
  516
+  return r;
  517
+}
  518
+
  519
+#endif /* USE_SHARED_CACHE */
  520
+
  521
+void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int line) {
  522
+  int r = 1;
  523
+  struct stat st;
  524
+      
  525
+  if (strcmp(k, "tls") == 0) {
  526
+    //cfg->ENC_TLS = 1;
  527
+  }
  528
+  else if (strcmp(k, "ssl") == 0) {
  529
+    //cfg->ENC_TLS = 0;
  530
+  }
  531
+  else if (strcmp(k, CFG_CIPHERS) == 0) {
  532
+    if (v != NULL && strlen(v) > 0) {
  533
+      config_assign_str(&cfg->CIPHER_SUITE, v);
  534
+    }
  535
+  }
  536
+  else if (strcmp(k, CFG_SSL_ENGINE) == 0) {
  537
+    if (v != NULL && strlen(v) > 0) {
  538
+      config_assign_str(&cfg->ENGINE, v);
  539
+    }
  540
+  }
  541
+  else if (strcmp(k, CFG_PREFER_SERVER_CIPHERS) == 0) {
  542
+    r = config_param_val_bool(v, &cfg->PREFER_SERVER_CIPHERS);
  543
+  }
  544
+  else if (strcmp(k, CFG_FRONTEND) == 0) {
  545
+    r = config_param_host_port_wildcard(v, &cfg->FRONT_IP, &cfg->FRONT_PORT, 1);
  546
+  }
  547
+  else if (strcmp(k, CFG_BACKEND) == 0) {
  548
+    r = config_param_host_port(v, &cfg->BACK_IP, &cfg->BACK_PORT);
  549
+  }
  550
+  else if (strcmp(k, CFG_WORKERS) == 0) {
  551
+    r = config_param_val_intl_pos(v, &cfg->NCORES);
  552
+  }
  553
+  else if (strcmp(k, CFG_BACKLOG) == 0) {
  554
+    r = config_param_val_int(v, &cfg->BACKLOG);
  555
+    if (r && cfg->BACKLOG < -1) cfg->BACKLOG = -1;
  556
+  }
  557
+  else if (strcmp(k, CFG_KEEPALIVE) == 0) {
  558
+    r = config_param_val_int_pos(v, &cfg->TCP_KEEPALIVE_TIME);
  559
+  }
  560
+#ifdef USE_SHARED_CACHE
  561
+  else if (strcmp(k, CFG_SHARED_CACHE) == 0) {
  562
+    r = config_param_val_int(v, &cfg->SHARED_CACHE);
  563
+  }
  564
+  else if (strcmp(k, CFG_SHARED_CACHE_LISTEN) == 0) {
  565
+    if (v != NULL && strlen(v) > 0)
  566
+      r = config_param_host_port_wildcard(v, &cfg->SHCUPD_IP, &cfg->SHCUPD_PORT, 1);
  567
+  }
  568
+  else if (strcmp(k, CFG_SHARED_CACHE_PEER) == 0) {
  569
+    r = config_param_shcupd_peer(v, cfg);
  570
+  }
  571
+  else if (strcmp(k, CFG_SHARED_CACHE_MCASTIF) == 0) {
  572
+    r = config_param_shcupd_mcastif(v, &cfg->SHCUPD_MCASTIF, &cfg->SHCUPD_MCASTTTL);
  573
+  }
  574
+#endif
  575
+  else if (strcmp(k, CFG_CHROOT) == 0) {
  576
+    if (v != NULL && strlen(v) > 0) {
  577
+      // check directory
  578
+      if (stat(v, &st) != 0) {
  579
+        config_error_set("Unable to stat directory '%s': %s'.", v, strerror(errno));
  580
+        r = 0;
  581
+      } else {
  582
+        if (! S_ISDIR(st.st_mode)) {
  583
+          config_error_set("Bad chroot directory '%s': Not a directory.", v, strerror(errno));
  584
+          r = 0;
  585
+        } else {
  586
+          config_assign_str(&cfg->CHROOT, v);
  587
+        }
  588
+      }
  589
+    }
  590
+  }
  591
+  else if (strcmp(k, CFG_USER) == 0) {
  592
+    if (v != NULL && strlen(v) > 0) {
  593
+      struct passwd *passwd;
  594
+      passwd = getpwnam(v);
  595
+      if (!passwd) {
  596
+        config_error_set("Invalid user '%s'.", v);
  597
+        r = 0;
  598
+      } else {
  599
+        cfg->UID = passwd->pw_uid;
  600
+        cfg->GID = passwd->pw_gid;    
  601
+      }
  602
+    }
  603
+  }
  604
+  else if (strcmp(k, CFG_GROUP) == 0) {
  605
+    if (v != NULL && strlen(v) > 0) {
  606
+      struct group *grp;
  607
+      grp = getgrnam(v);
  608
+      if (!grp) {
  609
+        config_error_set("Invalid group '%s'.", v);
  610
+        r = 0;
  611
+      } else {
  612
+        cfg->GID = grp->gr_gid;    
  613
+      }
  614
+    }
  615
+  }
  616
+  else if (strcmp(k, CFG_QUIET) == 0) {
  617
+    r = config_param_val_bool(v, &cfg->QUIET);
  618
+  }
  619
+  else if (strcmp(k, CFG_SYSLOG) == 0) {
  620
+    r = config_param_val_bool(v, &cfg->SYSLOG);
  621
+  }
  622
+  else if (strcmp(k, CFG_DAEMON) == 0) {
  623
+    r = config_param_val_bool(v, &cfg->DAEMONIZE);
  624
+  }
  625
+  else if (strcmp(k, CFG_WRITE_IP) == 0) {
  626
+    r = config_param_val_bool(v, &cfg->WRITE_IP_OCTET);
  627
+  }
  628
+  else if (strcmp(k, CFG_WRITE_PROXY) == 0) {
  629
+    r = config_param_val_bool(v, &cfg->WRITE_PROXY_LINE);
  630
+  }
  631
+  else if (strcmp(k, CFG_PEM_FILE) == 0) {
  632
+    if (v != NULL && strlen(v) > 0) {
  633
+      if (stat(v, &st) != 0) {
  634
+        config_error_set("Unable to stat x509 certificate PEM file '%s': ", v, strerror(errno));
  635
+        r = 0;
  636
+      }
  637
+      else if (! S_ISREG(st.st_mode)) {
  638
+        config_error_set("Invalid x509 certificate PEM file '%s': Not a file.", v);
  639
+        r = 0;        
  640
+      } else
  641
+        config_assign_str(&cfg->CERT_FILE, v);
  642
+    }
  643
+  }
  644
+  else {
  645
+    fprintf(
  646
+      stderr,
  647
+      "Ignoring unknown configuration key '%s' in configuration file '%s', line %d\n",
  648
+      k, file, line
  649
+    );
  650
+  }
  651
+  
  652
+  if (! r) {
  653
+    if (file != NULL)
  654
+      config_die("Error in configuration file '%s', line %d: %s\n", file, line, config_error_get()); 
  655
+    else
  656
+      config_die("Invalid parameter '%s': %s", k, config_error_get());
  657
+  }
  658
+}
  659
+
  660
+#ifndef NO_CONFIG_FILE
  661
+int config_file_parse (char *file, stud_config *cfg) {
  662
+  if (cfg == NULL)
  663
+    config_die("Undefined stud options; THIS IS A BUG!\n");
  664
+  
  665
+  char line[CONFIG_BUF_SIZE];
  666
+  FILE *fd = NULL;
  667
+
  668
+  // should we read stdin?
  669
+  if (file == NULL || strlen(file) < 1 || strcmp(file, "-") == 0) {
  670
+    fd = stdin;
  671
+  } else {
  672
+    fd = fopen(file, "r");
  673
+  }
  674
+  if (fd == NULL)
  675
+      config_die("Unable to open configuration file '%s': %s\n", file, strerror(errno));
  676
+
  677
+  // read config
  678
+  int i = 0;
  679
+  while (i < CONFIG_MAX_LINES) {
  680
+    memset(line, '\0', sizeof(line));
  681
+    if (fgets(line, (sizeof(line) - 1), fd) == NULL) break;
  682
+    i++;
  683
+    
  684
+    // get configuration key
  685
+    char *key, *val;
  686
+    key = config_get_param(line);
  687
+    if (key == NULL) continue;
  688
+    
  689
+    // get configuration key value...
  690
+    val = config_get_value(line);
  691
+    if (val == NULL) continue;
  692
+    str_trim(val);
  693
+    
  694
+    // printf("File '%s', line %d, key: '%s', value: '%s'\n", file, i, key, val);
  695
+    
  696
+    // validate configuration key => value
  697
+    config_param_validate(key, val, cfg, file, i);
  698
+  }
  699
+
  700
+  fclose(fd);
  701
+  
  702
+  return 1;
  703
+}
  704
+#endif /* NO_CONFIG_FILE */
  705
+
  706
+char * config_disp_str (char *str) {
  707
+  return (str == NULL) ? "" : str;
  708
+}
  709
+
  710
+char * config_disp_bool (int v) {
  711
+  return (v > 0) ? CFG_BOOL_ON : "off";
  712
+}
  713
+
  714
+char * config_disp_uid (uid_t uid) {
  715
+  memset(tmp_buf, '\0', sizeof(tmp_buf));
  716
+  if (uid == 0 && geteuid() != 0) return tmp_buf;
  717
+  struct passwd *pw = getpwuid(uid);
  718
+  if (pw) {
  719
+    memcpy(tmp_buf, pw->pw_name, strlen(pw->pw_name));
  720
+  }
  721
+  return tmp_buf;
  722
+}
  723
+
  724
+char * config_disp_gid (gid_t gid) {
  725
+  memset(tmp_buf, '\0', sizeof(tmp_buf));
  726
+  if (gid == 0 && geteuid() != 0) return tmp_buf;
  727
+  struct group *gr = getgrgid(gid);
  728
+  if (gr) {
  729
+    memcpy(tmp_buf, gr->gr_name, strlen(gr->gr_name));
  730
+  }
  731
+  return tmp_buf;  
  732
+}
  733
+
  734
+char * config_disp_hostport (char *host, char *port) {
  735
+  memset(tmp_buf, '\0', sizeof(tmp_buf));
  736
+  if (host == NULL && port == NULL)
  737
+    return "";
  738
+
  739
+  strcat(tmp_buf, "[");
  740
+  if (host == NULL)
  741
+    strcat(tmp_buf, "*");
  742
+  else {
  743
+    strncat(tmp_buf, host, 40);
  744
+  }
  745
+  strcat(tmp_buf, "]:");
  746
+  strncat(tmp_buf, port, 5);
  747
+  return tmp_buf;
  748
+}
  749
+
  750
+void config_print_usage_fd (char *prog, stud_config *cfg, FILE *out) {
  751
+  if (out == NULL) out = stderr;
  752
+  fprintf(out, "Usage: %s [OPTIONS] PEM\n\n", basename(prog));
  753
+  fprintf(out, "This is stud, The Scalable TLS Unwrapping Daemon.\n\n");
  754
+#ifndef NO_CONFIG_FILE
  755
+  fprintf(out, "CONFIGURATION:\n");
  756
+  fprintf(out, "\n");
  757
+  fprintf(out, "        --config=FILE      Load configuration from specified file.\n");
  758
+  fprintf(out, "        --default-config   Prints default configuration to stdout.\n");
  759
+  fprintf(out, "\n");
  760
+#endif
  761
+  fprintf(out, "ENCRYPTION METHODS:\n");
  762
+  fprintf(out, "\n");
  763
+  fprintf(out, "      --tls                   TLSv1 (default)\n");
  764
+  fprintf(out, "      --ssl                   SSLv3 (implies no TLSv1)\n");
  765
+  fprintf(out, "  -c  --ciphers=SUITE         Sets allowed ciphers (Default: \"%s\")\n", config_disp_str(cfg->CIPHER_SUITE));
  766
+  fprintf(out, "  -e  --ssl-engine=NAME       Sets OpenSSL engine (Default: \"%s\")\n", config_disp_str(cfg->ENGINE));
  767
+  fprintf(out, "  -O  --prefer-server-ciphers Prefer server list order\n");
  768
+  fprintf(out, "\n");
  769
+  fprintf(out, "SOCKET:\n");
  770
+  fprintf(out, "\n");
  771
+  fprintf(out, "  -b  --backend=HOST,PORT     Backend [connect] (default is \"%s\")\n", config_disp_hostport(cfg->BACK_IP, cfg->BACK_PORT));
  772
+  fprintf(out, "  -f  --frontend=HOST,PORT    Frontend [bind] (default is \"%s\")\n", config_disp_hostport(cfg->FRONT_IP, cfg->FRONT_PORT));
  773
+
  774
+#ifdef USE_SHARED_CACHE
  775
+  fprintf(out, "\n");
  776
+  fprintf(out, "  -U  --shared-cache-listen=HOST,PORT\n");
  777
+  fprintf(out, "                              Accept cache updates on UDP (Default: \"%s\")\n", config_disp_hostport(cfg->SHCUPD_IP, cfg->SHCUPD_PORT));
  778
+  fprintf(out, "                              NOTE: This option requires enabled SSL session cache.\n");
  779
+  fprintf(out, "  -P  --shared-cache-peer=HOST,PORT\n");
  780
+  fprintf(out, "                              Send cache updates to specified peer\n");
  781
+  fprintf(out, "                              NOTE: This option can be specified multiple times.\n");
  782
+  fprintf(out, "  -M  --shared-cache-if=IFACE[,TTL]\n");
  783
+  fprintf(out, "                              Force iface and ttl to receive and send multicast updates\n");
  784
+#endif
  785
+
  786
+  fprintf(out, "\n");
  787
+  fprintf(out, "PERFORMANCE:\n");
  788
+  fprintf(out, "\n");
  789
+  fprintf(out, "  -n  --workers=NUM          Number of worker processes (Default: %ld)\n", cfg->NCORES);
  790
+  fprintf(out, "  -B  --backlog=NUM          Set listen backlog size (Default: %d)\n", cfg->BACKLOG);
  791
+  fprintf(out, "  -k  --keepalive=SECS       TCP keepalive on client socket (Default: %d)\n", cfg->TCP_KEEPALIVE_TIME);
  792
+
  793
+#ifdef USE_SHARED_CACHE
  794
+  fprintf(out, "  -C  --session-cache=NUM    Enable and set SSL session cache to specified number\n");
  795
+  fprintf(out, "                             of sessions (Default: %d)\n", cfg->SHARED_CACHE);
  796
+#endif
  797
+
  798
+  fprintf(out, "\n");
  799
+  fprintf(out, "SECURITY:\n");
  800
+  fprintf(out, "\n");
  801
+  fprintf(out, "  -r  --chroot=DIR           Sets chroot directory (Default: \"%s\")\n", config_disp_str(cfg->CHROOT));
  802
+  fprintf(out, "  -u  --user=USER            Set uid/gid after binding the socket (Default: \"%s\")\n", config_disp_uid(cfg->UID));
  803
+  fprintf(out, "  -g  --group=GROUP          Set gid after binding the socket (Default: \"%s\")\n", config_disp_gid(cfg->GID));
  804
+  fprintf(out, "\n");
  805
+  fprintf(out, "LOGGING:\n");
  806
+  fprintf(out, "  -q  --quiet                Be quiet; emit only error messages\n");
  807
+  fprintf(out, "  -s  --syslog               Send log message to syslog in addition to stderr/stdout\n");
  808
+  fprintf(out, "\n");
  809
+  fprintf(out, "OTHER OPTIONS:\n");
  810
+  fprintf(out, "      --daemon               Fork into background and become a daemon (Default: %s)\n", config_disp_bool(cfg->DAEMONIZE));
  811
+  fprintf(out, "      --write-ip             Write 1 octet with the IP family followed by the IP\n");
  812
+  fprintf(out, "                             address in 4 (IPv4) or 16 (IPv6) octets little-endian\n");
  813
+  fprintf(out, "                             to backend before the actual data\n");
  814
+  fprintf(out, "                             (Default: %s)\n", config_disp_bool(cfg->WRITE_IP_OCTET));
  815
+  fprintf(out, "      --write-proxy          Write HaProxy's PROXY (IPv4 or IPv6) protocol line\n" );
  816
+  fprintf(out, "                             before actual data\n");
  817
+  fprintf(out, "                             (Default: %s)\n", config_disp_bool(cfg->WRITE_PROXY_LINE));
  818
+  fprintf(out, "\n");
  819
+  fprintf(out, "  -t  --test                 Test configuration and exit\n");
  820
+  fprintf(out, "  -V  --version              Print program version and exit\n");
  821
+  fprintf(out, "  -h  --help                 This help message\n");
  822
+}
  823
+
  824
+#ifndef NO_CONFIG_FILE
  825
+void config_print_default (FILE *fd, stud_config *cfg) {
  826
+  if (fd == NULL) return;
  827
+  fprintf(fd, "#\n");
  828
+  fprintf(fd, "# stud(8), The Scalable TLS Unwrapping Daemon's configuration\n");
  829
+  fprintf(fd, "#\n");
  830
+  fprintf(fd, "\n");
  831
+  fprintf(fd, "# NOTE: all config file parameters can be overriden\n");
  832
+  fprintf(fd, "#       from command line!\n");
  833
+  fprintf(fd, "\n");
  834
+
  835
+  fprintf(fd, "# Listening address. REQUIRED.\n");
  836
+  fprintf(fd, "#\n");
  837
+  fprintf(fd, "# type: string\n");
  838
+  fprintf(fd, "# syntax: [HOST]:PORT\n");
  839
+  fprintf(fd, FMT_QSTR, CFG_FRONTEND, config_disp_hostport(cfg->FRONT_IP, cfg->FRONT_PORT));
  840
+  fprintf(fd, "\n");
  841
+
  842
+  fprintf(fd, "# Upstream server address. REQUIRED.\n");
  843
+  fprintf(fd, "#\n");
  844
+  fprintf(fd, "# type: string\n");
  845
+  fprintf(fd, "# syntax: [HOST]:PORT.\n");
  846
+  fprintf(fd, FMT_QSTR, CFG_BACKEND, config_disp_hostport(cfg->BACK_IP, cfg->BACK_PORT));
  847
+  fprintf(fd, "\n");
  848
+
  849
+  fprintf(fd, "# SSL x509 certificate file. REQUIRED.\n");
  850
+  fprintf(fd, "#\n");
  851
+  fprintf(fd, "# type: string\n");
  852
+  fprintf(fd, FMT_QSTR, CFG_PEM_FILE, config_disp_str(cfg->CERT_FILE));
  853
+  fprintf(fd, "\n");
  854
+  
  855
+  fprintf(fd, "# SSL protocol.\n");
  856
+  fprintf(fd, "#\n");
  857
+  fprintf(fd, "# tls = on\n");
  858
+  fprintf(fd, "# ssl = off\n");
  859
+  fprintf(fd, "\n");
  860
+
  861
+  fprintf(fd, "# List of allowed SSL ciphers.\n");
  862
+  fprintf(fd, "#\n");
  863
+  fprintf(fd, "# Run openssl ciphers for list of available ciphers.\n");
  864
+  fprintf(fd, "# type: string\n");
  865
+  fprintf(fd, FMT_QSTR, CFG_CIPHERS, config_disp_str(cfg->CIPHER_SUITE));
  866
+  fprintf(fd, "\n");
  867
+
  868
+  fprintf(fd, "# Enforce server cipher list order\n");
  869
+  fprintf(fd, "#\n");
  870
+  fprintf(fd, "# type: boolean\n");
  871
+  fprintf(fd, FMT_STR, CFG_PREFER_SERVER_CIPHERS, config_disp_bool(cfg->PREFER_SERVER_CIPHERS));
  872
+  fprintf(fd, "\n");
  873
+
  874
+  fprintf(fd, "# Use specified SSL engine\n");
  875
+  fprintf(fd, "#\n");
  876
+  fprintf(fd, "# type: string\n");
  877
+  fprintf(fd, FMT_QSTR, CFG_SSL_ENGINE, config_disp_str(cfg->ENGINE));
  878
+  fprintf(fd, "\n");
  879
+
  880
+  fprintf(fd, "# Number of worker processes\n");
  881
+  fprintf(fd, "#\n");
  882
+  fprintf(fd, "# type: integer\n");
  883
+  fprintf(fd, FMT_ISTR, CFG_WORKERS, (int) cfg->NCORES);
  884
+  fprintf(fd, "\n");
  885
+
  886
+  fprintf(fd, "# Listen backlog size\n");
  887
+  fprintf(fd, "#\n");
  888
+  fprintf(fd, "# type: integer\n");
  889
+  fprintf(fd, FMT_ISTR, CFG_BACKLOG, cfg->BACKLOG);
  890
+  fprintf(fd, "\n");
  891
+
  892
+  fprintf(fd, "# TCP socket keepalive interval in seconds\n");
  893
+  fprintf(fd, "#\n");
  894
+  fprintf(fd, "# type: integer\n");
  895
+  fprintf(fd, FMT_ISTR, CFG_KEEPALIVE, cfg->TCP_KEEPALIVE_TIME);
  896
+  fprintf(fd, "\n");
  897
+
  898
+#ifdef USE_SHARED_CACHE
  899
+  fprintf(fd, "# SSL session cache size\n");
  900
+  fprintf(fd, "#\n");
  901
+  fprintf(fd, "# type: integer\n");
  902
+  fprintf(fd, FMT_ISTR, CFG_SHARED_CACHE, cfg->SHARED_CACHE);
  903
+  fprintf(fd, "\n");
  904
+  
  905
+  fprintf(fd, "# Accept shared SSL cache updates on specified listener.\n");
  906
+  fprintf(fd, "#\n");
  907
+  fprintf(fd, "# type: string\n");
  908
+  fprintf(fd, "# syntax: [HOST]:PORT\n");
  909
+  fprintf(fd, FMT_QSTR, CFG_SHARED_CACHE_LISTEN, config_disp_hostport(cfg->SHCUPD_IP, cfg->SHCUPD_PORT));
  910
+  fprintf(fd, "\n");
  911
+  
  912
+  fprintf(fd, "# Shared cache peer address.\n");
  913
+  fprintf(fd, "# Multiple stud processes on multiple hosts (host limit: %d)\n", MAX_SHCUPD_PEERS);
  914
+  fprintf(fd, "# can share SSL session cache by sending updates to peers.\n");
  915
+  fprintf(fd, "#\n");
  916
+  fprintf(fd, "# NOTE: This parameter can be specified multiple times in order\n");
  917
+  fprintf(fd, "#       to specify multiple peers.\n");
  918
+  fprintf(fd, "#\n");
  919
+  fprintf(fd, "# type: string\n");
  920
+  fprintf(fd, "# syntax: [HOST]:PORT\n");
  921
+  fprintf(fd, "# " FMT_QSTR, CFG_SHARED_CACHE_PEER, config_disp_hostport(NULL, NULL));
  922
+  for (int i = 0; i < MAX_SHCUPD_PEERS; i++) {
  923
+    if (cfg->SHCUPD_PEERS[i].ip == NULL && cfg->SHCUPD_PEERS[i].port == NULL) break;
  924
+    fprintf(fd, FMT_QSTR, CFG_SHARED_CACHE_PEER, config_disp_hostport(cfg->SHCUPD_PEERS[i].ip, cfg->SHCUPD_PEERS[i].port));
  925
+  }
  926
+  fprintf(fd, "\n");
  927
+
  928
+  fprintf(fd, "# Shared cache interface name and optional TTL\n");
  929
+  fprintf(fd, "#\n");
  930
+  fprintf(fd, "# type: string\n");
  931
+  fprintf(fd, "# syntax: iface[,TTL]\n");
  932
+  fprintf(fd, "# %s = \"%s", CFG_SHARED_CACHE_MCASTIF, config_disp_str(cfg->SHCUPD_MCASTIF));
  933
+  if (cfg->SHCUPD_MCASTTTL != NULL && strlen(cfg->SHCUPD_MCASTTTL) > 0) {
  934
+    fprintf(fd, ",%s", cfg->SHCUPD_MCASTTTL);
  935
+  }
  936
+  fprintf(fd, "\"\n");
  937
+  fprintf(fd, "\n");
  938
+#endif
  939
+
  940
+  fprintf(fd, "# Chroot directory\n");
  941
+  fprintf(fd, "#\n");
  942
+  fprintf(fd, "# type: string\n");
  943
+  fprintf(fd, FMT_QSTR, CFG_CHROOT, config_disp_str(cfg->CHROOT));
  944
+  fprintf(fd, "\n");
  945
+
  946
+  fprintf(fd, "# Set uid after binding a socket\n");
  947
+  fprintf(fd, "#\n");
  948
+  fprintf(fd, "# type: string\n");
  949
+  fprintf(fd, FMT_QSTR, CFG_USER, config_disp_uid(cfg->UID));
  950
+  fprintf(fd, "\n");
  951
+
  952
+  fprintf(fd, "# Set gid after binding a socket\n");
  953
+  fprintf(fd, "#\n");
  954
+  fprintf(fd, "# type: string\n");
  955
+  fprintf(fd, FMT_QSTR, CFG_GROUP, config_disp_gid(cfg->GID));
  956
+  fprintf(fd, "\n");
  957
+
  958
+  fprintf(fd, "# Quiet execution, report only error messages\n");
  959
+  fprintf(fd, "#\n");
  960
+  fprintf(fd, "# type: boolean\n");
  961
+  fprintf(fd, FMT_STR, CFG_QUIET, config_disp_bool(cfg->QUIET));
  962
+  fprintf(fd, "\n");
  963
+
  964
+  fprintf(fd, "# Use syslog for logging\n");
  965
+  fprintf(fd, "#\n");
  966
+  fprintf(fd, "# type: boolean\n");
  967
+  fprintf(fd, FMT_STR, CFG_SYSLOG, config_disp_bool(cfg->SYSLOG));
  968
+  fprintf(fd, "\n");
  969
+
  970
+  fprintf(fd, "# Run as daemon\n");
  971
+  fprintf(fd, "#\n");
  972
+  fprintf(fd, "# type: boolean\n");
  973
+  fprintf(fd, FMT_STR, CFG_DAEMON, config_disp_bool(cfg->DAEMONIZE));
  974
+  fprintf(fd, "\n");
  975
+
  976
+  fprintf(fd, "# Report client address by writing IP before sending data\n");
  977
+  fprintf(fd, "#\n");
  978
+  fprintf(fd, "# NOTE: This option is mutually exclusive with option %s.\n", CFG_WRITE_PROXY);
  979
+  fprintf(fd, "#\n");
  980
+  fprintf(fd, "# type: boolean\n");
  981
+  fprintf(fd, FMT_STR, CFG_WRITE_IP, config_disp_bool(cfg->WRITE_IP_OCTET));
  982
+  fprintf(fd, "\n");
  983
+
  984
+  fprintf(fd, "# Report client address using SENDPROXY protocol, see\n");
  985
+  fprintf(fd, "# http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt\n");
  986
+  fprintf(fd, "# for details.\n");
  987
+  fprintf(fd, "#\n");
  988
+  fprintf(fd, "# NOTE: This option is mutually exclusive with option %s.\n", CFG_WRITE_IP);
  989
+  fprintf(fd, "#\n");
  990
+  fprintf(fd, "# type: boolean\n");
  991
+  fprintf(fd, FMT_STR, CFG_WRITE_PROXY, config_disp_bool(cfg->WRITE_PROXY_LINE));
  992
+  fprintf(fd, "\n");
  993
+
  994
+  fprintf(fd, "# EOF\n");
  995
+}
  996
+#endif /* NO_CONFIG_FILE */
  997
+
  998
+void config_print_usage (char *prog, stud_config *cfg) {
  999
+  config_print_usage_fd(prog, cfg, stdout);
  1000
+}
  1001
+
  1002
+void config_parse_cli(int argc, char **argv, stud_config *cfg) {
  1003
+  static int tls = 0, ssl = 0;
  1004
+  int c;
  1005
+  int test_only = 0;
  1006
+  char *prog;
  1007
+
  1008
+  struct option long_options[] = {
  1009
+#ifndef NO_CONFIG_FILE
  1010
+    { CFG_CONFIG, 1, NULL, CFG_PARAM_CFGFILE },
  1011
+    { CFG_CONFIG_DEFAULT, 0, NULL, CFG_PARAM_DEFCFG },
  1012
+#endif
  1013
+    
  1014
+    { "tls", 0, &tls, 1},
  1015
+    { "ssl", 0, &ssl, 1},    
  1016
+    { CFG_CIPHERS, 1, NULL, 'c' },
  1017
+    { CFG_PREFER_SERVER_CIPHERS, 0, NULL, 'O' },
  1018
+    { CFG_BACKEND, 1, NULL, 'b' },
  1019
+    { CFG_FRONTEND, 1, NULL, 'f' },
  1020
+    { CFG_WORKERS, 1, NULL, 'n' },
  1021
+    { CFG_BACKLOG, 1, NULL, 'B' },
  1022
+#ifdef USE_SHARED_CACHE
  1023
+    { CFG_SHARED_CACHE, 1, NULL, 'C' },
  1024
+    { CFG_SHARED_CACHE_LISTEN, 1, NULL, 'U' },
  1025
+    { CFG_SHARED_CACHE_PEER, 1, NULL, 'P' },
  1026
+    { CFG_SHARED_CACHE_MCASTIF, 1, NULL, 'M' },
  1027
+#endif
  1028
+    { CFG_KEEPALIVE, 1, NULL, 'k' },
  1029
+    { CFG_CHROOT, 1, NULL, 'r' },
  1030
+    { CFG_USER, 1, NULL, 'u' },
  1031
+    { CFG_GROUP, 1, NULL, 'g' },
  1032
+    { CFG_QUIET, 0, NULL, 'q' },
  1033
+    { CFG_SYSLOG, 0, NULL, 's' },
  1034
+    { CFG_DAEMON, 0, &cfg->DAEMONIZE, 1 },
  1035
+    { CFG_WRITE_IP, 0, &cfg->WRITE_IP_OCTET, 1 },
  1036
+    { CFG_WRITE_PROXY, 0, &cfg->WRITE_PROXY_LINE, 1 },
  1037
+ 
  1038
+    { "test", 0, NULL, 't' },
  1039
+    { "version", 0, NULL, 'V' },
  1040
+    { "help", 0, NULL, 'h' },
  1041
+    { 0, 0, 0, 0 }
  1042
+  };
  1043
+
  1044
+  while (1) {
  1045
+    int option_index = 0;
  1046
+    c = getopt_long(
  1047
+      argc, argv,
  1048
+      "c:e:Ob:f:n:B:C:U:P:M:k:r:u:g:qstVh",
  1049
+      long_options, &option_index
  1050
+    );
  1051
+
  1052
+    if (c == -1)
  1053
+      break;
  1054
+
  1055
+    switch (c) {
  1056
+      case 0:
  1057
+        break;
  1058
+#ifndef NO_CONFIG_FILE
  1059
+      case CFG_PARAM_CFGFILE:
  1060
+        if (!config_file_parse(optarg, cfg))
  1061
+          config_die("%s", config_error_get());
  1062
+        break;
  1063
+      case CFG_PARAM_DEFCFG:
  1064
+        config_print_default(stdout, cfg);
  1065
+        exit(0);
  1066
+        break;
  1067
+#endif
  1068
+      case 'c':
  1069
+        config_param_validate(CFG_CIPHERS, optarg, cfg, NULL, 0);
  1070
+        break;
  1071
+      case 'e':
  1072
+        config_param_validate(CFG_SSL_ENGINE, optarg, cfg, NULL, 0);
  1073
+         break;
  1074
+      case 'O':
  1075
+        config_param_validate(CFG_PREFER_SERVER_CIPHERS, CFG_BOOL_ON, cfg, NULL, 0);
  1076
+        break;
  1077
+      case 'b':
  1078
+        config_param_validate(CFG_BACKEND, optarg, cfg, NULL, 0);
  1079
+        break;
  1080
+      case 'f':
  1081
+        config_param_validate(CFG_FRONTEND, optarg, cfg, NULL, 0);
  1082
+        break;
  1083
+      case 'n':
  1084
+        config_param_validate(CFG_WORKERS, optarg, cfg, NULL, 0);
  1085
+        break;
  1086
+      case 'B':
  1087
+        config_param_validate(CFG_BACKLOG, optarg, cfg, NULL, 0);
  1088
+        break;
  1089
+#ifdef USE_SHARED_CACHE
  1090
+      case 'C':
  1091
+        config_param_validate(CFG_SHARED_CACHE, optarg, cfg, NULL, 0);
  1092
+        break;
  1093
+      case 'U':
  1094
+        config_param_validate(CFG_SHARED_CACHE_LISTEN, optarg, cfg, NULL, 0);
  1095
+        break;
  1096
+      case 'P':
  1097
+        config_param_validate(CFG_SHARED_CACHE_PEER, optarg, cfg, NULL, 0); 
  1098
+        break;
  1099
+      case 'M':
  1100
+        config_param_validate(CFG_SHARED_CACHE_MCASTIF, optarg, cfg, NULL, 0);
  1101
+        break;
  1102
+#endif
  1103
+      case 'k':
  1104
+        config_param_validate(CFG_KEEPALIVE, optarg, cfg, NULL, 0);
  1105
+        break;
  1106
+      case 'r':
  1107
+        config_param_validate(CFG_CHROOT, optarg, cfg, NULL, 0);
  1108
+        break;
  1109
+      case 'u':
  1110
+        config_param_validate(CFG_USER, optarg, cfg, NULL, 0);
  1111
+        break;
  1112
+      case 'g':
  1113
+        config_param_validate(CFG_GROUP, optarg, cfg, NULL, 0);
  1114
+        break;
  1115
+      case 'q':
  1116
+        config_param_validate(CFG_QUIET, CFG_BOOL_ON, cfg, NULL, 0);
  1117
+        break;
  1118
+      case 's':
  1119
+        config_param_validate(CFG_SYSLOG, CFG_BOOL_ON, cfg, NULL, 0);
  1120
+        break;
  1121
+      case 't':
  1122
+        test_only = 1;
  1123
+        break;
  1124
+      case 'V':
  1125
+        printf("%s %s\n", basename(argv[0]), STUD_VERSION);
  1126
+        exit(0);
  1127
+        break;
  1128
+      case 'h':
  1129
+        config_print_usage(argv[0], cfg);
  1130
+        exit(0);
  1131
+        break;
  1132
+
  1133
+      default:
  1134
+        config_die("Invalid command line parameters. Run %s --help for instructions.", basename(argv[0]));
  1135
+    }
  1136
+  }
  1137
+  
  1138
+  prog = argv[0];
  1139
+
  1140
+  if (tls && ssl)
  1141
+    config_die("Options --tls and --ssl are mutually exclusive.");
  1142
+  else {
  1143
+    if (ssl)
  1144
+      cfg->ETYPE = ENC_SSL;
  1145
+    else if (tls)
  1146
+      cfg->ETYPE = ENC_TLS;
  1147
+  }
  1148
+
  1149
+  if (cfg->WRITE_IP_OCTET && cfg->WRITE_PROXY_LINE)
  1150
+    config_die("Options --write-ip and --write-proxy are mutually exclusive.");
  1151
+
  1152
+  if (cfg->DAEMONIZE) {
  1153
+    cfg->SYSLOG = 1;
  1154
+    cfg->QUIET = 1;
  1155
+  }
  1156
+
  1157
+#ifdef USE_SHARED_CACHE
  1158
+  if (cfg->SHCUPD_IP != NULL && ! cfg->SHARED_CACHE)
  1159
+    config_die("Shared cache update listener is defined, but shared cache is disabled.");
  1160
+#endif
  1161
+  
  1162
+  // argv leftovers, do we have pem file as an argument?
  1163
+  argc -= optind;
  1164
+  argv += optind;
  1165
+  if (argv != NULL && argv[0] != NULL)
  1166
+    config_param_validate(CFG_PEM_FILE, argv[0], cfg, NULL, 0);
  1167
+  else if (cfg->CERT_FILE == NULL || strlen(cfg->CERT_FILE) < 1)
  1168
+    config_die("No x509 certificate PEM file specified!");
  1169
+  
  1170
+  // was this only a test?
  1171
+  if (test_only) {
  1172
+    fprintf(stderr, "Trying to initialize SSL context with certificate '%s'\n", cfg->CERT_FILE);
  1173
+    if (! init_openssl())
  1174
+      config_die("Error initializing OpenSSL.");
  1175
+    printf("%s configuration looks ok.\n", basename(prog));
  1176
+    exit(0);
  1177
+  }
  1178
+}
67  configuration.h
... ...
@@ -0,0 +1,67 @@
  1
+/**
  2
+ * configuration.h
  3
+ *
  4
+ * Author: Brane F. Gracnar
  5
+ *
  6
+ */
  7
+
  8
+#include <sys/types.h>