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