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