1 /*
2 * Copyright (C) 2013-2018 Nikos Mavrogiannopoulos
3 * Copyright (C) 2014, 2015 Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <pwd.h>
27 #include <grp.h>
28 #include <fcntl.h>
29 #include <limits.h>
30 #include <common.h>
31 #include <ip-util.h>
32 #include <c-strcase.h>
33 #include <c-ctype.h>
34 #include <auth/pam.h>
35 #include <acct/pam.h>
36 #include <auth/radius.h>
37 #include <acct/radius.h>
38 #include <auth/plain.h>
39 #include <auth/gssapi.h>
40 #include <auth/openidconnect.h>
41 #include <auth/common.h>
42 #include <sec-mod-sup-config.h>
43 #include <sec-mod-acct.h>
44 #include "inih/ini.h"
45
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <dirent.h>
49 #include <netdb.h>
50 #include <assert.h>
51
52 #include <vpn.h>
53 #include <main.h>
54 #include <tlslib.h>
55 #include <occtl/ctl.h>
56 #include <gnutls/crypto.h>
57 #include "common-config.h"
58
59 #include <getopt.h>
60 #include <snapshot.h>
61
62 #define OLD_DEFAULT_CFG_FILE "/etc/ocserv.conf"
63 #define DEFAULT_CFG_FILE "/usr/local/etc/ocserv/ocserv.conf"
64
65 static void print_version(void);
66
67 static char pid_file[_POSIX_PATH_MAX] = "";
68 static char cfg_file[_POSIX_PATH_MAX] = DEFAULT_CFG_FILE;
69
70 static void archive_cfg(struct list_head *head);
71 static void clear_cfg(struct list_head *head);
72 static void check_cfg(vhost_cfg_st *vhost, vhost_cfg_st *defvhost, unsigned silent);
73
74 #define ERRSTR "error: "
75 #define WARNSTR "warning: "
76 #define NOTESTR "note: "
77
78 #define READ_MULTI_LINE(varname, num) { \
79 if (_add_multi_line_val(pool, &varname, &num, value) < 0) { \
80 fprintf(stderr, ERRSTR"memory\n"); \
81 exit(1); \
82 }}
83
84 #define READ_MULTI_BRACKET_LINE(varname, varname2, num) { \
85 if (varname == NULL || varname2 == NULL) { \
86 num = 0; \
87 varname = talloc_size(pool, sizeof(char*)*DEFAULT_CONFIG_ENTRIES); \
88 varname2 = talloc_size(pool, sizeof(char*)*DEFAULT_CONFIG_ENTRIES); \
89 if (varname == NULL || varname2 == NULL) { \
90 fprintf(stderr, ERRSTR"memory\n"); \
91 exit(1); \
92 } \
93 } \
94 if (num < DEFAULT_CONFIG_ENTRIES) { \
95 char *xp; \
96 varname[num] = talloc_strdup(pool, value); \
97 xp = strchr(varname[num], '['); if (xp != NULL) *xp = 0; \
98 varname2[num] = get_brackets_string1(pool, value); \
99 num++; \
100 varname[num] = NULL; \
101 varname2[num] = NULL; \
102 }}
103
104 #define PREAD_STRING(pool, varname) { \
105 unsigned len = strlen(value); \
106 while(len > 0 && c_isspace(value[len-1])) \
107 len--; \
108 varname = talloc_strndup(pool, value, len); \
109 }
110
111 #define READ_STRING(varname) \
112 PREAD_STRING(pool, varname)
113
114 #define READ_STATIC_STRING(varname) { \
115 strlcpy(varname, value, sizeof(varname)); \
116 }
117
118 #define READ_TF(varname) {\
119 if (c_strcasecmp(value, "true") == 0 || c_strcasecmp(value, "yes") == 0) \
120 varname = 1; \
121 else \
122 varname = 0; \
123 }
124
125 #define READ_NUMERIC(varname) { \
126 varname = strtol(value, NULL, 10); \
127 }
128
129 #define READ_PRIO_TOS(varname) \
130 if (strncmp(value, "0x", 2) == 0) { \
131 varname = strtol(value, NULL, 16); \
132 varname = TOS_PACK(varname); \
133 } else { \
134 varname = strtol(value, NULL, 10); \
135 varname++; \
136 }
137
138 struct snapshot_t * config_snapshot = NULL;
139
140 char ** pam_auth_group_list = NULL;
141 char ** gssapi_auth_group_list = NULL;
142 char ** plain_auth_group_list = NULL;
143 unsigned pam_auth_group_list_size = 0;
144 unsigned gssapi_auth_group_list_size = 0;
145 unsigned plain_auth_group_list_size = 0;
146
147
148 /* Parses the string ::1/prefix, to return prefix
149 * and modify the string to contain the network only.
150 */
extract_prefix(char * network)151 unsigned extract_prefix(char *network)
152 {
153 char *p;
154 unsigned prefix;
155
156 if (network == NULL)
157 return 0;
158
159 p = strchr(network, '/');
160
161 if (p == NULL)
162 return 0;
163
164 prefix = atoi(p+1);
165 *p = 0;
166
167 return prefix;
168 }
169
170 typedef struct auth_types_st {
171 const char *name;
172 unsigned name_size;
173 const struct auth_mod_st *mod;
174 unsigned type;
175 void *(*get_brackets_string)(void *pool, struct perm_cfg_st *config, const char *);
176 } auth_types_st;
177
178 #define NAME(x) (x),(sizeof(x)-1)
179 static auth_types_st avail_auth_types[] =
180 {
181 #ifdef HAVE_PAM
182 {NAME("pam"), &pam_auth_funcs, AUTH_TYPE_PAM, pam_get_brackets_string},
183 #endif
184 #ifdef HAVE_GSSAPI
185 {NAME("gssapi"), &gssapi_auth_funcs, AUTH_TYPE_GSSAPI, gssapi_get_brackets_string},
186 #endif
187 #ifdef HAVE_RADIUS
188 {NAME("radius"), &radius_auth_funcs, AUTH_TYPE_RADIUS, radius_get_brackets_string},
189 #endif
190 {NAME("plain"), &plain_auth_funcs, AUTH_TYPE_PLAIN, plain_get_brackets_string},
191 {NAME("certificate"), NULL, AUTH_TYPE_CERTIFICATE, NULL},
192 #ifdef SUPPORT_OIDC_AUTH
193 {NAME("oidc"), &oidc_auth_funcs, AUTH_TYPE_OIDC, oidc_get_brackets_string},
194 #endif
195 };
196
check_for_duplicate_password_auth(struct perm_cfg_st * config,const char * vhostname,unsigned type)197 static void check_for_duplicate_password_auth(struct perm_cfg_st *config, const char *vhostname, unsigned type)
198 {
199 unsigned i;
200
201 if (type & AUTH_TYPE_USERNAME_PASS) {
202 for (i=0;i<MAX_AUTH_METHODS;i++) {
203 if (config->auth[i].enabled == 0)
204 break;
205 if (config->auth[i].type & AUTH_TYPE_USERNAME_PASS) {
206 fprintf(stderr, ERRSTR"%s: you cannot mix multiple password authentication methods\n", vhostname);
207 exit(1);
208 }
209 }
210 }
211 }
212
figure_auth_funcs(void * pool,const char * vhostname,struct perm_cfg_st * config,char ** auth,unsigned auth_size,unsigned primary)213 static void figure_auth_funcs(void *pool, const char *vhostname,
214 struct perm_cfg_st *config, char **auth, unsigned auth_size,
215 unsigned primary)
216 {
217 unsigned j, i;
218 unsigned found;
219
220 if (auth == NULL)
221 return;
222
223 if (vhostname[0] == 0)
224 vhostname = "vhost:default";
225
226 if (primary != 0) {
227 /* Set the primary authentication methods */
228 for (j=0;j<auth_size;j++) {
229 found = 0;
230 for (i=0;i<sizeof(avail_auth_types)/sizeof(avail_auth_types[0]);i++) {
231 if (c_strncasecmp(auth[j], avail_auth_types[i].name, avail_auth_types[i].name_size) == 0) {
232 if (avail_auth_types[i].get_brackets_string)
233 config->auth[0].additional = avail_auth_types[i].get_brackets_string(pool, config, auth[j]+avail_auth_types[i].name_size);
234
235 if (config->auth[0].amod != NULL && avail_auth_types[i].mod != NULL) {
236 fprintf(stderr, ERRSTR"%s: you cannot mix multiple authentication methods of %s type\n", vhostname, auth[j]);
237 exit(1);
238 }
239
240 if (config->auth[0].amod == NULL)
241 config->auth[0].amod = avail_auth_types[i].mod;
242 config->auth[0].type |= avail_auth_types[i].type;
243 if (config->auth[0].name == NULL) {
244 config->auth[0].name = talloc_strdup(pool, avail_auth_types[i].name);
245 } else {
246 char *tmp;
247 tmp = talloc_asprintf(pool, "%s+%s", config->auth[0].name, avail_auth_types[i].name);
248 talloc_free(config->auth[0].name);
249 config->auth[0].name = tmp;
250 }
251 config->auth[0].enabled = 1;
252 config->auth_methods = 1;
253 found = 1;
254 break;
255 }
256 }
257
258 if (found == 0) {
259 fprintf(stderr, ERRSTR"%s: unknown or unsupported auth method: %s\n", vhostname, auth[j]);
260 exit(1);
261 }
262 talloc_free(auth[j]);
263 }
264 fprintf(stderr, NOTESTR"%s: setting '%s' as primary authentication method\n", vhostname, config->auth[0].name);
265 } else {
266 unsigned x = config->auth_methods;
267 /* Append authentication methods (alternative options) */
268 for (j=0;j<auth_size;j++) {
269 found = 0;
270 for (i=0;i<sizeof(avail_auth_types)/sizeof(avail_auth_types[0]);i++) {
271 if (c_strncasecmp(auth[j], avail_auth_types[i].name, avail_auth_types[i].name_size) == 0) {
272 if (avail_auth_types[i].get_brackets_string)
273 config->auth[x].additional = avail_auth_types[i].get_brackets_string(pool, config, auth[j]+avail_auth_types[i].name_size);
274
275 config->auth[x].name = talloc_strdup(pool, avail_auth_types[i].name);
276 fprintf(stderr, NOTESTR"%s: enabling '%s' as authentication method\n", vhostname, avail_auth_types[i].name);
277
278 check_for_duplicate_password_auth(config, vhostname, avail_auth_types[i].type);
279 config->auth[x].amod = avail_auth_types[i].mod;
280 config->auth[x].type |= avail_auth_types[i].type;
281 config->auth[x].enabled = 1;
282 found = 1;
283 x++;
284 if (x >= MAX_AUTH_METHODS) {
285 fprintf(stderr, ERRSTR"%s: you cannot enable more than %d authentication methods\n", vhostname, x);
286 exit(1);
287 }
288 break;
289 }
290 }
291
292 if (found == 0) {
293 fprintf(stderr, ERRSTR"%s: unknown or unsupported auth method: %s\n", vhostname, auth[j]);
294 exit(1);
295 }
296 talloc_free(auth[j]);
297 }
298 config->auth_methods = x;
299 }
300 talloc_free(auth);
301 }
302
303 typedef struct acct_types_st {
304 const char *name;
305 unsigned name_size;
306 const struct acct_mod_st *mod;
307 void *(*get_brackets_string)(void *pool, struct perm_cfg_st *config, const char *);
308 } acct_types_st;
309
310 static acct_types_st avail_acct_types[] =
311 {
312 #ifdef HAVE_RADIUS
313 {NAME("radius"), &radius_acct_funcs, radius_get_brackets_string},
314 #endif
315 #ifdef HAVE_PAM
316 {NAME("pam"), &pam_acct_funcs, NULL},
317 #endif
318 };
319
figure_acct_funcs(void * pool,const char * vhostname,struct perm_cfg_st * config,const char * acct)320 static void figure_acct_funcs(void *pool, const char *vhostname, struct perm_cfg_st *config, const char *acct)
321 {
322 unsigned i;
323 unsigned found = 0;
324
325 if (acct == NULL)
326 return;
327
328 /* Set the accounting method */
329 for (i=0;i<sizeof(avail_acct_types)/sizeof(avail_acct_types[0]);i++) {
330 if (c_strncasecmp(acct, avail_acct_types[i].name, avail_acct_types[i].name_size) == 0) {
331 if (avail_acct_types[i].mod == NULL)
332 continue;
333
334 if (avail_acct_types[i].get_brackets_string)
335 config->acct.additional = avail_acct_types[i].get_brackets_string(pool, config, acct+avail_acct_types[i].name_size);
336
337 if ((avail_acct_types[i].mod->auth_types & config->auth[0].type) == 0) {
338 fprintf(stderr, ERRSTR"%s: you cannot mix the '%s' accounting method with the '%s' authentication method\n", vhostname, acct, config->auth[0].name);
339 exit(1);
340 }
341
342 config->acct.amod = avail_acct_types[i].mod;
343 config->acct.name = avail_acct_types[i].name;
344 found = 1;
345 break;
346 }
347 }
348
349 if (found == 0) {
350 fprintf(stderr, ERRSTR"%s: unknown or unsupported accounting method: %s\n", vhostname, acct);
351 exit(1);
352 }
353 fprintf(stderr, NOTESTR"%ssetting '%s' as accounting method\n", vhostname, config->acct.name);
354 }
355
356 #ifdef HAVE_GSSAPI
parse_kkdcp(struct cfg_st * config,char ** urlfw,unsigned urlfw_size)357 static void parse_kkdcp(struct cfg_st *config, char **urlfw, unsigned urlfw_size)
358 {
359 unsigned i, j;
360 char *path, *server, *port, *realm;
361 struct addrinfo hints, *res;
362 int ret;
363 struct kkdcp_st *kkdcp;
364 struct kkdcp_realm_st *kkdcp_realm;
365
366 config->kkdcp = talloc_zero_size(config, urlfw_size*sizeof(kkdcp_st));
367 if (config->kkdcp == NULL) {
368 fprintf(stderr, ERRSTR"memory\n");
369 exit(1);
370 }
371
372 config->kkdcp_size = 0;
373
374 for (i=0;i<urlfw_size;i++) {
375 memset(&hints, 0, sizeof(hints));
376
377 parse_kkdcp_string(urlfw[i], &hints.ai_socktype, &port, &server, &path, &realm);
378
379 ret = getaddrinfo(server, port, &hints, &res);
380 if (ret != 0) {
381 fprintf(stderr, ERRSTR"getaddrinfo(%s) failed: %s\n", server,
382 gai_strerror(ret));
383 exit(1);
384 }
385
386 kkdcp = NULL;
387 /* check if the path is already added */
388 for (j=0;j<config->kkdcp_size;j++) {
389 if (strcmp(path, config->kkdcp[j].url) == 0) {
390 kkdcp = &config->kkdcp[j];
391 }
392 }
393
394 if (kkdcp == NULL) {
395 kkdcp = &config->kkdcp[i];
396 kkdcp->url = talloc_strdup(config->kkdcp, path);
397 config->kkdcp_size++;
398 }
399
400 if (kkdcp->realms_size >= MAX_KRB_REALMS) {
401 fprintf(stderr, ERRSTR"reached maximum number (%d) of realms per URL\n", MAX_KRB_REALMS);
402 exit(1);
403 }
404
405 kkdcp_realm = &kkdcp->realms[kkdcp->realms_size];
406
407 memcpy(&kkdcp_realm->addr, res->ai_addr, res->ai_addrlen);
408 kkdcp_realm->addr_len = res->ai_addrlen;
409 kkdcp_realm->ai_family = res->ai_family;
410 kkdcp_realm->ai_socktype = res->ai_socktype;
411 kkdcp_realm->ai_protocol = res->ai_protocol;
412
413 kkdcp_realm->realm = talloc_strdup(config->kkdcp, realm);
414
415 freeaddrinfo(res);
416 kkdcp->realms_size++;
417 }
418
419 }
420 #endif
421
422 struct iroute_ctx {
423 struct cfg_st *config;
424 const char *file;
425 };
426
sanitize_config_value(void * pool,const char * value)427 char *sanitize_config_value(void *pool, const char *value)
428 {
429 ssize_t len = strlen(value);
430 unsigned i = 0;
431
432 while(c_isspace(value[len-1]) || value[len-1] == '"')
433 len--;
434
435 while(c_isspace(value[i]) || value[i] == '"') {
436 i++;
437 len--;
438 }
439
440 if (len < 0)
441 return NULL;
442
443 return talloc_strndup(pool, &value[i], len); \
444
445 }
446
iroutes_handler(void * _ctx,const char * section,const char * name,const char * _value)447 static int iroutes_handler(void *_ctx, const char *section, const char *name, const char* _value)
448 {
449 struct iroute_ctx *ctx = _ctx;
450 int ret;
451 char *value;
452
453 if (section != NULL && section[0] != 0) {
454 fprintf(stderr, WARNSTR"skipping unknown section '%s'\n", section);
455 return 0;
456 }
457
458 if (strcmp(name, "iroute")!=0)
459 return 0;
460
461 value = sanitize_config_value(ctx->config, _value);
462 if (value == NULL)
463 return 0;
464
465 ret = _add_multi_line_val(ctx->config, &ctx->config->known_iroutes,
466 &ctx->config->known_iroutes_size, value);
467 if (ret < 0) {
468 fprintf(stderr, ERRSTR"cannot load iroute from %s\n", ctx->file);
469 }
470
471 talloc_free(value);
472 return 0;
473 }
474
append_iroutes_from_file(struct cfg_st * config,const char * file)475 static void append_iroutes_from_file(struct cfg_st *config, const char *file)
476 {
477 struct iroute_ctx ctx;
478 int ret;
479 unsigned j;
480
481 ctx.file = file;
482 ctx.config = config;
483
484 ret = ini_parse(file, iroutes_handler, &ctx);
485 if (ret != 0)
486 return;
487
488 for (j=0;j<config->known_iroutes_size;j++) {
489 if (ip_route_sanity_check(config->known_iroutes, &config->known_iroutes[j]) != 0)
490 exit(1);
491 }
492
493 return;
494 }
495
load_iroutes(struct cfg_st * config)496 static void load_iroutes(struct cfg_st *config)
497 {
498 DIR *dir;
499 struct dirent *r;
500 int ret;
501 char path[_POSIX_PATH_MAX];
502
503 if (config->per_user_dir == NULL)
504 return;
505
506 dir = opendir(config->per_user_dir);
507 if (dir != NULL) {
508 do {
509 r = readdir(dir);
510 if (r != NULL && r->d_type == DT_REG) {
511 ret = snprintf(path, sizeof(path), "%s/%s", config->per_user_dir, r->d_name);
512 if (ret != (int)strlen(path)) {
513 fprintf(stderr, NOTESTR"path name too long and truncated: %s\n", path);
514 }
515 append_iroutes_from_file(config, path);
516 }
517 } while(r != NULL);
518 closedir(dir);
519 }
520 }
521
apply_default_conf(vhost_cfg_st * vhost,unsigned reload)522 static void apply_default_conf(vhost_cfg_st *vhost, unsigned reload)
523 {
524 /* set config (no-zero) default vals
525 */
526 if (!reload) { /* perm config defaults */
527 tls_vhost_init(vhost);
528 vhost->perm_config.stats_reset_time = 24*60*60*7; /* weekly */
529 }
530
531 vhost->perm_config.config->mobile_idle_timeout = (unsigned)-1;
532 #ifdef ENABLE_COMPRESSION
533 vhost->perm_config.config->no_compress_limit = DEFAULT_NO_COMPRESS_LIMIT;
534 #endif
535 vhost->perm_config.config->rekey_time = 24*60*60;
536 vhost->perm_config.config->cookie_timeout = DEFAULT_COOKIE_RECON_TIMEOUT;
537 vhost->perm_config.config->auth_timeout = DEFAULT_AUTH_TIMEOUT_SECS;
538 vhost->perm_config.config->ban_reset_time = DEFAULT_BAN_RESET_TIME;
539 vhost->perm_config.config->max_ban_score = DEFAULT_MAX_BAN_SCORE;
540 vhost->perm_config.config->ban_points_wrong_password = DEFAULT_PASSWORD_POINTS;
541 vhost->perm_config.config->ban_points_connect = DEFAULT_CONNECT_POINTS;
542 vhost->perm_config.config->ban_points_kkdcp = DEFAULT_KKDCP_POINTS;
543 vhost->perm_config.config->dpd = DEFAULT_DPD_TIME;
544 vhost->perm_config.config->network.ipv6_subnet_prefix = 128;
545 vhost->perm_config.config->dtls_legacy = 1;
546 vhost->perm_config.config->dtls_psk = 1;
547 vhost->perm_config.config->predictable_ips = 1;
548 vhost->perm_config.config->use_utmp = 1;
549 vhost->perm_config.config->keepalive = 3600;
550 vhost->perm_config.config->dpd = 60;
551
552 }
553
cfg_new(struct vhost_cfg_st * vhost,unsigned reload)554 static void cfg_new(struct vhost_cfg_st *vhost, unsigned reload)
555 {
556 vhost->perm_config.config = talloc_zero(vhost->pool, struct cfg_st);
557 if (vhost->perm_config.config == NULL)
558 exit(1);
559
560 vhost->perm_config.config->usage_count = talloc_zero(vhost->perm_config.config, int);
561 if (vhost->perm_config.config->usage_count == NULL) {
562 fprintf(stderr, ERRSTR"memory\n");
563 exit(1);
564 }
565
566 apply_default_conf(vhost, reload);
567 }
568
vhost_add(void * pool,struct list_head * head,const char * name,unsigned reload)569 static vhost_cfg_st *vhost_add(void *pool, struct list_head *head, const char *name, unsigned reload)
570 {
571 vhost_cfg_st *vhost;
572
573 vhost = talloc_zero(pool, struct vhost_cfg_st);
574 if (vhost == NULL)
575 exit(1);
576 vhost->pool = vhost;
577
578 cfg_new(vhost, reload);
579
580 if (name) {
581 vhost->name = talloc_strdup(vhost, name);
582 if (vhost->name == NULL) {
583 fprintf(stderr, ERRSTR"memory\n");
584 exit(1);
585 }
586 }
587
588 vhost->perm_config.sup_config_type = SUP_CONFIG_FILE;
589 list_head_init(&vhost->perm_config.attic);
590
591
592 list_add(head, &vhost->list);
593
594 return vhost;
595 }
596
597 struct ini_ctx_st {
598 struct list_head *head;
599 unsigned reload;
600 const char *file;
601 void *pool;
602 };
603
604 #define WARN_ON_VHOST_ONLY(vname, oname) \
605 ({int rval; \
606 if (vname) { \
607 fprintf(stderr, WARNSTR"%s is ignored on %s virtual host\n", oname, vname); \
608 rval = 1; \
609 } else { \
610 rval = 0; \
611 } \
612 rval; \
613 })
614
615 #define WARN_ON_VHOST(vname, oname, member) \
616 ({int rval; \
617 if (vname) { \
618 fprintf(stderr, WARNSTR"%s is ignored on %s virtual host\n", oname, vname); \
619 memcpy(&config->member, &defvhost->perm_config.config->member, sizeof(config->member)); \
620 rval = 1; \
621 } else { \
622 rval = 0; \
623 } \
624 rval; \
625 })
626
627 #define PWARN_ON_VHOST(vname, oname, member) \
628 ({int rval; \
629 if (vname) { \
630 fprintf(stderr, WARNSTR"%s is ignored on %s virtual host\n", oname, vname); \
631 vhost->perm_config.member = defvhost->perm_config.member; \
632 rval = 1; \
633 } else { \
634 rval = 0; \
635 } \
636 rval; \
637 })
638
639 #define PWARN_ON_VHOST_STRDUP(vname, oname, member) \
640 ({int rval; \
641 if (vname) { \
642 fprintf(stderr, WARNSTR"%s is ignored on %s virtual host\n", oname, vname); \
643 vhost->perm_config.member = talloc_strdup(pool, defvhost->perm_config.member); \
644 rval = 1; \
645 } else { \
646 rval = 0; \
647 } \
648 rval; \
649 })
650
idna_map(void * pool,const char * name,unsigned size)651 static char *idna_map(void *pool, const char *name, unsigned size)
652 {
653 #if GNUTLS_VERSION_NUMBER > 0x030508
654 int ret;
655 gnutls_datum_t out;
656
657 ret = gnutls_idna_map(name, size, &out, 0);
658 if (ret < 0) {
659 goto fallback;
660 }
661
662 return talloc_strdup(pool, (char*)out.data);
663
664 fallback:
665 #endif
666 return talloc_strndup(pool, name, size);
667 }
668
669 static
sanitize_name(void * pool,const char * p)670 char *sanitize_name(void *pool, const char *p)
671 {
672 size_t len;
673 /* cleanup spaces before and after */
674 while (c_isspace(*p))
675 p++;
676
677 len = strlen(p);
678 if (len > 0) {
679 while (c_isspace(p[len-1]))
680 len--;
681 }
682
683 return idna_map(pool, p, len);
684 }
685
cfg_ini_handler(void * _ctx,const char * section,const char * name,const char * _value)686 static int cfg_ini_handler(void *_ctx, const char *section, const char *name, const char *_value)
687 {
688 struct ini_ctx_st *ctx = _ctx;
689 vhost_cfg_st *vhost, *vtmp = NULL, *defvhost;
690 unsigned use_dbus;
691 struct cfg_st *config;
692 void *pool;
693 unsigned reload = ctx->reload;
694 int ret;
695 unsigned stage1_found = 1;
696 unsigned force_cert_auth;
697 unsigned prefix = 0;
698 unsigned prefix4 = 0;
699 unsigned found_vhost;
700 char *value;
701
702 defvhost = vhost = default_vhost(ctx->head);
703
704 assert(defvhost != NULL);
705
706 if (section != NULL && section[0] != 0) {
707 char *vname;
708
709 if (strncmp(section, "vhost:", 6) != 0) {
710 if (reload == 0)
711 fprintf(stderr, WARNSTR"skipping unknown section '%s'\n", section);
712 return 1;
713 }
714
715 vname = sanitize_name(ctx->pool, section+6);
716 if (vname == NULL || vname[0] == 0) {
717 fprintf(stderr, ERRSTR"virtual host name is illegal '%s'\n", section+6);
718 return 0;
719 }
720
721 /* virtual host */
722 found_vhost = 0;
723 list_for_each(ctx->head, vtmp, list) {
724 if (vtmp->name && strcmp(vtmp->name, vname) == 0) {
725 vhost = vtmp;
726 found_vhost = 1;
727 break;
728 }
729 }
730
731 if (c_strcasecmp(section+6, vname) != 0) {
732 fprintf(stderr, NOTESTR"virtual host name '%s' was canonicalized to '%s'\n",
733 section+6, vname);
734 }
735
736 if (!found_vhost) {
737 /* add */
738 fprintf(stderr, NOTESTR"adding virtual host: %s\n", vname);
739 vhost = vhost_add(ctx->pool, ctx->head, vname, reload);
740 }
741 talloc_free(vname);
742 }
743
744 value = sanitize_config_value(vhost->pool, _value);
745 if (value == NULL)
746 return 1;
747
748 /* read persistent configuration */
749 if (vhost->auth_init == 0) {
750 pool = vhost;
751
752 if (strcmp(name, "auth") == 0) {
753 READ_MULTI_LINE(vhost->auth, vhost->auth_size);
754 } else if (strcmp(name, "enable-auth") == 0) {
755 READ_MULTI_LINE(vhost->eauth, vhost->eauth_size);
756 } else if (strcmp(name, "acct") == 0) {
757 vhost->acct = talloc_strdup(pool, value);
758 } else if (strcmp(name, "listen-host") == 0) {
759 PREAD_STRING(pool, vhost->perm_config.listen_host);
760 } else if (strcmp(name, "udp-listen-host") == 0) {
761 PREAD_STRING(pool, vhost->perm_config.udp_listen_host);
762 } else if (strcmp(name, "listen-clear-file") == 0) {
763 fprintf(stderr, ERRSTR"the 'listen-clear-file' option was removed in ocserv 1.1.2\n");
764 return 0;
765 } else if (strcmp(name, "listen-netns") == 0) {
766 vhost->perm_config.listen_netns_name = talloc_strdup(pool, value);
767 } else if (strcmp(name, "tcp-port") == 0) {
768 if (!PWARN_ON_VHOST(vhost->name, "tcp-port", port))
769 READ_NUMERIC(vhost->perm_config.port);
770 } else if (strcmp(name, "udp-port") == 0) {
771 if (!PWARN_ON_VHOST(vhost->name, "udp-port", udp_port))
772 READ_NUMERIC(vhost->perm_config.udp_port);
773 } else if (strcmp(name, "run-as-user") == 0) {
774 if (!PWARN_ON_VHOST(vhost->name, "run-as-user", uid)) {
775 const struct passwd* pwd = getpwnam(value);
776 if (pwd == NULL) {
777 fprintf(stderr, ERRSTR"unknown user: %s\n", value);
778 return 0;
779 }
780 vhost->perm_config.uid = pwd->pw_uid;
781 }
782 } else if (strcmp(name, "run-as-group") == 0) {
783 if (!PWARN_ON_VHOST(vhost->name, "run-as-group", gid)) {
784 const struct group* grp = getgrnam(value);
785 if (grp == NULL) {
786 fprintf(stderr, ERRSTR"unknown group: %s\n", value);
787 return 0;
788 }
789 vhost->perm_config.gid = grp->gr_gid;
790 }
791 } else if (strcmp(name, "server-cert") == 0) {
792 READ_MULTI_LINE(vhost->perm_config.cert, vhost->perm_config.cert_size);
793 } else if (strcmp(name, "server-key") == 0) {
794 READ_MULTI_LINE(vhost->perm_config.key, vhost->perm_config.key_size);
795 } else if (strcmp(name, "debug-no-secmod-stats") == 0) {
796 READ_TF(vhost->perm_config.debug_no_secmod_stats);
797 } else if (strcmp(name, "dh-params") == 0) {
798 READ_STRING(vhost->perm_config.dh_params_file);
799 } else if (strcmp(name, "pin-file") == 0) {
800 READ_STRING(vhost->perm_config.pin_file);
801 } else if (strcmp(name, "srk-pin-file") == 0) {
802 READ_STRING(vhost->perm_config.srk_pin_file);
803 } else if (strcmp(name, "ca-cert") == 0) {
804 READ_STRING(vhost->perm_config.ca);
805 #if !defined(OCSERV_WORKER_PROCESS)
806 } else if (strcmp(name, "key-pin") == 0) {
807 READ_STRING(vhost->perm_config.key_pin);
808 } else if (strcmp(name, "srk-pin") == 0) {
809 READ_STRING(vhost->perm_config.srk_pin);
810 #endif
811 } else if (strcmp(name, "socket-file") == 0) {
812 if (!PWARN_ON_VHOST_STRDUP(vhost->name, "socket-file", socket_file_prefix))
813 PREAD_STRING(pool, vhost->perm_config.socket_file_prefix);
814 } else if (strcmp(name, "occtl-socket-file") == 0) {
815 if (!PWARN_ON_VHOST_STRDUP(vhost->name, "occtl-socket-file", occtl_socket_file))
816 PREAD_STRING(pool, vhost->perm_config.occtl_socket_file);
817 } else if (strcmp(name, "chroot-dir") == 0) {
818 if (!PWARN_ON_VHOST_STRDUP(vhost->name, "chroot-dir", chroot_dir))
819 PREAD_STRING(pool, vhost->perm_config.chroot_dir);
820 } else if (strcmp(name, "server-stats-reset-time") == 0) {
821 /* cannot be modified as it would require sec-mod to
822 * re-read configuration too */
823 if (!PWARN_ON_VHOST(vhost->name, "server-stats-reset-time", stats_reset_time))
824 READ_NUMERIC(vhost->perm_config.stats_reset_time);
825 } else if (strcmp(name, "pid-file") == 0) {
826 if (pid_file[0] == 0) {
827 READ_STATIC_STRING(pid_file);
828 } else if (reload == 0)
829 fprintf(stderr, NOTESTR"skipping 'pid-file' config option\n");
830 } else if (strcmp(name, "sec-mod-scale") == 0) {
831 if (!PWARN_ON_VHOST(vhost->name, "sec-mod-scale", sec_mod_scale))
832 READ_NUMERIC(vhost->perm_config.sec_mod_scale);
833 } else if (strcmp(name, "log-level") == 0) {
834 if (vhost->perm_config.debug == 0) {
835 READ_NUMERIC(vhost->perm_config.debug);
836 }
837 } else {
838 stage1_found = 0;
839 }
840 if (stage1_found)
841 goto exit;
842 }
843
844
845 /* read the rest of the (non-permanent) configuration */
846 pool = vhost->perm_config.config;
847 config = vhost->perm_config.config;
848
849 /* When adding allocated data, remember to modify
850 * reload_cfg_file();
851 */
852 if (strcmp(name, "listen-host-is-dyndns") == 0) {
853 READ_TF(config->is_dyndns);
854 } else if (strcmp(name, "listen-proxy-proto") == 0) {
855 if (!WARN_ON_VHOST(vhost->name, "listen-proxy-proto", listen_proxy_proto))
856 READ_TF(config->listen_proxy_proto);
857 } else if (strcmp(name, "append-routes") == 0) {
858 READ_TF(config->append_routes);
859 #ifdef HAVE_GSSAPI
860 } else if (strcmp(name, "kkdcp") == 0) {
861 READ_MULTI_LINE(vhost->urlfw, vhost->urlfw_size);
862 #endif
863 } else if (strcmp(name, "tunnel-all-dns") == 0) {
864 READ_TF(config->tunnel_all_dns);
865 } else if (strcmp(name, "keepalive") == 0) {
866 READ_NUMERIC(config->keepalive);
867 } else if (strcmp(name, "switch-to-tcp-timeout") == 0) {
868 READ_NUMERIC(config->switch_to_tcp_timeout);
869 } else if (strcmp(name, "dpd") == 0) {
870 READ_NUMERIC(config->dpd);
871 } else if (strcmp(name, "mobile-dpd") == 0) {
872 READ_NUMERIC(config->mobile_dpd);
873 } else if (strcmp(name, "rate-limit-ms") == 0) {
874 if (!WARN_ON_VHOST(vhost->name, "rate-limit-ms", rate_limit_ms))
875 READ_NUMERIC(config->rate_limit_ms);
876 } else if (strcmp(name, "server-drain-ms") == 0) {
877 if (!WARN_ON_VHOST(vhost->name, "server-drain-ms", server_drain_ms))
878 READ_NUMERIC(config->server_drain_ms);
879 } else if (strcmp(name, "ocsp-response") == 0) {
880 READ_STRING(config->ocsp_response);
881 #ifdef ANYCONNECT_CLIENT_COMPAT
882 } else if (strcmp(name, "user-profile") == 0) {
883 READ_STRING(config->xml_config_file);
884 #endif
885 } else if (strcmp(name, "client-bypass-protocol") == 0) {
886 READ_TF(config->client_bypass_protocol);
887 } else if (strcmp(name, "default-domain") == 0) {
888 READ_STRING(config->default_domain);
889 } else if (strcmp(name, "crl") == 0) {
890 READ_STRING(config->crl);
891 } else if (strcmp(name, "cert-user-oid") == 0) {
892 READ_STRING(config->cert_user_oid);
893 } else if (strcmp(name, "cert-group-oid") == 0) {
894 READ_STRING(config->cert_group_oid);
895 } else if (strcmp(name, "connect-script") == 0) {
896 if (!WARN_ON_VHOST(vhost->name, "connect-script", connect_script))
897 READ_STRING(config->connect_script);
898 } else if (strcmp(name, "host-update-script") == 0) {
899 if (!WARN_ON_VHOST(vhost->name, "host-update-script", host_update_script))
900 READ_STRING(config->host_update_script);
901 } else if (strcmp(name, "disconnect-script") == 0) {
902 if (!WARN_ON_VHOST(vhost->name, "disconnect-script", disconnect_script))
903 READ_STRING(config->disconnect_script);
904 } else if (strcmp(name, "session-control") == 0) {
905 fprintf(stderr, WARNSTR"the option 'session-control' is deprecated\n");
906 } else if (strcmp(name, "banner") == 0) {
907 READ_STRING(config->banner);
908 } else if (strcmp(name, "pre-login-banner") == 0) {
909 READ_STRING(config->pre_login_banner);
910 } else if (strcmp(name, "dtls-legacy") == 0) {
911 READ_TF(config->dtls_legacy);
912 } else if (strcmp(name, "cisco-client-compat") == 0) {
913 READ_TF(config->cisco_client_compat);
914 } else if (strcmp(name, "always-require-cert") == 0) {
915 READ_TF(force_cert_auth);
916 if (force_cert_auth == 0) {
917 fprintf(stderr, NOTESTR"'always-require-cert' was replaced by 'cisco-client-compat'\n");
918 config->cisco_client_compat = 1;
919 }
920 } else if (strcmp(name, "dtls-psk") == 0) {
921 if (!WARN_ON_VHOST(vhost->name, "dtls-psk", dtls_psk))
922 READ_TF(config->dtls_psk);
923 } else if (strcmp(name, "match-tls-dtls-ciphers") == 0) {
924 READ_TF(config->match_dtls_and_tls);
925 #ifdef ENABLE_COMPRESSION
926 } else if (strcmp(name, "compression") == 0) {
927 READ_TF(config->enable_compression);
928 } else if (strcmp(name, "compression-algo-priority") == 0) {
929 if (!WARN_ON_VHOST_ONLY(vhost->name, "compression-algo-priority")) {
930 #if defined(OCSERV_WORKER_PROCESS)
931 if (switch_comp_priority(pool, value) == 0) {
932 fprintf(stderr, WARNSTR"invalid compression modstring %s\n", value);
933 }
934 #endif
935 }
936 } else if (strcmp(name, "no-compress-limit") == 0) {
937 READ_NUMERIC(config->no_compress_limit);
938 #endif
939 } else if (strcmp(name, "use-seccomp") == 0) {
940 READ_TF(config->isolate);
941 if (config->isolate)
942 fprintf(stderr, NOTESTR"'use-seccomp' was replaced by 'isolate-workers'\n");
943 } else if (strcmp(name, "isolate-workers") == 0) {
944 if (!WARN_ON_VHOST(vhost->name, "isolate-workers", isolate))
945 READ_TF(config->isolate);
946 } else if (strcmp(name, "predictable-ips") == 0) {
947 READ_TF(config->predictable_ips);
948 } else if (strcmp(name, "use-utmp") == 0) {
949 if (!WARN_ON_VHOST(vhost->name, "use-utmp", use_utmp))
950 READ_TF(config->use_utmp);
951 } else if (strcmp(name, "use-dbus") == 0) {
952 READ_TF(use_dbus);
953 if (use_dbus != 0) {
954 fprintf(stderr, NOTESTR"'use-dbus' was replaced by 'use-occtl'\n");
955 config->use_occtl = use_dbus;
956 }
957 } else if (strcmp(name, "use-occtl") == 0) {
958 if (!WARN_ON_VHOST(vhost->name, "use-occtl", use_occtl))
959 READ_TF(config->use_occtl);
960 } else if (strcmp(name, "try-mtu-discovery") == 0) {
961 if (!WARN_ON_VHOST(vhost->name, "try-mtu-discovery", try_mtu))
962 READ_TF(config->try_mtu);
963 } else if (strcmp(name, "ping-leases") == 0) {
964 if (!WARN_ON_VHOST(vhost->name, "ping_leases", ping_leases))
965 READ_TF(config->ping_leases);
966 } else if (strcmp(name, "restrict-user-to-routes") == 0) {
967 READ_TF(config->restrict_user_to_routes);
968 } else if (strcmp(name, "restrict-user-to-ports") == 0) {
969 ret = cfg_parse_ports(pool, &config->fw_ports, &config->n_fw_ports, value);
970 if (ret < 0) {
971 fprintf(stderr, ERRSTR"cannot parse restrict-user-to-ports\n");
972 return 0;
973 }
974 } else if (strcmp(name, "tls-priorities") == 0) {
975 READ_STRING(config->priorities);
976 } else if (strcmp(name, "mtu") == 0) {
977 READ_NUMERIC(config->default_mtu);
978 } else if (strcmp(name, "net-priority") == 0) {
979 READ_PRIO_TOS(config->net_priority);
980 } else if (strcmp(name, "output-buffer") == 0) {
981 READ_NUMERIC(config->output_buffer);
982 } else if (strcmp(name, "rx-data-per-sec") == 0) {
983 READ_NUMERIC(config->rx_per_sec);
984 config->rx_per_sec /= 1000; /* in kb */
985 } else if (strcmp(name, "tx-data-per-sec") == 0) {
986 READ_NUMERIC(config->tx_per_sec);
987 config->tx_per_sec /= 1000; /* in kb */
988 } else if (strcmp(name, "deny-roaming") == 0) {
989 READ_TF(config->deny_roaming);
990 } else if (strcmp(name, "stats-report-time") == 0) {
991 READ_NUMERIC(config->stats_report_time);
992 } else if (strcmp(name, "rekey-time") == 0) {
993 READ_NUMERIC(config->rekey_time);
994 } else if (strcmp(name, "rekey-method") == 0) {
995 if (strcmp(value, "ssl") == 0)
996 config->rekey_method = REKEY_METHOD_SSL;
997 else if (strcmp(value, "new-tunnel") == 0)
998 config->rekey_method = REKEY_METHOD_NEW_TUNNEL;
999 else {
1000 fprintf(stderr, ERRSTR"unknown rekey method '%s'\n", value);
1001 return 0;
1002 }
1003 } else if (strcmp(name, "cookie-timeout") == 0) {
1004 READ_NUMERIC(config->cookie_timeout);
1005 } else if (strcmp(name, "persistent-cookies") == 0) {
1006 READ_TF(config->persistent_cookies);
1007 } else if (strcmp(name, "session-timeout") == 0) {
1008 READ_NUMERIC(config->session_timeout);
1009 } else if (strcmp(name, "auth-timeout") == 0) {
1010 if (!WARN_ON_VHOST(vhost->name, "auth-timeout", auth_timeout))
1011 READ_NUMERIC(config->auth_timeout);
1012 } else if (strcmp(name, "idle-timeout") == 0) {
1013 READ_NUMERIC(config->idle_timeout);
1014 } else if (strcmp(name, "mobile-idle-timeout") == 0) {
1015 READ_NUMERIC(config->mobile_idle_timeout);
1016 } else if (strcmp(name, "max-clients") == 0) {
1017 if (!WARN_ON_VHOST(vhost->name, "max-clients", max_clients))
1018 READ_NUMERIC(config->max_clients);
1019 } else if (strcmp(name, "min-reauth-time") == 0) {
1020 if (!WARN_ON_VHOST(vhost->name, "min-reauth-time", min_reauth_time))
1021 READ_NUMERIC(config->min_reauth_time);
1022 } else if (strcmp(name, "ban-reset-time") == 0) {
1023 if (!WARN_ON_VHOST(vhost->name, "ban-reset-time", ban_reset_time))
1024 READ_NUMERIC(config->ban_reset_time);
1025 } else if (strcmp(name, "max-ban-score") == 0) {
1026 if (!WARN_ON_VHOST(vhost->name, "max-ban-score", max_ban_score))
1027 READ_NUMERIC( config->max_ban_score);
1028 } else if (strcmp(name, "ban-points-wrong-password") == 0) {
1029 if (!WARN_ON_VHOST(vhost->name, "ban-points-wrong-password", ban_points_wrong_password))
1030 READ_NUMERIC(config->ban_points_wrong_password);
1031 } else if (strcmp(name, "ban-points-connection") == 0) {
1032 if (!WARN_ON_VHOST(vhost->name, "ban-points-connection", ban_points_connect))
1033 READ_NUMERIC(config->ban_points_connect);
1034 } else if (strcmp(name, "ban-points-kkdcp") == 0) {
1035 if (!WARN_ON_VHOST(vhost->name, "ban-points-kkdcp", ban_points_kkdcp))
1036 READ_NUMERIC(config->ban_points_kkdcp);
1037 } else if (strcmp(name, "max-same-clients") == 0) {
1038 READ_NUMERIC(config->max_same_clients);
1039 } else if (strcmp(name, "device") == 0) {
1040 if (!WARN_ON_VHOST(vhost->name, "device", network.name))
1041 READ_STATIC_STRING(config->network.name);
1042 } else if (strcmp(name, "cgroup") == 0) {
1043 READ_STRING(config->cgroup);
1044 } else if (strcmp(name, "proxy-url") == 0) {
1045 READ_STRING(config->proxy_url);
1046 } else if (strcmp(name, "ipv4-network") == 0) {
1047 READ_STRING(config->network.ipv4);
1048 prefix4 = extract_prefix(config->network.ipv4);
1049 if (prefix4 != 0) {
1050 config->network.ipv4_netmask = ipv4_prefix_to_strmask(config, prefix4);
1051 }
1052 } else if (strcmp(name, "ipv4-netmask") == 0) {
1053 READ_STRING(config->network.ipv4_netmask);
1054 } else if (strcmp(name, "ipv6-network") == 0) {
1055 READ_STRING(config->network.ipv6);
1056 prefix = extract_prefix(config->network.ipv6);
1057 if (prefix)
1058 config->network.ipv6_prefix = prefix;
1059 } else if (strcmp(name, "ipv6-prefix") == 0) {
1060 READ_NUMERIC(config->network.ipv6_prefix);
1061
1062 if (valid_ipv6_prefix(config->network.ipv6_prefix) == 0) {
1063 fprintf(stderr, ERRSTR"invalid IPv6 prefix: %u\n", prefix);
1064 return 0;
1065 }
1066 } else if (strcmp(name, "ipv6-subnet-prefix") == 0) {
1067 /* read subnet prefix */
1068 READ_NUMERIC(prefix);
1069 if (prefix > 0) {
1070 config->network.ipv6_subnet_prefix = prefix;
1071
1072 if (valid_ipv6_prefix(prefix) == 0) {
1073 fprintf(stderr, ERRSTR"invalid IPv6 subnet prefix: %u\n", prefix);
1074 return 0;
1075 }
1076 }
1077 } else if (strcmp(name, "custom-header") == 0) {
1078 READ_MULTI_LINE(config->custom_header, config->custom_header_size);
1079 } else if (strcmp(name, "split-dns") == 0) {
1080 READ_MULTI_LINE(config->split_dns, config->split_dns_size);
1081 } else if (strcmp(name, "route") == 0) {
1082 READ_MULTI_LINE(config->network.routes, config->network.routes_size);
1083 } else if (strcmp(name, "no-route") == 0) {
1084 READ_MULTI_LINE(config->network.no_routes, config->network.no_routes_size);
1085 } else if (strcmp(name, "default-select-group") == 0) {
1086 READ_STRING(config->default_select_group);
1087 } else if (strcmp(name, "auto-select-group") == 0) {
1088 READ_TF(vhost->auto_select_group);
1089 } else if (strcmp(name, "select-group") == 0) {
1090 READ_MULTI_BRACKET_LINE(config->group_list,
1091 config->friendly_group_list,
1092 config->group_list_size);
1093 } else if (strcmp(name, "dns") == 0) {
1094 READ_MULTI_LINE(config->network.dns, config->network.dns_size);
1095 } else if (strcmp(name, "ipv4-dns") == 0) {
1096 READ_MULTI_LINE(config->network.dns, config->network.dns_size);
1097 } else if (strcmp(name, "ipv6-dns") == 0) {
1098 READ_MULTI_LINE(config->network.dns, config->network.dns_size);
1099 } else if (strcmp(name, "nbns") == 0) {
1100 READ_MULTI_LINE(config->network.nbns, config->network.nbns_size);
1101 } else if (strcmp(name, "ipv4-nbns") == 0) {
1102 READ_MULTI_LINE(config->network.nbns, config->network.nbns_size);
1103 } else if (strcmp(name, "ipv6-nbns") == 0) {
1104 READ_MULTI_LINE(config->network.nbns, config->network.nbns_size);
1105 } else if (strcmp(name, "route-add-cmd") == 0) {
1106 if (!WARN_ON_VHOST(vhost->name, "route-add-cmd", route_add_cmd))
1107 READ_STRING(config->route_add_cmd);
1108 } else if (strcmp(name, "route-del-cmd") == 0) {
1109 if (!WARN_ON_VHOST(vhost->name, "route-del-cmd", route_del_cmd))
1110 READ_STRING(config->route_del_cmd);
1111 } else if (strcmp(name, "config-per-user") == 0) {
1112 READ_STRING(config->per_user_dir);
1113 } else if (strcmp(name, "config-per-group") == 0) {
1114 READ_STRING(config->per_group_dir);
1115 } else if (strcmp(name, "expose-iroutes") == 0) {
1116 READ_TF(vhost->expose_iroutes);
1117 } else if (strcmp(name, "default-user-config") == 0) {
1118 READ_STRING(config->default_user_conf);
1119 } else if (strcmp(name, "default-group-config") == 0) {
1120 READ_STRING(config->default_group_conf);
1121 } else {
1122 if (reload == 0)
1123 fprintf(stderr, WARNSTR"skipping unknown option '%s'\n", name);
1124 }
1125
1126 exit:
1127 talloc_free(value);
1128 return 1;
1129 }
1130
1131 enum {
1132 CFG_FLAG_RELOAD = (1<<0),
1133 CFG_FLAG_SECMOD = (1<<1),
1134 CFG_FLAG_WORKER = (1<<2)
1135 };
1136
replace_file_with_snapshot(char ** file_name)1137 static void replace_file_with_snapshot(char ** file_name)
1138 {
1139 char * snapshot_file_name;
1140 if (*file_name == NULL) {
1141 return;
1142 }
1143
1144 if (snapshot_lookup_filename(
1145 config_snapshot,
1146 *file_name,
1147 &snapshot_file_name) < 0) {
1148 fprintf(stderr, ERRSTR"cannot find snapshot for file %s\n", *file_name);
1149 exit(1);
1150 }
1151
1152 talloc_free(*file_name);
1153 *file_name = snapshot_file_name;
1154 }
1155
1156 #define CONFIG_ERROR(filename, err) { \
1157 if (err > 0) \
1158 fprintf(stderr, ERRSTR"config file error in line %d\n", err); \
1159 else \
1160 fprintf(stderr, ERRSTR"cannot load config file %s\n", filename); }
1161
parse_cfg_file(void * pool,const char * file,struct list_head * head,unsigned flags)1162 static void parse_cfg_file(void *pool, const char *file, struct list_head *head,
1163 unsigned flags)
1164 {
1165 int ret;
1166 struct cfg_st *config;
1167 struct ini_ctx_st ctx;
1168 vhost_cfg_st *vhost = NULL;
1169 vhost_cfg_st *defvhost;
1170
1171 memset(&ctx, 0, sizeof(ctx));
1172 ctx.file = file;
1173 ctx.reload = (flags&CFG_FLAG_RELOAD)?1:0;
1174 ctx.head = head;
1175
1176 #if defined(PROC_FS_SUPPORTED)
1177 // Worker always reads from snapshot
1178 if ((flags & CFG_FLAG_WORKER) == CFG_FLAG_WORKER) {
1179 char * snapshot_file = NULL;
1180
1181 if ((snapshot_lookup_filename(config_snapshot, file, &snapshot_file) < 0) &&
1182 (snapshot_lookup_filename(config_snapshot, OLD_DEFAULT_CFG_FILE, &snapshot_file) < 0)) {
1183 fprintf(stderr, ERRSTR"snapshot_lookup failed for file %s\n", file);
1184 exit(1);
1185 }
1186
1187 ret = ini_parse(snapshot_file, cfg_ini_handler, &ctx);
1188 if (ret != 0) {
1189 CONFIG_ERROR(file, ret);
1190 exit(1);
1191 }
1192 talloc_free(snapshot_file);
1193
1194 // Walk the config, replacing filename with the snapshot equivalent
1195 list_for_each(head, vhost, list) {
1196 size_t index;
1197 replace_file_with_snapshot(&vhost->perm_config.dh_params_file);
1198 replace_file_with_snapshot(&vhost->perm_config.config->ocsp_response);
1199 for (index = 0; index < vhost->perm_config.cert_size; index ++) {
1200 replace_file_with_snapshot(&vhost->perm_config.cert[index]);
1201 }
1202 }
1203 } else {
1204 const char *local_cfg_file = file;
1205
1206 if (local_cfg_file == NULL) {
1207 fprintf(stderr, ERRSTR"no config file!\n");
1208 exit(1);
1209 }
1210
1211 /* parse configuration
1212 */
1213 ret = ini_parse(local_cfg_file, cfg_ini_handler, &ctx);
1214 if (ret < 0 && strcmp(file, DEFAULT_CFG_FILE) == 0) {
1215 local_cfg_file = OLD_DEFAULT_CFG_FILE;
1216 ret = ini_parse(local_cfg_file, cfg_ini_handler, &ctx);
1217 }
1218
1219 if (ret != 0) {
1220 CONFIG_ERROR(local_cfg_file, ret);
1221 exit(1);
1222 }
1223
1224 ret = snapshot_create(config_snapshot, local_cfg_file);
1225 if (ret < 0){
1226 fprintf(stderr, ERRSTR"cannot snapshot config file %s\n", local_cfg_file);
1227 exit(1);
1228 }
1229 list_for_each(head, vhost, list) {
1230 size_t index;
1231 snapshot_create(config_snapshot, vhost->perm_config.dh_params_file);
1232 snapshot_create(config_snapshot, vhost->perm_config.config->ocsp_response);
1233 for (index = 0; index < vhost->perm_config.cert_size; index ++) {
1234 snapshot_create(config_snapshot, vhost->perm_config.cert[index]);
1235 }
1236 }
1237
1238 }
1239 #else
1240 const char * local_cfg_file = file;
1241
1242 if (local_cfg_file == NULL) {
1243 fprintf(stderr, ERRSTR"no config file!\n");
1244 exit(1);
1245 }
1246
1247 /* parse configuration
1248 */
1249 ret = ini_parse(local_cfg_file, cfg_ini_handler, &ctx);
1250 if (ret < 0 && file != NULL && strcmp(file, DEFAULT_CFG_FILE) == 0) {
1251 local_cfg_file = OLD_DEFAULT_CFG_FILE;
1252 ret = ini_parse(local_cfg_file, cfg_ini_handler, &ctx);
1253 }
1254
1255 if (ret != 0) {
1256 CONFIG_ERROR(local_cfg_file, ret);
1257 exit(1);
1258 }
1259 #endif
1260
1261 /* apply configuration not yet applied.
1262 * We start from the last, which is the default server (firstly
1263 * added).
1264 */
1265 list_for_each_rev(head, vhost, list) {
1266 config = vhost->perm_config.config;
1267
1268 if (vhost->auth_init == 0) {
1269 if (vhost->auth_size == 0) {
1270 fprintf(stderr, ERRSTR"%sthe 'auth' configuration option was not specified!\n", PREFIX_VHOST(vhost));
1271 exit(1);
1272 }
1273
1274 figure_auth_funcs(vhost, PREFIX_VHOST(vhost), &vhost->perm_config, vhost->auth, vhost->auth_size, 1);
1275 figure_auth_funcs(vhost, PREFIX_VHOST(vhost), &vhost->perm_config, vhost->eauth, vhost->eauth_size, 0);
1276
1277 figure_acct_funcs(vhost, PREFIX_VHOST(vhost), &vhost->perm_config, vhost->acct);
1278
1279 vhost->auth_init = 1;
1280 }
1281
1282 if (vhost->auto_select_group != 0 && vhost->perm_config.auth[0].amod != NULL && vhost->perm_config.auth[0].amod->group_list != NULL) {
1283 vhost->perm_config.auth[0].amod->group_list(config, vhost->perm_config.auth[0].additional, &config->group_list, &config->group_list_size);
1284 switch (vhost->perm_config.auth[0].amod->type) {
1285 case AUTH_TYPE_PAM|AUTH_TYPE_USERNAME_PASS:
1286 pam_auth_group_list = config->group_list;
1287 pam_auth_group_list_size = config->group_list_size;
1288 break;
1289 case AUTH_TYPE_GSSAPI:
1290 gssapi_auth_group_list = config->group_list;
1291 gssapi_auth_group_list_size = config->group_list_size;
1292 break;
1293 case AUTH_TYPE_PLAIN|AUTH_TYPE_USERNAME_PASS:
1294 plain_auth_group_list = config->group_list;
1295 plain_auth_group_list_size = config->group_list_size;
1296 break;
1297 }
1298 }
1299
1300 if (vhost->expose_iroutes != 0) {
1301 load_iroutes(config);
1302 }
1303
1304 if (vhost->name)
1305 defvhost = default_vhost(head);
1306 else
1307 defvhost = NULL;
1308
1309 /* this check copies mandatory fields from default vhost if needed */
1310 check_cfg(vhost, defvhost, ctx.reload);
1311
1312 /* the following are only useful in main process */
1313 if (!(flags & CFG_FLAG_SECMOD)) {
1314 tls_load_files(NULL, vhost);
1315 tls_load_prio(NULL, vhost);
1316 tls_reload_crl(NULL, vhost, 1);
1317 }
1318
1319 #ifdef HAVE_GSSAPI
1320 if (vhost->urlfw_size > 0) {
1321 parse_kkdcp(config, vhost->urlfw, vhost->urlfw_size);
1322 talloc_free(vhost->urlfw);
1323 vhost->urlfw = NULL;
1324 }
1325 #endif
1326 fprintf(stderr, NOTESTR"%ssetting '%s' as supplemental config option\n",
1327 PREFIX_VHOST(vhost),
1328 sup_config_name(vhost->perm_config.sup_config_type));
1329 }
1330 }
1331
1332
1333 /* sanity checks on config */
check_cfg(vhost_cfg_st * vhost,vhost_cfg_st * defvhost,unsigned silent)1334 static void check_cfg(vhost_cfg_st *vhost, vhost_cfg_st *defvhost, unsigned silent)
1335 {
1336 unsigned j, i;
1337 struct cfg_st *config;
1338
1339 config = vhost->perm_config.config;
1340
1341 if (vhost->perm_config.auth[0].enabled == 0) {
1342 fprintf(stderr, ERRSTR"%sno authentication method was specified!\n", PREFIX_VHOST(vhost));
1343 exit(1);
1344 }
1345
1346 if (vhost->perm_config.socket_file_prefix == NULL) {
1347 if (vhost->name) {
1348 vhost->perm_config.socket_file_prefix = talloc_strdup(vhost, defvhost->perm_config.socket_file_prefix);
1349 } else {
1350 /* The 'socket-file' is not mandatory on main server */
1351 fprintf(stderr, ERRSTR"%sthe 'socket-file' configuration option must be specified!\n", PREFIX_VHOST(vhost));
1352 exit(1);
1353 }
1354 }
1355
1356 if (vhost->perm_config.port == 0) {
1357 if (defvhost) {
1358 if (vhost->perm_config.port)
1359 vhost->perm_config.port = defvhost->perm_config.port;
1360 } else {
1361 fprintf(stderr, ERRSTR"%sthe tcp-port option is mandatory!\n", PREFIX_VHOST(vhost));
1362 exit(1);
1363 }
1364 }
1365
1366 if (vhost->perm_config.cert_size == 0 || vhost->perm_config.key_size == 0) {
1367 fprintf(stderr, ERRSTR"%sthe 'server-cert' and 'server-key' configuration options must be specified!\n", PREFIX_VHOST(vhost));
1368 exit(1);
1369 }
1370
1371 if (config->network.ipv4 == NULL && config->network.ipv6 == NULL) {
1372 fprintf(stderr, ERRSTR"%sno ipv4-network or ipv6-network options set.\n", PREFIX_VHOST(vhost));
1373 exit(1);
1374 }
1375
1376 if (config->network.ipv4 != NULL && config->network.ipv4_netmask == NULL) {
1377 fprintf(stderr, ERRSTR"%sno mask found for IPv4 network.\n", PREFIX_VHOST(vhost));
1378 exit(1);
1379 }
1380
1381 if (config->network.ipv6 != NULL && config->network.ipv6_prefix == 0) {
1382 fprintf(stderr, ERRSTR"%sno prefix found for IPv6 network.\n", PREFIX_VHOST(vhost));
1383 exit(1);
1384 }
1385
1386 if (config->banner && strlen(config->banner) > MAX_BANNER_SIZE) {
1387 fprintf(stderr, ERRSTR"%sbanner size is too long\n", PREFIX_VHOST(vhost));
1388 exit(1);
1389 }
1390
1391 if (vhost->perm_config.cert_size != vhost->perm_config.key_size) {
1392 fprintf(stderr, ERRSTR"%sthe specified number of keys doesn't match the certificates\n", PREFIX_VHOST(vhost));
1393 exit(1);
1394 }
1395
1396 if ((vhost->perm_config.auth[0].type & AUTH_TYPE_CERTIFICATE) && vhost->perm_config.auth_methods == 1) {
1397 if (config->cisco_client_compat == 0)
1398 config->cert_req = GNUTLS_CERT_REQUIRE;
1399 else
1400 config->cert_req = GNUTLS_CERT_REQUEST;
1401 } else {
1402 unsigned i;
1403 for (i=0;i<vhost->perm_config.auth_methods;i++) {
1404 if (vhost->perm_config.auth[i].type & AUTH_TYPE_CERTIFICATE) {
1405 config->cert_req = GNUTLS_CERT_REQUEST;
1406 break;
1407 }
1408 }
1409 }
1410
1411 if (config->cert_req != 0 && config->cert_user_oid == NULL) {
1412 fprintf(stderr, ERRSTR"%sa certificate is requested by the option 'cert-user-oid' is not set\n", PREFIX_VHOST(vhost));
1413 exit(1);
1414 }
1415
1416 if (config->cert_req != 0 && config->cert_user_oid != NULL) {
1417 if (!c_isdigit(config->cert_user_oid[0]) && strcmp(config->cert_user_oid, "SAN(rfc822name)") != 0) {
1418 fprintf(stderr, ERRSTR"%sthe option 'cert-user-oid' has a unsupported value\n", PREFIX_VHOST(vhost));
1419 exit(1);
1420 }
1421 }
1422
1423 #ifdef ANYCONNECT_CLIENT_COMPAT
1424 if (vhost->perm_config.cert && vhost->perm_config.cert_hash == NULL) {
1425 vhost->perm_config.cert_hash = calc_sha1_hash(vhost->pool, vhost->perm_config.cert[0], 1);
1426 }
1427
1428 if (config->xml_config_file) {
1429 config->xml_config_hash = calc_sha1_hash(vhost->pool, config->xml_config_file, 0);
1430 if (config->xml_config_hash == NULL && vhost->perm_config.chroot_dir != NULL) {
1431 char path[_POSIX_PATH_MAX];
1432
1433 snprintf(path, sizeof(path), "%s/%s", vhost->perm_config.chroot_dir, config->xml_config_file);
1434 config->xml_config_hash = calc_sha1_hash(vhost->pool, path, 0);
1435
1436 if (config->xml_config_hash == NULL) {
1437 fprintf(stderr, ERRSTR"%scannot open file '%s'\n", PREFIX_VHOST(vhost), path);
1438 exit(1);
1439 }
1440 }
1441 if (config->xml_config_hash == NULL) {
1442 fprintf(stderr, ERRSTR"%scannot open file '%s'\n", PREFIX_VHOST(vhost), config->xml_config_file);
1443 exit(1);
1444 }
1445 }
1446 #endif
1447
1448 if (config->priorities == NULL) {
1449 char *tmp = "";
1450 /* on vhosts assign the main host priorities. We furthermore disable TLS1.3 on Cisco clients
1451 * due to issue #318. */
1452
1453 if (config->cisco_client_compat) {
1454 tmp = ":-VERS-TLS1.3";
1455 }
1456
1457 if (defvhost) {
1458 config->priorities = talloc_asprintf(config, "%s%s", defvhost->perm_config.config->priorities, tmp);
1459 } else {
1460 config->priorities = talloc_asprintf(config, "%s%s", "NORMAL:%SERVER_PRECEDENCE:%COMPAT", tmp);
1461 }
1462 }
1463
1464 if (vhost->perm_config.occtl_socket_file == NULL)
1465 vhost->perm_config.occtl_socket_file = talloc_strdup(vhost, OCCTL_UNIX_SOCKET);
1466
1467
1468 if (config->network.ipv6_prefix && config->network.ipv6_prefix >= config->network.ipv6_subnet_prefix) {
1469 fprintf(stderr, ERRSTR"%sthe subnet prefix (%u) cannot be smaller or equal to network's (%u)\n",
1470 PREFIX_VHOST(vhost), config->network.ipv6_subnet_prefix, config->network.ipv6_prefix);
1471 exit(1);
1472 }
1473
1474 if (!vhost->name && config->network.name[0] == 0) {
1475 fprintf(stderr, ERRSTR"%sthe 'device' configuration option must be specified!\n", PREFIX_VHOST(vhost));
1476 exit(1);
1477 }
1478
1479 if (config->mobile_dpd == 0)
1480 config->mobile_dpd = config->dpd;
1481
1482 if (config->cisco_client_compat) {
1483 if (!config->dtls_legacy && !silent) {
1484 fprintf(stderr, NOTESTR"%sthe cisco-client-compat option implies dtls-legacy = true; enabling\n", PREFIX_VHOST(vhost));
1485 }
1486 config->dtls_legacy = 1;
1487 }
1488
1489 if (config->match_dtls_and_tls) {
1490 if (config->dtls_legacy) {
1491 fprintf(stderr, ERRSTR"%s'match-tls-dtls-ciphers' cannot be applied when 'dtls-legacy' or 'cisco-client-compat' is on\n", PREFIX_VHOST(vhost));
1492 exit(1);
1493 }
1494 }
1495
1496 if (config->mobile_idle_timeout == (unsigned)-1)
1497 config->mobile_idle_timeout = config->idle_timeout;
1498
1499 #ifdef ENABLE_COMPRESSION
1500 if (config->no_compress_limit < MIN_NO_COMPRESS_LIMIT)
1501 config->no_compress_limit = MIN_NO_COMPRESS_LIMIT;
1502 #endif
1503
1504 /* use tcp listen host by default */
1505 if (vhost->perm_config.udp_listen_host == NULL) {
1506 vhost->perm_config.udp_listen_host = vhost->perm_config.listen_host;
1507 }
1508
1509 #if !defined(HAVE_LIBSECCOMP)
1510 if (config->isolate != 0 && !silent) {
1511 fprintf(stderr, ERRSTR"%s'isolate-workers' is set to true, but not compiled with seccomp or Linux namespaces support\n", PREFIX_VHOST(vhost));
1512 }
1513 #endif
1514
1515 for (j=0;j<config->network.routes_size;j++) {
1516 if (ip_route_sanity_check(config->network.routes, &config->network.routes[j]) != 0)
1517 exit(1);
1518
1519 if (strcmp(config->network.routes[j], "0.0.0.0/0") == 0 ||
1520 strcmp(config->network.routes[j], "default") == 0) {
1521 /* set default route */
1522 for (i=0;i<j;i++)
1523 talloc_free(config->network.routes[i]);
1524 config->network.routes_size = 0;
1525 break;
1526 }
1527 }
1528
1529 for (j=0;j<config->network.no_routes_size;j++) {
1530 if (ip_route_sanity_check(config->network.no_routes, &config->network.no_routes[j]) != 0)
1531 exit(1);
1532 }
1533
1534 for (j=0;j<config->network.dns_size;j++) {
1535 if (strcmp(config->network.dns[j], "local") == 0) {
1536 fprintf(stderr, ERRSTR"%sthe 'local' DNS keyword is no longer supported.\n", PREFIX_VHOST(vhost));
1537 exit(1);
1538 }
1539 }
1540
1541 if (config->per_user_dir || config->per_group_dir) {
1542 if (vhost->perm_config.sup_config_type != SUP_CONFIG_FILE) {
1543 fprintf(stderr, ERRSTR"%sspecified config-per-user or config-per-group but supplemental config is '%s'\n",
1544 PREFIX_VHOST(vhost), sup_config_name(vhost->perm_config.sup_config_type));
1545 exit(1);
1546 }
1547 }
1548
1549 }
1550
1551 #define OPT_NO_CHDIR 1
1552 static const struct option long_options[] = {
1553 {"debug", 1, 0, 'd'},
1554 {"config", 1, 0, 'c'},
1555 {"pid-file", 1, 0, 'p'},
1556 {"test-config", 0, 0, 't'},
1557 {"foreground", 0, 0, 'f'},
1558 {"no-chdir", 0, 0, OPT_NO_CHDIR},
1559 {"help", 0, 0, 'h'},
1560 {"traceable", 0, 0, 'x'},
1561 {"version", 0, 0, 'v'},
1562 {NULL, 0, 0, 0}
1563 };
1564
1565 static
usage(void)1566 void usage(void)
1567 {
1568 fprintf(stderr, "ocserv - OpenConnect VPN server\n");
1569 fprintf(stderr, "Usage: ocserv [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\n");
1570
1571 fprintf(stderr, " -f, --foreground Do not fork into background\n");
1572 fprintf(stderr, " -d, --debug=num Enable verbose network debugging information\n");
1573 fprintf(stderr, " - it must be in the range:\n");
1574 fprintf(stderr, " 0 to 9\n");
1575 fprintf(stderr, " -c, --config=file Configuration file for the server\n");
1576 fprintf(stderr, " - file must exist\n");
1577 fprintf(stderr, " -t, --test-config Test the provided configuration file\n");
1578 fprintf(stderr, " --no-chdir Do not perform a chdir on daemonize\n");
1579 fprintf(stderr, " -p, --pid-file=file Specify pid file for the server\n");
1580 fprintf(stderr, " -v, --version output version information and exit\n");
1581 fprintf(stderr, " -x, --traceable Allow processes tracing\n");
1582 fprintf(stderr, " - use for debugging purposes only\n");
1583 fprintf(stderr, " -h, --help display extended usage information and exit\n\n");
1584
1585 fprintf(stderr, "Openconnect VPN server (ocserv) is a VPN server compatible with the\n");
1586 fprintf(stderr, "openconnect VPN client. It follows the TLS and DTLS-based AnyConnect VPN\n");
1587 fprintf(stderr, "protocol which is used by several CISCO routers.\n\n");
1588
1589 fprintf(stderr, "Please send bug reports to: "PACKAGE_BUGREPORT"\n");
1590 }
1591
cmd_parser(void * pool,int argc,char ** argv,struct list_head * head,bool worker)1592 int cmd_parser (void *pool, int argc, char **argv, struct list_head *head, bool worker)
1593 {
1594 unsigned test_only = 0;
1595 int c;
1596 vhost_cfg_st *vhost;
1597
1598 vhost = vhost_add(pool, head, NULL, 0);
1599 assert(vhost != NULL);
1600
1601 while (1) {
1602 c = getopt_long(argc, argv, "d:c:p:ftvxh", long_options, NULL);
1603 if (c == -1)
1604 break;
1605
1606 switch(c) {
1607 case 'f':
1608 vhost->perm_config.foreground = 1;
1609 break;
1610 case 'p':
1611 strlcpy(pid_file, optarg, sizeof(pid_file));
1612 break;
1613 case 'c':
1614 strlcpy(cfg_file, optarg, sizeof(cfg_file));
1615 break;
1616 case 'd':
1617 vhost->perm_config.debug = atoi(optarg);
1618 break;
1619 case 't':
1620 test_only = 1;
1621 break;
1622 case OPT_NO_CHDIR:
1623 vhost->perm_config.no_chdir = 1;
1624 break;
1625 case 'h':
1626 usage();
1627 exit(0);
1628 case 'v':
1629 print_version();
1630 exit(0);
1631 case 'x':
1632 vhost->perm_config.pr_dumpable = 1;
1633 break;
1634 }
1635 }
1636
1637 if (optind != argc) {
1638 fprintf(stderr, ERRSTR"no additional command line options are allowed\n\n");
1639 exit(1);
1640 }
1641
1642 if (access(cfg_file, R_OK) != 0) {
1643 fprintf(stderr, ERRSTR"cannot access config file: %s\n", cfg_file);
1644 fprintf(stderr, "Usage: %s -c [config]\nUse %s --help for more information.\n", argv[0], argv[0]);
1645 exit(1);
1646 }
1647
1648 parse_cfg_file(pool, cfg_file, head, worker ? CFG_FLAG_WORKER : 0);
1649
1650 if (test_only)
1651 exit(0);
1652
1653 return 0;
1654
1655 }
1656
archive_cfg(struct list_head * head)1657 static void archive_cfg(struct list_head *head)
1658 {
1659 attic_entry_st *e;
1660 struct vhost_cfg_st* vhost = NULL;
1661
1662 list_for_each(head, vhost, list) {
1663 /* we don't clear anything as it may be referenced by some
1664 * client (proc_st). We move everything to attic and
1665 * once nothing is in use we clear that */
1666
1667 e = talloc(vhost, attic_entry_st);
1668 if (e == NULL) {
1669 /* we leak, but better than crashing */
1670 return;
1671 }
1672
1673 e->usage_count = vhost->perm_config.config->usage_count;
1674
1675 /* we rely on talloc doing that recursively */
1676 talloc_steal(e, vhost->perm_config.config);
1677 vhost->perm_config.config = NULL;
1678
1679 if (e->usage_count == NULL || *e->usage_count == 0) {
1680 talloc_free(e);
1681 } else {
1682 list_add(&vhost->perm_config.attic, &e->list);
1683 }
1684 }
1685
1686 return;
1687 }
1688
clear_cfg(struct list_head * head)1689 static void clear_cfg(struct list_head *head)
1690 {
1691 vhost_cfg_st *cpos = NULL, *ctmp;
1692
1693 list_for_each_safe(head, cpos, ctmp, list) {
1694 /* we rely on talloc freeing recursively */
1695 talloc_free(cpos->perm_config.config);
1696 cpos->perm_config.config = NULL;
1697 }
1698
1699 return;
1700 }
1701
clear_vhosts(struct list_head * head)1702 void clear_vhosts(struct list_head *head)
1703 {
1704 vhost_cfg_st *vhost = NULL, *ctmp;
1705
1706 list_for_each_safe(head, vhost, ctmp, list) {
1707 tls_vhost_deinit(vhost);
1708 /* we rely on talloc freeing recursively */
1709 talloc_free(vhost->perm_config.config);
1710 vhost->perm_config.config = NULL;
1711 }
1712
1713 return;
1714 }
1715
append(const char * option)1716 static void append(const char *option)
1717 {
1718 static int have_previous_val = 0;
1719
1720 if (have_previous_val == 0) {
1721 have_previous_val = 1;
1722 } else {
1723 fprintf(stderr, ", ");
1724 }
1725 fprintf(stderr, "%s", option);
1726 }
1727
print_version(void)1728 static void print_version(void)
1729 {
1730 const char *p;
1731
1732 fputs(PACKAGE_STRING, stderr);
1733 fprintf(stderr, "\n\nCompiled with: ");
1734 #ifdef HAVE_LIBSECCOMP
1735 append("seccomp");
1736 #endif
1737 #ifdef HAVE_LIBWRAP
1738 append("tcp-wrappers");
1739 #endif
1740 #ifdef HAVE_LIBOATH
1741 append("oath");
1742 #endif
1743 #ifdef HAVE_RADIUS
1744 append("radius");
1745 #endif
1746 #ifdef HAVE_GSSAPI
1747 append("gssapi");
1748 #endif
1749 #ifdef HAVE_PAM
1750 append("PAM");
1751 #endif
1752 append("PKCS#11");
1753 #ifdef ANYCONNECT_CLIENT_COMPAT
1754 append("AnyConnect");
1755 #endif
1756 #ifdef SUPPORT_OIDC_AUTH
1757 append("oidc_auth");
1758 #endif
1759 fprintf(stderr, "\n");
1760
1761 p = gnutls_check_version(NULL);
1762 if (strcmp(p, GNUTLS_VERSION) != 0) {
1763 fprintf(stderr, "GnuTLS version: %s (compiled with %s)\n", p, GNUTLS_VERSION);
1764 } else {
1765 fprintf(stderr, "GnuTLS version: %s\n", p);
1766 }
1767 }
1768
1769
reload_cfg_file(void * pool,struct list_head * configs,unsigned sec_mod)1770 void reload_cfg_file(void *pool, struct list_head *configs, unsigned sec_mod)
1771 {
1772 struct vhost_cfg_st* vhost = NULL;
1773 unsigned flags = CFG_FLAG_RELOAD;
1774
1775 if (sec_mod)
1776 flags |= CFG_FLAG_SECMOD;
1777
1778 /* Archive or clear any non-permanent configs */
1779 if (!sec_mod)
1780 archive_cfg(configs);
1781 else
1782 clear_cfg(configs);
1783
1784 /* Create new config structures and apply defaults */
1785 list_for_each(configs, vhost, list) {
1786 if (vhost->perm_config.config == NULL)
1787 cfg_new(vhost, 1);
1788 }
1789
1790 /* parse the config again */
1791 parse_cfg_file(pool, cfg_file, configs, flags);
1792
1793 return;
1794 }
1795
write_pid_file(void)1796 void write_pid_file(void)
1797 {
1798 FILE* fp;
1799
1800 if (pid_file[0]==0)
1801 return;
1802
1803 fp = fopen(pid_file, "w");
1804 if (fp == NULL) {
1805 fprintf(stderr, ERRSTR"cannot open pid file '%s'\n", pid_file);
1806 exit(1);
1807 }
1808
1809 fprintf(fp, "%u", (unsigned)getpid());
1810 fclose(fp);
1811 }
1812
remove_pid_file(void)1813 void remove_pid_file(void)
1814 {
1815 if (pid_file[0]==0)
1816 return;
1817
1818 (void)remove(pid_file);
1819 }
1820
_add_multi_line_val(void * pool,char *** varname,size_t * num,const char * value)1821 int _add_multi_line_val(void *pool, char ***varname, size_t *num,
1822 const char *value)
1823 {
1824 unsigned _max = DEFAULT_CONFIG_ENTRIES;
1825 void *tmp;
1826
1827 if (*varname == NULL) {
1828 *num = 0;
1829 *varname = talloc_array(pool, char*, _max);
1830 if (*varname == NULL)
1831 return -1;
1832 }
1833
1834 if (*num >= _max-1) {
1835 tmp = talloc_realloc(pool, *varname, char*, (*num)+2);
1836 if (tmp == NULL)
1837 return -1;
1838 *varname = tmp;
1839 }
1840
1841 (*varname)[*num] = talloc_strdup(*varname, value);
1842 (*num)++;
1843
1844 (*varname)[*num] = NULL;
1845 return 0;
1846 }
1847
clear_old_configs(struct list_head * head)1848 void clear_old_configs(struct list_head *head)
1849 {
1850 attic_entry_st *e = NULL, *pos;
1851 vhost_cfg_st *cpos = NULL;
1852
1853 list_for_each(head, cpos, list) {
1854 /* go through the attic and clear old configurations if unused */
1855 list_for_each_safe(&cpos->perm_config.attic, e, pos, list) {
1856 if (*e->usage_count == 0) {
1857 list_del(&e->list);
1858 talloc_free(e);
1859 }
1860 }
1861 }
1862 }
1863
1864 // ocserv and ocserv-worker both load and parse the configuration files.
1865 // As part of the process of loading the config files, auth / acct methods
1866 // are enabled based on the content of the acct_mod_st and auth_mod_st tables.
1867 // These auth tables are present in the auth sub-subsystem. Linking against
1868 // the auth subsystem pulls in a very large set of dependent binaries which
1869 // increases the overall memory footprint. To avoid this, we provide stub
1870 // versions of acct_mod_st and auth_mod_st tables that the ocserv-worker
1871 // process can link against.
1872 #if defined(OCSERV_WORKER_PROCESS)
1873
1874 // Group information is populated by the auth subsystem.
1875 // When compiles as part of ocserv-worker, the auth subsystem is not present.
1876 // To work around this, the group information is passed from ocserv-main to
1877 // ocserv-worker, which then caches it and returns it when queried.
pam_group_list(void * pool,void * _additional,char *** groupname,unsigned * groupname_size)1878 static void pam_group_list(void *pool, void *_additional, char ***groupname, unsigned *groupname_size)
1879 {
1880 *groupname = pam_auth_group_list;
1881 *groupname_size = pam_auth_group_list_size;
1882 }
1883
gssapi_group_list(void * pool,void * _additional,char *** groupname,unsigned * groupname_size)1884 static void gssapi_group_list(void *pool, void *_additional, char ***groupname, unsigned *groupname_size)
1885 {
1886 *groupname = gssapi_auth_group_list;
1887 *groupname_size = gssapi_auth_group_list_size;
1888 }
1889
plain_group_list(void * pool,void * _additional,char *** groupname,unsigned * groupname_size)1890 static void plain_group_list(void *pool, void *_additional, char ***groupname, unsigned *groupname_size)
1891 {
1892 *groupname = plain_auth_group_list;
1893 *groupname_size = plain_auth_group_list_size;
1894 }
1895
1896 const struct acct_mod_st radius_acct_funcs = {
1897 .type = ACCT_TYPE_RADIUS,
1898 .auth_types = ALL_AUTH_TYPES,
1899 .vhost_init = NULL,
1900 .vhost_deinit = NULL,
1901 .open_session = NULL,
1902 .close_session = NULL,
1903 .session_stats = NULL
1904 };
1905
1906 const struct acct_mod_st pam_acct_funcs = {
1907 .type = ACCT_TYPE_PAM,
1908 .auth_types = ALL_AUTH_TYPES,
1909 .open_session = NULL,
1910 .close_session = NULL,
1911 };
1912
1913 const struct auth_mod_st pam_auth_funcs = {
1914 .type = AUTH_TYPE_PAM | AUTH_TYPE_USERNAME_PASS,
1915 .auth_init = NULL,
1916 .auth_deinit = NULL,
1917 .auth_msg = NULL,
1918 .auth_pass = NULL,
1919 .auth_group = NULL,
1920 .auth_user = NULL,
1921 .group_list = pam_group_list
1922 };
1923
1924 const struct auth_mod_st gssapi_auth_funcs = {
1925 .type = AUTH_TYPE_GSSAPI,
1926 .auth_init = NULL,
1927 .auth_deinit = NULL,
1928 .auth_msg = NULL,
1929 .auth_pass = NULL,
1930 .auth_user = NULL,
1931 .auth_group = NULL,
1932 .vhost_init = NULL,
1933 .vhost_deinit = NULL,
1934 .group_list = gssapi_group_list
1935 };
1936
1937 const struct auth_mod_st plain_auth_funcs = {
1938 .type = AUTH_TYPE_PLAIN | AUTH_TYPE_USERNAME_PASS,
1939 .allows_retries = 1,
1940 .vhost_init = NULL,
1941 .auth_init = NULL,
1942 .auth_deinit = NULL,
1943 .auth_msg = NULL,
1944 .auth_pass = NULL,
1945 .auth_user = NULL,
1946 .auth_group = NULL,
1947 .group_list = plain_group_list
1948 };
1949
1950
1951 const struct auth_mod_st radius_auth_funcs = {
1952 .type = AUTH_TYPE_RADIUS | AUTH_TYPE_USERNAME_PASS,
1953 .allows_retries = 1,
1954 .vhost_init = NULL,
1955 .vhost_deinit = NULL,
1956 .auth_init = NULL,
1957 .auth_deinit = NULL,
1958 .auth_msg = NULL,
1959 .auth_pass = NULL,
1960 .auth_user = NULL,
1961 .auth_group = NULL,
1962 .group_list = NULL
1963 };
1964
1965 const struct auth_mod_st oidc_auth_funcs = {
1966 .type = AUTH_TYPE_OIDC,
1967 .allows_retries = 1,
1968 .vhost_init = NULL,
1969 .vhost_deinit = NULL,
1970 .auth_init = NULL,
1971 .auth_deinit = NULL,
1972 .auth_msg = NULL,
1973 .auth_pass = NULL,
1974 .auth_user = NULL,
1975 .auth_group = NULL,
1976 .group_list = NULL
1977 };
1978
1979
1980 #else
get_cert_names(struct worker_st * ws,const gnutls_datum_t * raw)1981 int get_cert_names(struct worker_st * ws, const gnutls_datum_t * raw)
1982 {
1983 return -1;
1984 }
1985 #endif
1986
1987 char secmod_socket_file_name_socket_file[_POSIX_PATH_MAX] = {0};
1988
restore_secmod_socket_file_name(const char * save_path)1989 void restore_secmod_socket_file_name(const char * save_path)
1990 {
1991 strlcpy(secmod_socket_file_name_socket_file, save_path, sizeof(secmod_socket_file_name_socket_file));
1992 }
1993
1994 /* Creates a permanent filename to use for secmod to main communication
1995 */
secmod_socket_file_name(struct perm_cfg_st * perm_config)1996 const char *secmod_socket_file_name(struct perm_cfg_st *perm_config)
1997 {
1998 unsigned int rnd;
1999 int ret;
2000
2001 if (secmod_socket_file_name_socket_file[0] != 0)
2002 return secmod_socket_file_name_socket_file;
2003
2004 ret = gnutls_rnd(GNUTLS_RND_NONCE, &rnd, sizeof(rnd));
2005 if (ret < 0)
2006 exit(1);
2007
2008 /* make socket name */
2009 snprintf(secmod_socket_file_name_socket_file, sizeof(secmod_socket_file_name_socket_file), "%s.%x",
2010 perm_config->socket_file_prefix, rnd);
2011
2012 return secmod_socket_file_name_socket_file;
2013 }
2014