1 /*
2  * Copyright (C) 2015-2017 Red Hat, Inc.
3  * Copyright (C) 2015-2020 Nikos Mavrogiannopoulos
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 <sys/uio.h>
27 #include <sys/select.h>
28 #include <sys/wait.h>
29 #include <fcntl.h>
30 #include <sys/socket.h>
31 #include <netdb.h>
32 #include <system.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <sys/ioctl.h>
36 #include <gnutls/gnutls.h>
37 #include <gnutls/crypto.h>
38 #include <tlslib.h>
39 #include "common.h"
40 #include "str.h"
41 #include "setproctitle.h"
42 #include <sec-mod.h>
43 #include <ip-lease.h>
44 #include <route-add.h>
45 #include <ipc.pb-c.h>
46 #include <script-list.h>
47 #include <cloexec.h>
48 
49 #include <vpn.h>
50 #include <main.h>
51 #include <main-ban.h>
52 #include <ccan/list/list.h>
53 
54 #ifdef HAVE_MALLOC_TRIM
55 # include <malloc.h>
56 #endif
57 
update_auth_failures(main_server_st * s,uint64_t auth_failures)58 static void update_auth_failures(main_server_st * s, uint64_t auth_failures)
59 {
60 	if (s->stats.auth_failures + auth_failures < s->stats.auth_failures) {
61 		mslog(s, NULL, LOG_INFO, "overflow on updating authentication failures; resetting");
62 		s->stats.auth_failures = 0;
63 		return;
64 	}
65 	s->stats.auth_failures += auth_failures;
66 	s->stats.total_auth_failures += auth_failures;
67 }
68 
handle_sec_mod_commands(sec_mod_instance_st * sec_mod_instance)69 int handle_sec_mod_commands(sec_mod_instance_st * sec_mod_instance)
70 {
71 	struct main_server_st * s = sec_mod_instance->server;
72 	struct iovec iov[3];
73 	uint8_t cmd;
74 	struct msghdr hdr;
75 	uint32_t length;
76 	uint8_t *raw;
77 	int ret, raw_len, e;
78 	void *pool = talloc_new(s);
79 	PROTOBUF_ALLOCATOR(pa, pool);
80 	BanIpMsg *tmsg = NULL;
81 
82 	if (pool == NULL)
83 		return -1;
84 
85 	iov[0].iov_base = &cmd;
86 	iov[0].iov_len = 1;
87 
88 	iov[1].iov_base = &length;
89 	iov[1].iov_len = 4;
90 
91 	memset(&hdr, 0, sizeof(hdr));
92 	hdr.msg_iov = iov;
93 	hdr.msg_iovlen = 2;
94 
95 	do {
96 		ret = recvmsg(sec_mod_instance->sec_mod_fd, &hdr, 0);
97 	} while(ret == -1 && errno == EINTR);
98 	if (ret == -1) {
99 		e = errno;
100 		mslog(s, NULL, LOG_ERR,
101 		      "cannot obtain metadata from sec-mod socket: %s",
102 		      strerror(e));
103 		return ERR_BAD_COMMAND;
104 	}
105 
106 	if (ret == 0) {
107 		mslog(s, NULL, LOG_ERR, "command socket for sec-mod closed");
108 		return ERR_BAD_COMMAND;
109 	}
110 
111 	if (ret < 5 || cmd <= MIN_SECM_CMD || cmd >= MAX_SECM_CMD) {
112 		mslog(s, NULL, LOG_ERR, "main received invalid message from sec-mod of %u bytes (cmd: %u)\n",
113 		      (unsigned)length, (unsigned)cmd);
114 		return ERR_BAD_COMMAND;
115 	}
116 
117 	mslog(s, NULL, LOG_DEBUG, "main received message '%s' from sec-mod of %u bytes\n",
118 	      cmd_request_to_str(cmd), (unsigned)length);
119 
120 	raw = talloc_size(pool, length);
121 	if (raw == NULL) {
122 		mslog(s, NULL, LOG_ERR, "memory error");
123 		return ERR_MEM;
124 	}
125 
126 	raw_len = force_read_timeout(sec_mod_instance->sec_mod_fd, raw, length, MAIN_SEC_MOD_TIMEOUT);
127 	if (raw_len != length) {
128 		e = errno;
129 		mslog(s, NULL, LOG_ERR,
130 		      "cannot obtain data of cmd %u with length %u from sec-mod socket: %s",
131 		      (unsigned)cmd, (unsigned)length, strerror(e));
132 		ret = ERR_BAD_COMMAND;
133 		goto cleanup;
134 	}
135 
136 	switch (cmd) {
137 	case CMD_SECM_BAN_IP:{
138 			BanIpReplyMsg reply = BAN_IP_REPLY_MSG__INIT;
139 
140 			tmsg = ban_ip_msg__unpack(&pa, raw_len, raw);
141 			if (tmsg == NULL) {
142 				mslog(s, NULL, LOG_ERR, "error unpacking sec-mod data");
143 				ret = ERR_BAD_COMMAND;
144 				goto cleanup;
145 			}
146 			/* No need to authenticate tmsg->ip as sec-mod is trusted */
147 			ret = add_str_ip_to_ban_list(s, tmsg->ip, tmsg->score);
148 			if (ret < 0) {
149 				reply.reply =
150 				    AUTH__REP__FAILED;
151 			} else {
152 				/* no need to send a reply at all */
153 				ret = 0;
154 				goto cleanup;
155 			}
156 
157 			reply.sid.data = tmsg->sid.data;
158 			reply.sid.len = tmsg->sid.len;
159 			reply.has_sid = tmsg->has_sid;
160 
161 			mslog(s, NULL, LOG_DEBUG, "sending msg %s to sec-mod", cmd_request_to_str(CMD_SECM_BAN_IP_REPLY));
162 
163 			ret = send_msg(NULL, sec_mod_instance->sec_mod_fd, CMD_SECM_BAN_IP_REPLY,
164 				&reply, (pack_size_func)ban_ip_reply_msg__get_packed_size,
165 				(pack_func)ban_ip_reply_msg__pack);
166 			if (ret < 0) {
167 				mslog(s, NULL, LOG_ERR,
168 				      "could not send reply cmd %d.",
169 				      (unsigned)cmd);
170 				ret = ERR_BAD_COMMAND;
171 				goto cleanup;
172 			}
173 
174 			safe_memset(tmsg->sid.data, 0, tmsg->sid.len);
175 			safe_memset(raw, 0, raw_len);
176 		}
177 
178 		break;
179 	case CMD_SECM_STATS:{
180 			SecmStatsMsg *smsg = NULL;
181 
182 			smsg = secm_stats_msg__unpack(&pa, raw_len, raw);
183 			if (smsg == NULL) {
184 				mslog(s, NULL, LOG_ERR, "error unpacking sec-mod data");
185 				ret = ERR_BAD_COMMAND;
186 				goto cleanup;
187 			}
188 
189 			sec_mod_instance->secmod_client_entries = smsg->secmod_client_entries;
190 			sec_mod_instance->tlsdb_entries = smsg->secmod_tlsdb_entries;
191 			sec_mod_instance->max_auth_time = smsg->secmod_max_auth_time;
192 			sec_mod_instance->avg_auth_time = smsg->secmod_avg_auth_time;
193 			update_auth_failures(s, smsg->secmod_auth_failures);
194 
195 		}
196 
197 		break;
198 	default:
199 		mslog(s, NULL, LOG_ERR, "unknown CMD from sec-mod 0x%x.", (unsigned)cmd);
200 		ret = ERR_BAD_COMMAND;
201 		goto cleanup;
202 	}
203 
204 	ret = 0;
205  cleanup:
206 	if (tmsg != NULL)
207 		ban_ip_msg__free_unpacked(tmsg, &pa);
208 	talloc_free(raw);
209 	talloc_free(pool);
210 
211 	return ret;
212 }
213 
append_routes(sec_mod_instance_st * sec_mod_instance,proc_st * proc,GroupCfgSt * gc)214 static void append_routes(sec_mod_instance_st * sec_mod_instance, proc_st *proc, GroupCfgSt *gc)
215 {
216 	vhost_cfg_st *vhost = proc->vhost;
217 
218 	/* if we have known_iroutes, we must append them to the routes list */
219 	if (vhost->perm_config.config->known_iroutes_size > 0 || vhost->perm_config.config->append_routes) {
220 		char **old_routes = gc->routes;
221 		unsigned old_routes_size = gc->n_routes;
222 		unsigned i, j, append;
223 		unsigned to_append = 0;
224 
225 		to_append = vhost->perm_config.config->known_iroutes_size;
226 		if (vhost->perm_config.config->append_routes)
227 			to_append += vhost->perm_config.config->network.routes_size;
228 
229 		gc->n_routes = 0;
230 		gc->routes = talloc_size(proc, sizeof(char*)*(old_routes_size+to_append));
231 
232 		for (i=0;i<old_routes_size;i++) {
233 			gc->routes[i] = talloc_strdup(proc, old_routes[i]);
234 			if (gc->routes[i] == NULL)
235 				break;
236 			gc->n_routes++;
237 		}
238 
239 		if (gc->routes) {
240 			/* Append any iroutes that are known and don't match the client's */
241 			for (i=0;i<vhost->perm_config.config->known_iroutes_size;i++) {
242 				append = 1;
243 				for (j=0;j<gc->n_iroutes;j++) {
244 					if (strcmp(gc->iroutes[j], vhost->perm_config.config->known_iroutes[i]) == 0) {
245 						append = 0;
246 						break;
247 					}
248 				}
249 
250 				if (append) {
251 					gc->routes[gc->n_routes] = talloc_strdup(proc, vhost->perm_config.config->known_iroutes[i]);
252 					if (gc->routes[gc->n_routes] == NULL)
253 						break;
254 					gc->n_routes++;
255 				}
256 			}
257 		}
258 
259 		if (vhost->perm_config.config->append_routes) {
260 			/* Append all global routes */
261 			if (gc->routes) {
262 				for (i=0;i<vhost->perm_config.config->network.routes_size;i++) {
263 					gc->routes[gc->n_routes] = talloc_strdup(proc, vhost->perm_config.config->network.routes[i]);
264 					if (gc->routes[gc->n_routes] == NULL)
265 						break;
266 					gc->n_routes++;
267 				}
268 			}
269 
270 			/* Append no-routes */
271 			if (vhost->perm_config.config->network.no_routes_size == 0)
272 				return;
273 
274 			old_routes = gc->no_routes;
275 			old_routes_size = gc->n_no_routes;
276 
277 			gc->n_no_routes = 0;
278 			gc->no_routes = talloc_size(proc, sizeof(char*)*(old_routes_size+vhost->perm_config.config->network.no_routes_size));
279 
280 			for (i=0;i<old_routes_size;i++) {
281 				gc->no_routes[i] = talloc_strdup(proc, old_routes[i]);
282 				if (gc->no_routes[i] == NULL)
283 					break;
284 				gc->n_no_routes++;
285 			}
286 
287 			for (i=0;i<vhost->perm_config.config->network.no_routes_size;i++) {
288 				gc->no_routes[gc->n_no_routes] = talloc_strdup(proc, vhost->perm_config.config->network.no_routes[i]);
289 				if (gc->no_routes[gc->n_no_routes] == NULL)
290 					break;
291 				gc->n_no_routes++;
292 			}
293 		}
294 	}
295 }
296 
297 static
apply_default_config(sec_mod_instance_st * sec_mod_instance,proc_st * proc,GroupCfgSt * gc)298 void apply_default_config(sec_mod_instance_st * sec_mod_instance, proc_st *proc, GroupCfgSt *gc)
299 {
300 	vhost_cfg_st *vhost = proc->vhost;
301 
302 	if (!gc->has_no_udp) {
303 		gc->no_udp = (vhost->perm_config.udp_port!=0)?0:1;
304 		gc->has_no_udp = 1;
305 	}
306 
307 	if (gc->routes == NULL) {
308 		gc->routes = vhost->perm_config.config->network.routes;
309 		gc->n_routes = vhost->perm_config.config->network.routes_size;
310 	}
311 
312 	append_routes(sec_mod_instance, proc, gc);
313 
314 	if (gc->no_routes == NULL) {
315 		gc->no_routes = vhost->perm_config.config->network.no_routes;
316 		gc->n_no_routes = vhost->perm_config.config->network.no_routes_size;
317 	}
318 
319 	if (gc->dns == NULL) {
320 		gc->dns = vhost->perm_config.config->network.dns;
321 		gc->n_dns = vhost->perm_config.config->network.dns_size;
322 	}
323 
324 	if (gc->nbns == NULL) {
325 		gc->nbns = vhost->perm_config.config->network.nbns;
326 		gc->n_nbns = vhost->perm_config.config->network.nbns_size;
327 	}
328 
329 	if (gc->split_dns == NULL) {
330 		gc->split_dns = vhost->perm_config.config->split_dns;
331 		gc->n_split_dns = vhost->perm_config.config->split_dns_size;
332 	}
333 
334 	if (!gc->has_interim_update_secs) {
335 		gc->interim_update_secs = vhost->perm_config.config->stats_report_time;
336 		gc->has_interim_update_secs = 1;
337 	}
338 
339 	if (!gc->has_session_timeout_secs) {
340 		gc->session_timeout_secs = vhost->perm_config.config->session_timeout;
341 		gc->has_session_timeout_secs = 1;
342 	}
343 
344 	if (!gc->has_deny_roaming) {
345 		gc->deny_roaming = vhost->perm_config.config->deny_roaming;
346 		gc->has_deny_roaming = 1;
347 	}
348 
349 	if (!gc->ipv4_net) {
350 		gc->ipv4_net = vhost->perm_config.config->network.ipv4_network;
351 	}
352 
353 	if (!gc->ipv4_netmask) {
354 		gc->ipv4_netmask = vhost->perm_config.config->network.ipv4_netmask;
355 	}
356 
357 	if (!gc->ipv6_net) {
358 		gc->ipv6_net = vhost->perm_config.config->network.ipv6_network;
359 	}
360 
361 	if (!gc->has_ipv6_prefix) {
362 		gc->ipv6_prefix = vhost->perm_config.config->network.ipv6_prefix;
363 		gc->has_ipv6_prefix = 1;
364 	}
365 
366 	if (!gc->has_ipv6_subnet_prefix) {
367 		gc->ipv6_subnet_prefix = vhost->perm_config.config->network.ipv6_subnet_prefix;
368 		gc->has_ipv6_subnet_prefix = 1;
369 	}
370 
371 	if (!gc->cgroup) {
372 		gc->cgroup = vhost->perm_config.config->cgroup;
373 	}
374 
375 #ifdef ANYCONNECT_CLIENT_COMPAT
376 	if (!gc->xml_config_file) {
377 		gc->xml_config_file = vhost->perm_config.config->xml_config_file;
378 	}
379 #endif
380 
381 	if (!gc->has_client_bypass_protocol) {
382 		gc->client_bypass_protocol = vhost->perm_config.config->client_bypass_protocol;
383 		gc->has_client_bypass_protocol = 1;
384 	}
385 
386 	if (!gc->has_rx_per_sec) {
387 		gc->rx_per_sec = vhost->perm_config.config->rx_per_sec;
388 		gc->has_rx_per_sec = 1;
389 	}
390 
391 	if (!gc->has_tx_per_sec) {
392 		gc->tx_per_sec = vhost->perm_config.config->tx_per_sec;
393 		gc->has_tx_per_sec = 1;
394 	}
395 
396 	if (!gc->has_net_priority) {
397 		gc->net_priority = vhost->perm_config.config->net_priority;
398 		gc->has_net_priority = 1;
399 	}
400 
401 	if (!gc->has_keepalive) {
402 		gc->keepalive = vhost->perm_config.config->keepalive;
403 		gc->has_keepalive = 1;
404 	}
405 
406 	if (!gc->has_dpd) {
407 		gc->dpd = vhost->perm_config.config->dpd;
408 		gc->has_dpd = 1;
409 	}
410 
411 	if (!gc->has_mobile_dpd) {
412 		gc->mobile_dpd = vhost->perm_config.config->mobile_dpd;
413 		gc->has_mobile_dpd = 1;
414 	}
415 
416 	if (!gc->has_max_same_clients) {
417 		gc->max_same_clients = vhost->perm_config.config->max_same_clients;
418 		gc->has_max_same_clients = 1;
419 	}
420 
421 	if (!gc->has_tunnel_all_dns) {
422 		gc->tunnel_all_dns = vhost->perm_config.config->tunnel_all_dns;
423 		gc->has_tunnel_all_dns = 1;
424 	}
425 
426 	if (!gc->has_restrict_user_to_routes) {
427 		gc->restrict_user_to_routes = vhost->perm_config.config->restrict_user_to_routes;
428 		gc->has_restrict_user_to_routes = 1;
429 	}
430 
431 	if (!gc->has_mtu) {
432 		gc->mtu = vhost->perm_config.config->network.mtu;
433 		gc->has_mtu = 1;
434 	}
435 
436 	if (!gc->has_idle_timeout) {
437 		gc->idle_timeout = vhost->perm_config.config->idle_timeout;
438 		gc->has_idle_timeout = 1;
439 	}
440 
441 	if (!gc->has_mobile_idle_timeout) {
442 		gc->mobile_idle_timeout = vhost->perm_config.config->mobile_idle_timeout;
443 		gc->has_mobile_idle_timeout = 1;
444 	}
445 
446 	if (gc->n_fw_ports == 0 && vhost->perm_config.config->n_fw_ports > 0) {
447 		gc->n_fw_ports = vhost->perm_config.config->n_fw_ports;
448 		gc->fw_ports = vhost->perm_config.config->fw_ports;
449 	}
450 
451 	/* since we keep pointers on s->config, increase its usage count */
452 	proc->config_usage_count = vhost->perm_config.config->usage_count;
453 	(*proc->config_usage_count)++;
454 }
455 
session_open(sec_mod_instance_st * sec_mod_instance,struct proc_st * proc,const uint8_t * cookie,unsigned cookie_size)456 int session_open(sec_mod_instance_st * sec_mod_instance, struct proc_st *proc, const uint8_t *cookie, unsigned cookie_size)
457 {
458 	int ret, e;
459 	main_server_st * s = sec_mod_instance->server;
460 	SecmSessionOpenMsg ireq = SECM_SESSION_OPEN_MSG__INIT;
461 	SecmSessionReplyMsg *msg = NULL;
462 	char str_ipv4[MAX_IP_STR];
463 	char str_ipv6[MAX_IP_STR];
464 	char str_ip[MAX_IP_STR];
465 
466 	if (cookie == NULL || cookie_size != SID_SIZE)
467 		return -1;
468 
469 	ireq.sid.data = (void*)cookie;
470 	ireq.sid.len = cookie_size;
471 
472 	if (proc->ipv4 &&
473 	    human_addr2((struct sockaddr *)&proc->ipv4->rip, proc->ipv4->rip_len,
474 	    str_ipv4, sizeof(str_ipv4), 0) != NULL) {
475 		ireq.ipv4 = str_ipv4;
476 	}
477 
478 	if (proc->ipv6 &&
479 	    human_addr2((struct sockaddr *)&proc->ipv6->rip, proc->ipv6->rip_len,
480 	    str_ipv6, sizeof(str_ipv6), 0) != NULL) {
481 		ireq.ipv6 = str_ipv6;
482 	}
483 
484 	mslog(s, proc, LOG_DEBUG, "sending msg %s to sec-mod", cmd_request_to_str(CMD_SECM_SESSION_OPEN));
485 
486 	ret = send_msg(proc, sec_mod_instance->sec_mod_fd_sync, CMD_SECM_SESSION_OPEN,
487 		&ireq, (pack_size_func)secm_session_open_msg__get_packed_size,
488 		(pack_func)secm_session_open_msg__pack);
489 	if (ret < 0) {
490 		mslog(s, proc, LOG_ERR,
491 		      "error sending message to sec-mod cmd socket");
492 		return -1;
493 	}
494 
495 	ret = recv_msg(proc, sec_mod_instance->sec_mod_fd_sync, CMD_SECM_SESSION_REPLY,
496 	       (void *)&msg, (unpack_func) secm_session_reply_msg__unpack, MAIN_SEC_MOD_TIMEOUT);
497 	if (ret < 0) {
498 		e = errno;
499 		mslog(s, proc, LOG_ERR, "error receiving auth reply message from sec-mod cmd socket: %s", strerror(e));
500 		return ret;
501 	}
502 
503 	if (msg->reply != AUTH__REP__OK) {
504 		mslog(s, proc, LOG_DEBUG, "session initiation was rejected");
505 		update_auth_failures(s, 1);
506 		return -1;
507 	}
508 
509 	if (msg->username == NULL) {
510 		mslog(s, proc, LOG_INFO, "no username present in session reply");
511 		return -1;
512 	}
513 	strlcpy(proc->username, msg->username, sizeof(proc->username));
514 
515 	if (msg->user_agent != NULL) {
516 		strlcpy(proc->user_agent, msg->user_agent, sizeof(proc->user_agent));
517 	}
518 
519 	if (msg->device_type != NULL) {
520 		strlcpy(proc->device_type, msg->device_type, sizeof(proc->device_type));
521 	}
522 
523 	if (msg->device_platform != NULL) {
524 		strlcpy(proc->device_platform, msg->device_platform, sizeof(proc->device_platform));
525 	}
526 
527 	/* override the group name in order to load the correct configuration in
528 	 * case his group is specified in the certificate */
529 	if (msg->groupname)
530 		strlcpy(proc->groupname, msg->groupname, sizeof(proc->groupname));
531 
532 	if (msg->config == NULL) {
533 		mslog(s, proc, LOG_INFO, "received invalid configuration for '%s'; could not initiate session", proc->username);
534 		return -1;
535 	}
536 
537 	memcpy(proc->ipv4_seed, &msg->ipv4_seed, sizeof(proc->ipv4_seed));
538 
539 	proc->config = msg->config;
540 	proc->vhost = find_vhost(s->vconfig, msg->vhost);
541 
542 	if (proc->config) {
543 		apply_default_config(sec_mod_instance, proc, proc->config);
544 
545 		/* check whether the cookie IP matches */
546 		if (proc->config->deny_roaming != 0) {
547 			if (msg->ip == NULL) {
548 				return -1;
549 			}
550 
551 			if (human_addr2((struct sockaddr *)&proc->remote_addr, proc->remote_addr_len,
552 						    str_ip, sizeof(str_ip), 0) == NULL)
553 				return -1;
554 
555 			if (strcmp(str_ip, msg->ip) != 0) {
556 				mslog(s, proc, LOG_INFO, "user '%s' is re-using cookie from different IP (prev: %s, current: %s); rejecting",
557 					proc->username, msg->ip, str_ip);
558 				return -1;
559 			}
560 		}
561 	}
562 
563 	return 0;
564 }
565 
reset_stats(main_server_st * s,time_t now)566 static void reset_stats(main_server_st *s, time_t now)
567 {
568 	unsigned int i;
569 	unsigned long max_auth_time = 0;
570 	unsigned long avg_auth_time = 0;
571 	for (i = 0; i < s->sec_mod_instance_count; i ++) {
572 		max_auth_time = MAX(max_auth_time, s->sec_mod_instances[i].max_auth_time);
573 		s->sec_mod_instances[i].max_auth_time = 0;
574 		avg_auth_time += s->sec_mod_instances[i].avg_auth_time;
575 		s->sec_mod_instances[i].avg_auth_time = 0;
576 	}
577 	if (s->sec_mod_instance_count != 0)
578 		avg_auth_time /= s->sec_mod_instance_count;
579 	mslog(s, NULL, LOG_INFO, "Start statistics block");
580 	mslog(s, NULL, LOG_INFO, "Total sessions handled: %lu", (unsigned long)s->stats.total_sessions_closed);
581 	mslog(s, NULL, LOG_INFO, "Sessions handled: %lu", (unsigned long)s->stats.sessions_closed);
582 	mslog(s, NULL, LOG_INFO, "Maximum session time: %lu min", (unsigned long)s->stats.max_session_mins);
583 	mslog(s, NULL, LOG_INFO, "Average session time: %lu min", (unsigned long)s->stats.avg_session_mins);
584 	mslog(s, NULL, LOG_INFO, "Closed due to timeout sessions: %lu", (unsigned long)s->stats.session_timeouts);
585 	mslog(s, NULL, LOG_INFO, "Closed due to timeout (idle) sessions: %lu", (unsigned long)s->stats.session_idle_timeouts);
586 	mslog(s, NULL, LOG_INFO, "Closed due to error sessions: %lu", (unsigned long)s->stats.session_errors);
587 
588 	mslog(s, NULL, LOG_INFO, "Total authentication failures: %lu", (unsigned long)s->stats.total_auth_failures);
589 	mslog(s, NULL, LOG_INFO, "Authentication failures: %lu", (unsigned long)s->stats.auth_failures);
590 	mslog(s, NULL, LOG_INFO, "Maximum authentication time: %lu sec", max_auth_time);
591 	mslog(s, NULL, LOG_INFO, "Average authentication time: %lu sec", avg_auth_time);
592 	mslog(s, NULL, LOG_INFO, "Data in: %lu, out: %lu kbytes", (unsigned long)s->stats.kbytes_in, (unsigned long)s->stats.kbytes_out);
593 	mslog(s, NULL, LOG_INFO, "End of statistics block; resetting non-total stats");
594 
595 	s->stats.session_idle_timeouts = 0;
596 	s->stats.session_timeouts = 0;
597 	s->stats.session_errors = 0;
598 	s->stats.sessions_closed = 0;
599 	s->stats.auth_failures = 0;
600 	s->stats.last_reset = now;
601 	s->stats.kbytes_in = 0;
602 	s->stats.kbytes_out = 0;
603 	s->stats.max_session_mins = 0;
604 
605 }
606 
update_main_stats(main_server_st * s,struct proc_st * proc)607 static void update_main_stats(main_server_st * s, struct proc_st *proc)
608 {
609 	uint64_t kb_in, kb_out;
610 	time_t now = time(0), stime;
611 	vhost_cfg_st *vhost = proc->vhost;
612 
613 	if (vhost->perm_config.stats_reset_time != 0 &&
614 	    now - s->stats.last_reset > vhost->perm_config.stats_reset_time) {
615 		mslog(s, NULL, LOG_INFO, "resetting stats counters");
616 		reset_stats(s, now);
617 	}
618 
619 	if (proc->discon_reason == REASON_IDLE_TIMEOUT)
620 		s->stats.session_idle_timeouts++;
621 	else if (proc->discon_reason == REASON_SESSION_TIMEOUT)
622 		s->stats.session_timeouts++;
623 	else if (proc->discon_reason == REASON_ERROR)
624 		s->stats.session_errors++;
625 
626 	s->stats.sessions_closed++;
627 	s->stats.total_sessions_closed++;
628 	if (s->stats.sessions_closed == 0) { /* overflow */
629 		goto reset;
630 	}
631 
632 	kb_in = proc->bytes_in/1000;
633 	kb_out = proc->bytes_out/1000;
634 
635 	if (s->stats.kbytes_in + kb_in <  s->stats.kbytes_in)
636 		goto reset;
637 
638 	if (s->stats.kbytes_out + kb_out <  s->stats.kbytes_out)
639 		goto reset;
640 
641 	s->stats.kbytes_in += kb_in;
642 	s->stats.kbytes_out += kb_out;
643 
644 	if (s->stats.min_mtu == 0 || proc->mtu < s->stats.min_mtu)
645 		s->stats.min_mtu = proc->mtu;
646 	if (s->stats.max_mtu == 0 || proc->mtu > s->stats.min_mtu)
647 		s->stats.max_mtu = proc->mtu;
648 
649 	/* connection time in minutes */
650 	stime = (now - proc->conn_time)/60;
651 	if (stime > 0) {
652 		s->stats.avg_session_mins = ((s->stats.sessions_closed-1) * s->stats.avg_session_mins + stime) / s->stats.sessions_closed;
653 		if (stime > s->stats.max_session_mins)
654 			s->stats.max_session_mins = stime;
655 	}
656 
657 	return;
658  reset:
659 	mslog(s, NULL, LOG_INFO, "overflow on updating server statistics, resetting stats");
660 	reset_stats(s, now);
661 }
662 
session_close(sec_mod_instance_st * sec_mod_instance,struct proc_st * proc)663 int session_close(sec_mod_instance_st * sec_mod_instance, struct proc_st *proc)
664 {
665 	main_server_st * s = sec_mod_instance->server;
666 	int ret, e;
667 	SecmSessionCloseMsg ireq = SECM_SESSION_CLOSE_MSG__INIT;
668 	CliStatsMsg *msg = NULL;
669 	PROTOBUF_ALLOCATOR(pa, proc);
670 
671 	ireq.uptime = time(0)-proc->conn_time;
672 	ireq.has_uptime = 1;
673 	ireq.bytes_in = proc->bytes_in;
674 	ireq.has_bytes_in = 1;
675 	ireq.bytes_out = proc->bytes_out;
676 	ireq.has_bytes_out = 1;
677 	ireq.sid.data = proc->sid;
678 	ireq.sid.len = sizeof(proc->sid);
679 
680 	if (proc->invalidated)
681 		ireq.server_disconnected = 1;
682 
683 	mslog(s, proc, LOG_DEBUG, "sending msg %s to sec-mod", cmd_request_to_str(CMD_SECM_SESSION_CLOSE));
684 
685 	ret = send_msg(proc, sec_mod_instance->sec_mod_fd_sync, CMD_SECM_SESSION_CLOSE,
686 		&ireq, (pack_size_func)secm_session_close_msg__get_packed_size,
687 		(pack_func)secm_session_close_msg__pack);
688 	if (ret < 0) {
689 		mslog(s, proc, LOG_ERR,
690 		      "error sending message to sec-mod cmd socket");
691 		return -1;
692 	}
693 
694 	ret = recv_msg(proc, sec_mod_instance->sec_mod_fd_sync, CMD_SECM_CLI_STATS,
695 	       (void *)&msg, (unpack_func) cli_stats_msg__unpack, MAIN_SEC_MOD_TIMEOUT);
696 	if (ret < 0) {
697 		e = errno;
698 		mslog(s, proc, LOG_ERR, "error receiving auth cli stats message from sec-mod cmd socket: %s", strerror(e));
699 		return ret;
700 	}
701 
702 	proc->bytes_in = msg->bytes_in;
703 	proc->bytes_out = msg->bytes_out;
704 	if (msg->has_discon_reason) {
705 		proc->discon_reason = msg->discon_reason;
706 	}
707 
708 	update_main_stats(s, proc);
709 
710 	cli_stats_msg__free_unpacked(msg, &pa);
711 
712 	return 0;
713 }
714 
secmod_reload(sec_mod_instance_st * sec_mod_instance)715 int secmod_reload(sec_mod_instance_st * sec_mod_instance)
716 {
717 	main_server_st * s = sec_mod_instance->server;
718 	int ret, e;
719 
720 	mslog(s, NULL, LOG_DEBUG, "sending msg %s to sec-mod", cmd_request_to_str(CMD_SECM_RELOAD));
721 
722 	ret = send_msg(s->main_pool, sec_mod_instance->sec_mod_fd_sync, CMD_SECM_RELOAD,
723 		       NULL, NULL, NULL);
724 	if (ret < 0) {
725 		mslog(s, NULL, LOG_ERR,
726 		      "error sending message to sec-mod cmd socket");
727 		return -1;
728 	}
729 
730 	ret = recv_msg(s->main_pool, sec_mod_instance->sec_mod_fd_sync, CMD_SECM_RELOAD_REPLY,
731 		       NULL, NULL, MAIN_SEC_MOD_TIMEOUT);
732 	if (ret < 0) {
733 		e = errno;
734 		mslog(s, NULL, LOG_ERR, "error receiving reload reply message from sec-mod cmd socket: %s", strerror(e));
735 		return ret;
736 	}
737 
738 	return 0;
739 }
740 
clear_unneeded_mem(struct list_head * vconfig)741 static void clear_unneeded_mem(struct list_head *vconfig)
742 {
743 	vhost_cfg_st *vhost = NULL;
744 
745 	/* deinitialize certificate credentials etc. */
746 	list_for_each_rev(vconfig, vhost, list) {
747 		tls_vhost_deinit(vhost);
748 	}
749 }
750 
751 /* Returns two file descriptors to be used for communication with sec-mod.
752  * The sync_fd is used by main to send synchronous commands- commands which
753  * expect a reply immediately.
754  */
run_sec_mod(sec_mod_instance_st * sec_mod_instance,unsigned int instance_index)755 void run_sec_mod(sec_mod_instance_st * sec_mod_instance, unsigned int instance_index)
756 {
757 	int e, fd[2], ret;
758 	int sfd[2];
759 	pid_t pid;
760 	const char *p;
761 
762 	main_server_st * s = sec_mod_instance->server;
763 
764 	/* fills sec_mod_instance->socket_file */
765 
766 	snprintf(sec_mod_instance->socket_file, sizeof(sec_mod_instance->socket_file), "%s.%d", secmod_socket_file_name(GETPCONFIG(s)), instance_index);
767 	mslog(s, NULL, LOG_DEBUG, "created sec-mod socket file (%s)", sec_mod_instance->socket_file);
768 
769 	if (GETPCONFIG(s)->chroot_dir != NULL) {
770 		ret = snprintf(sec_mod_instance->full_socket_file, sizeof(sec_mod_instance->full_socket_file), "%s/%s",
771 			       GETPCONFIG(s)->chroot_dir, sec_mod_instance->socket_file);
772 		if (ret != strlen(sec_mod_instance->full_socket_file)) {
773 			mslog(s, NULL, LOG_ERR, "too long chroot path; cannot create socket: %s", sec_mod_instance->full_socket_file);
774 			exit(1);
775 		}
776 	} else {
777 		strlcpy(sec_mod_instance->full_socket_file, sec_mod_instance->socket_file, sizeof(sec_mod_instance->full_socket_file));
778 	}
779 
780 	p = sec_mod_instance->full_socket_file;
781 
782 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
783 	if (ret < 0) {
784 		mslog(s, NULL, LOG_ERR, "error creating sec-mod command socket");
785 		exit(1);
786 	}
787 
788 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sfd);
789 	if (ret < 0) {
790 		mslog(s, NULL, LOG_ERR, "error creating sec-mod sync command socket");
791 		exit(1);
792 	}
793 
794 	pid = fork();
795 	if (pid == 0) {		/* child */
796 		clear_lists(s);
797 		kill_on_parent_kill(SIGTERM);
798 
799 #ifdef HAVE_MALLOC_TRIM
800 		/* try to return all the pages we've freed to
801 		 * the operating system. */
802 		malloc_trim(0);
803 #endif
804 		setproctitle(PACKAGE_NAME "-sm");
805 		close(fd[1]);
806 		close(sfd[1]);
807 		set_cloexec_flag (fd[0], 1);
808 		set_cloexec_flag (sfd[0], 1);
809 		clear_unneeded_mem(s->vconfig);
810 		sec_mod_server(s->main_pool, s->config_pool, s->vconfig, p, fd[0], sfd[0], sizeof(s->hmac_key), s->hmac_key, instance_index);
811 		exit(0);
812 	} else if (pid > 0) {	/* parent */
813 		close(fd[0]);
814 		close(sfd[0]);
815 		sec_mod_instance->sec_mod_pid = pid;
816 		set_cloexec_flag (fd[1], 1);
817 		set_cloexec_flag (sfd[1], 1);
818 		sec_mod_instance->sec_mod_fd_sync = sfd[1];
819 		sec_mod_instance->sec_mod_fd = fd[1];
820 		return;
821 	} else {
822 		e = errno;
823 		mslog(s, NULL, LOG_ERR, "error in fork(): %s", strerror(e));
824 		exit(1);
825 	}
826 }
827 
828