1 /*
2  * Copyright (C) 2014-2017 Red Hat
3  * Copyright (C) 2014-2018 Nikos Mavrogiannopoulos
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of ocserv.
8  *
9  * ocserv is free software: you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * ocserv is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <c-ctype.h>
31 #include <ctl.h>
32 #include <ctl.pb-c.h>
33 #include <occtl/occtl.h>
34 #include <common.h>
35 #include <c-strcase.h>
36 #include <arpa/inet.h>
37 #include <system.h>
38 #include <termios.h>
39 #include <unistd.h>
40 #include <minmax.h>
41 #include <sys/select.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/socket.h>
46 #include <sys/un.h>
47 #include <assert.h>
48 #include "hex.h"
49 #include "geoip.h"
50 #include <vpn.h>
51 #include <base64-helper.h>
52 
53 /* In JSON output include fields which were no longer available after 0.11.7
54  */
55 #undef OCSERV_0_11_6_COMPAT
56 
57 static
58 int common_info_cmd(UserListRep *args, FILE *out, cmd_params_st *params);
59 static
60 int session_info_cmd(void *ctx, SecmListCookiesReplyMsg * args, FILE *out,
61 		    cmd_params_st *params,
62 		    const char *lsid, unsigned all);
63 
64 struct unix_ctx {
65 	int fd;
66 	int is_open;
67 	const char *socket_file;
68 };
69 
70 static uint8_t msg_map[] = {
71         [CTL_CMD_STATUS] = CTL_CMD_STATUS_REP,
72         [CTL_CMD_RELOAD] = CTL_CMD_RELOAD_REP,
73         [CTL_CMD_STOP] = CTL_CMD_STOP_REP,
74         [CTL_CMD_LIST] = CTL_CMD_LIST_REP,
75         [CTL_CMD_LIST_COOKIES] = CTL_CMD_LIST_COOKIES_REP,
76         [CTL_CMD_LIST_BANNED] = CTL_CMD_LIST_BANNED_REP,
77         [CTL_CMD_USER_INFO] = CTL_CMD_LIST_REP,
78         [CTL_CMD_TOP] = CTL_CMD_LIST_REP,
79         [CTL_CMD_ID_INFO] = CTL_CMD_LIST_REP,
80         [CTL_CMD_DISCONNECT_NAME] = CTL_CMD_DISCONNECT_NAME_REP,
81         [CTL_CMD_DISCONNECT_ID] = CTL_CMD_DISCONNECT_ID_REP,
82         [CTL_CMD_UNBAN_IP] = CTL_CMD_UNBAN_IP_REP,
83 };
84 
85 struct cmd_reply_st {
86 	unsigned cmd;
87 	uint8_t *data;
88 	unsigned data_size;
89 };
90 
free_reply(struct cmd_reply_st * rep)91 static void free_reply(struct cmd_reply_st *rep)
92 {
93 	talloc_free(rep->data);
94 }
95 
init_reply(struct cmd_reply_st * rep)96 static void init_reply(struct cmd_reply_st *rep)
97 {
98 	if (rep)
99 		rep->data = NULL;
100 }
101 
102 /* sends a message and returns the reply */
103 static
send_cmd(struct unix_ctx * ctx,unsigned cmd,const void * data,pack_size_func get_size,pack_func pack,struct cmd_reply_st * rep)104 int send_cmd(struct unix_ctx *ctx, unsigned cmd, const void *data,
105 		 pack_size_func get_size, pack_func pack,
106 		 struct cmd_reply_st *rep)
107 {
108 	int e, ret;
109 	uint32_t length32 = 0;
110 	void *packed = NULL;
111 	uint8_t rcmd;
112 
113 	ret = send_msg(ctx, ctx->fd, cmd, data, get_size, pack);
114 	if (ret < 0) {
115 		e = errno;
116 		fprintf(stderr, "writev: %s\n", strerror(e));
117 		ret = -1;
118 		goto fail;
119 	}
120 
121 	if (rep != NULL) {
122 		ret = recv_msg_headers(ctx->fd, &rcmd, DEFAULT_TIMEOUT);
123 		if (ret < 0) {
124 			/*e = errno;
125 			fprintf(stderr, "read: %s\n", strerror(e));*/
126 			ret = -1;
127 			goto fail;
128 		}
129 
130 		rep->cmd = rcmd;
131 		length32 = ret;
132 
133 		if (msg_map[cmd] != rep->cmd) {
134 			fprintf(stderr, "Unexpected message '%d', expected '%d'\n", (int)rep->cmd, (int)msg_map[cmd]);
135 			ret = -1;
136 			goto fail;
137 		}
138 
139 		rep->data_size = length32;
140 		rep->data = talloc_size(ctx, length32);
141 		if (rep->data == NULL) {
142 			fprintf(stderr, "memory error\n");
143 			ret = -1;
144 			goto fail;
145 		}
146 
147 		ret = force_read_timeout(ctx->fd, rep->data, length32, DEFAULT_TIMEOUT);
148 		if (ret == -1) {
149 			e = errno;
150 			talloc_free(rep->data);
151 			rep->data = NULL;
152 			fprintf(stderr, "read: %s\n", strerror(e));
153 			ret = -1;
154 			goto fail;
155 		}
156 	}
157 
158 	ret = 0;
159  fail:
160 	talloc_free(packed);
161 	return ret;
162 }
163 
164 static
connect_to_ocserv(const char * socket_file)165 int connect_to_ocserv (const char *socket_file)
166 {
167 	int sd, ret, e;
168 	struct sockaddr_un sa;
169 
170 	if (socket_file == NULL)
171 		socket_file = OCCTL_UNIX_SOCKET;
172 
173 	memset(&sa, 0, sizeof(sa));
174 	sa.sun_family = AF_UNIX;
175 	snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", socket_file);
176 
177 	sd = socket(AF_UNIX, SOCK_STREAM, 0);
178 	if (sd == -1) {
179 		e = errno;
180 		fprintf(stderr, "error opening socket: %s\n", strerror(e));
181 		return -1;
182 	}
183 
184 	ret = connect(sd, (struct sockaddr *)&sa, sizeof(sa));
185 	if (ret == -1) {
186 		e = errno;
187 		fprintf(stderr, "error connecting to ocserv socket '%s': %s\n",
188 			sa.sun_path, strerror(e));
189 		ret = -1;
190 		goto error;
191 	}
192 
193 	return sd;
194 error:
195 	close(sd);
196 	return ret;
197 
198 }
199 
handle_status_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)200 int handle_status_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
201 {
202 	int ret;
203 	struct cmd_reply_st raw;
204 	StatusRep *rep;
205 	char str_since[64];
206 	char buf[MAX_TMPSTR_SIZE];
207 	time_t t;
208 	struct tm *tm, _tm;
209 	PROTOBUF_ALLOCATOR(pa, ctx);
210 
211 	init_reply(&raw);
212 
213 	print_start_block(stdout, params);
214 	if (NO_JSON(params)) {
215 		printf("Note: the printed statistics are not real-time; session time\n");
216 		printf("as well as RX and TX data are updated on user disconnect\n");
217 	}
218 
219 	ret = send_cmd(ctx, CTL_CMD_STATUS, NULL, NULL, NULL, &raw);
220 	if (ret < 0) {
221 		goto error_status;
222 	}
223 
224 	rep = status_rep__unpack(&pa, raw.data_size, raw.data);
225 	if (rep == NULL)
226 		goto error_status;
227 
228 
229 	if (rep->status) {
230 		print_separator(stdout, params);
231 
232 		if (NO_JSON(params))
233 			printf("General info:\n");
234 
235 		print_single_value(stdout, params, "Status", rep->status != 0 ? "online" : "error", 1);
236 		print_single_value_int(stdout, params, "Server PID", rep->pid, 1);
237 		print_single_value_int(stdout, params, "Sec-mod PID", rep->sec_mod_pids[0], 1);
238 		print_single_value_int(stdout, params, "Sec-mod instance count", rep->n_sec_mod_pids, 1);
239 
240 		t = rep->start_time;
241 		tm = localtime_r(&t, &_tm);
242 		print_time_ival7(buf, time(0), t);
243 		strftime(str_since, sizeof(str_since), DATE_TIME_FMT, tm);
244 
245 		print_single_value_ex(stdout, params, "Up since", str_since, buf, 1);
246 		if (HAVE_JSON(params)) {
247 			print_single_value_int(stdout, params, "raw_up_since", rep->start_time, 1);
248 			print_single_value_int(stdout, params, "uptime", ((long)time(0)) - ((long)rep->start_time), 1);
249 		}
250 		print_single_value_int(stdout, params, "Active sessions", rep->active_clients, 1);
251 		print_single_value_int(stdout, params, "Total sessions", rep->total_sessions_closed, 1);
252 		print_single_value_int(stdout, params, "Total authentication failures", rep->total_auth_failures, 1);
253 		print_single_value_int(stdout, params, "IPs in ban list", rep->banned_ips, 1);
254 		if (params && params->debug) {
255 			print_single_value_int(stdout, params, "Sec-mod client entries", rep->secmod_client_entries, 1);
256 #if defined(CAPTURE_LATENCY_SUPPORT)
257 			print_single_value_int(stdout, params, "TLS DB entries", rep->stored_tls_sessions, 1);
258 #else
259 			print_single_value_int(stdout, params, "TLS DB entries", rep->stored_tls_sessions, 0);
260 #endif
261 		}
262 
263 #if defined(CAPTURE_LATENCY_SUPPORT)
264 		if (rep->has_latency_sample_count) {
265 			unsigned int median_latency = (unsigned int)(rep->latency_sample_count ? rep->latency_median_total / rep->latency_sample_count : 0);
266 			unsigned int stdev_latency = (unsigned int)(rep->latency_sample_count ? rep->latency_rms_total / rep->latency_sample_count : 0);
267 
268 			time2human(median_latency, buf, sizeof(buf));
269 			print_single_value(stdout, params, "Median latency", buf, 1);
270 			if (HAVE_JSON(params))
271 				print_single_value_int(stdout, params, "raw_median_latency", median_latency, 1);
272 
273 			time2human(stdev_latency, buf, sizeof(buf));
274 			print_single_value(stdout, params, "STDEV latency", buf, 1);
275 			if (HAVE_JSON(params))
276 				print_single_value_int(stdout, params, "raw_stdev_latency", stdev_latency, 1);
277 
278 		}
279 #endif
280 
281 		print_separator(stdout, params);
282 		if (NO_JSON(params))
283 			printf("Current stats period:\n");
284 
285 		t = rep->last_reset;
286 		if (t > 0) {
287 			tm = localtime_r(&t, &_tm);
288 			print_time_ival7(buf, time(0), t);
289 			strftime(str_since, sizeof(str_since), DATE_TIME_FMT, tm);
290 
291 			print_single_value_ex(stdout, params, "Last stats reset", str_since, buf, 1);
292 			if (HAVE_JSON(params))
293 				print_single_value_int(stdout, params, "raw_last_stats_reset", rep->last_reset, 1);
294 		}
295 
296 		print_single_value_int(stdout, params, "Sessions handled", rep->sessions_closed, 1);
297 		print_single_value_int(stdout, params, "Timed out sessions", rep->session_timeouts, 1);
298 		print_single_value_int(stdout, params, "Timed out (idle) sessions", rep->session_idle_timeouts, 1);
299 		print_single_value_int(stdout, params, "Closed due to error sessions", rep->session_errors, 1);
300 		print_single_value_int(stdout, params, "Authentication failures", rep->auth_failures, 1);
301 
302 		print_time_ival7(buf, rep->avg_auth_time, 0);
303 		print_single_value(stdout, params, "Average auth time", buf, 1);
304 		if (HAVE_JSON(params))
305 			print_single_value_int(stdout, params, "raw_avg_auth_time", rep->avg_auth_time, 1);
306 
307 		print_time_ival7(buf, rep->max_auth_time, 0);
308 		print_single_value(stdout, params, "Max auth time", buf, 1);
309 		if (HAVE_JSON(params))
310 			print_single_value_int(stdout, params, "raw_max_auth_time", rep->max_auth_time, 1);
311 
312 		print_time_ival7(buf, rep->avg_session_mins*60, 0);
313 		print_single_value(stdout, params, "Average session time", buf, 1);
314 		if (HAVE_JSON(params))
315 			print_single_value_int(stdout, params, "raw_avg_session_time", rep->avg_session_mins*60, 1);
316 
317 		print_time_ival7(buf, rep->max_session_mins*60, 0);
318 		print_single_value(stdout, params, "Max session time", buf, 1);
319 		if (HAVE_JSON(params))
320 			print_single_value_int(stdout, params, "raw_max_session_time", rep->max_session_mins*60, 1);
321 
322 		if (rep->min_mtu > 0)
323 			print_single_value_int(stdout, params, "Min MTU", rep->min_mtu, 1);
324 		if (rep->max_mtu > 0)
325 			print_single_value_int(stdout, params, "Max MTU", rep->max_mtu, 1);
326 
327 		bytes2human(rep->kbytes_in*1000, buf, sizeof(buf), "");
328 		print_single_value(stdout, params, "RX", buf, 1);
329 		if (HAVE_JSON(params))
330 			print_single_value_int(stdout, params, "raw_rx", rep->kbytes_in*1000, 1);
331 		bytes2human(rep->kbytes_out*1000, buf, sizeof(buf), "");
332 		print_single_value(stdout, params, "TX", buf, 1);
333 		if (HAVE_JSON(params))
334 			print_single_value_int(stdout, params, "raw_tx", rep->kbytes_out*1000, 0);
335 	}
336 
337 	print_end_block(stdout, params, 0);
338 
339 	status_rep__free_unpacked(rep, &pa);
340 
341 	ret = 0;
342 	goto cleanup;
343 
344  error_status:
345 	print_single_value(stdout, params, "Status", "offline", 0);
346 	print_end_block(stdout, params, 0);
347 	ret = 1;
348 
349  cleanup:
350  	free_reply(&raw);
351 	return ret;
352 }
353 
handle_reload_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)354 int handle_reload_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
355 {
356 	int ret;
357 	struct cmd_reply_st raw;
358 	BoolMsg *rep;
359 	unsigned status;
360 	PROTOBUF_ALLOCATOR(pa, ctx);
361 
362 	init_reply(&raw);
363 
364 	ret = send_cmd(ctx, CTL_CMD_RELOAD, NULL, NULL, NULL, &raw);
365 	if (ret < 0) {
366 		goto error_status;
367 	}
368 
369 	rep = bool_msg__unpack(&pa, raw.data_size, raw.data);
370 	if (rep == NULL)
371 		goto error_status;
372 
373 	status = rep->status;
374 	bool_msg__free_unpacked(rep, &pa);
375 
376 	if (status != 0)
377         	printf("Server scheduled to reload\n");
378 	else
379 		goto error_status;
380 
381 	ret = 0;
382 	goto cleanup;
383 
384  error_status:
385 	printf("Error scheduling reload\n");
386 	ret = 1;
387 
388  cleanup:
389 	free_reply(&raw);
390 
391 	return ret;
392 }
393 
handle_stop_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)394 int handle_stop_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
395 {
396 	int ret;
397 	struct cmd_reply_st raw;
398 	BoolMsg *rep;
399 	unsigned status;
400 	PROTOBUF_ALLOCATOR(pa, ctx);
401 
402 	init_reply(&raw);
403 
404 	ret = send_cmd(ctx, CTL_CMD_STOP, NULL, NULL, NULL, &raw);
405 	if (ret < 0) {
406 		goto error_status;
407 	}
408 
409 	rep = bool_msg__unpack(&pa, raw.data_size, raw.data);
410 	if (rep == NULL)
411 		goto error_status;
412 
413 	status = rep->status;
414 	bool_msg__free_unpacked(rep, &pa);
415 
416 	if (status != 0)
417         	printf("Server scheduled to stop\n");
418 	else
419 		goto error_status;
420 
421 	ret = 0;
422 	goto cleanup;
423 
424  error_status:
425 	printf("Error scheduling server stop\n");
426 	ret = 1;
427 	goto cleanup;
428  cleanup:
429 	free_reply(&raw);
430 
431 	return ret;
432 }
433 
handle_unban_ip_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)434 int handle_unban_ip_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
435 {
436 	int ret;
437 	struct cmd_reply_st raw;
438 	BoolMsg *rep;
439 	unsigned status;
440 	UnbanReq req = UNBAN_REQ__INIT;
441 	int af;
442 	unsigned char tmp[16];
443 	PROTOBUF_ALLOCATOR(pa, ctx);
444 
445 	if (arg == NULL || need_help(arg)) {
446 		check_cmd_help(rl_line_buffer);
447 		return 1;
448 	}
449 
450 	init_reply(&raw);
451 
452 	/* convert the IP to the simplest form */
453 	if (strchr(arg, ':') != 0) {
454 		af = AF_INET6;
455 	} else {
456 		af = AF_INET;
457 	}
458 
459 	ret = inet_pton(af, arg, tmp);
460 	if (ret == 1) {
461 		req.ip.data = tmp;
462 		if (af == AF_INET)
463 			req.ip.len = 4;
464 		else
465 			req.ip.len = 16;
466 	} else {
467 		fprintf(stderr, "Cannot parse IP: %s", arg);
468 		return 1;
469 	}
470 
471 	ret = send_cmd(ctx, CTL_CMD_UNBAN_IP, &req,
472 		(pack_size_func)unban_req__get_packed_size,
473 		(pack_func)unban_req__pack, &raw);
474 	if (ret < 0) {
475 		goto error;
476 	}
477 
478 	rep = bool_msg__unpack(&pa, raw.data_size, raw.data);
479 	if (rep == NULL)
480 		goto error;
481 
482 	status = rep->status;
483 	bool_msg__free_unpacked(rep, &pa);
484 
485 	if (status != 0) {
486 		printf("IP '%s' was unbanned\n", arg);
487 		ret = 0;
488 	} else {
489 		printf("could not unban IP '%s'\n", arg);
490 		ret = 1;
491 	}
492 
493 	goto cleanup;
494 
495  error:
496 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
497 	ret = 1;
498  cleanup:
499 	free_reply(&raw);
500 
501 	return ret;
502 }
503 
handle_disconnect_user_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)504 int handle_disconnect_user_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
505 {
506 	int ret;
507 	struct cmd_reply_st raw;
508 	BoolMsg *rep;
509 	unsigned status;
510 	UsernameReq req = USERNAME_REQ__INIT;
511 	PROTOBUF_ALLOCATOR(pa, ctx);
512 
513 	if (arg == NULL || need_help(arg)) {
514 		check_cmd_help(rl_line_buffer);
515 		return 1;
516 	}
517 
518 	init_reply(&raw);
519 
520 	req.username = (void*)arg;
521 
522 	ret = send_cmd(ctx, CTL_CMD_DISCONNECT_NAME, &req,
523 		(pack_size_func)username_req__get_packed_size,
524 		(pack_func)username_req__pack, &raw);
525 	if (ret < 0) {
526 		goto error;
527 	}
528 
529 	rep = bool_msg__unpack(&pa, raw.data_size, raw.data);
530 	if (rep == NULL)
531 		goto error;
532 
533 	status = rep->status;
534 	bool_msg__free_unpacked(rep, &pa);
535 
536 	if (status != 0) {
537 		printf("user '%s' was disconnected\n", arg);
538 		ret = 0;
539 	} else {
540 		printf("could not disconnect user '%s'\n", arg);
541 		ret = 1;
542 	}
543 
544 	goto cleanup;
545 
546  error:
547 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
548 	ret = 1;
549  cleanup:
550 	free_reply(&raw);
551 
552 	return ret;
553 }
554 
handle_disconnect_id_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)555 int handle_disconnect_id_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
556 {
557 	int ret;
558 	struct cmd_reply_st raw;
559 	BoolMsg *rep;
560 	unsigned status;
561 	unsigned id;
562 	IdReq req = ID_REQ__INIT;
563 	PROTOBUF_ALLOCATOR(pa, ctx);
564 
565 	if (arg != NULL)
566 		id = atoi(arg);
567 
568 	if (arg == NULL || need_help(arg) || id == 0) {
569 		check_cmd_help(rl_line_buffer);
570 		return 1;
571 	}
572 
573 	init_reply(&raw);
574 
575 	req.id = id;
576 
577 	ret = send_cmd(ctx, CTL_CMD_DISCONNECT_ID, &req,
578 		(pack_size_func)id_req__get_packed_size,
579 		(pack_func)id_req__pack, &raw);
580 	if (ret < 0) {
581 		goto error;
582 	}
583 
584 	rep = bool_msg__unpack(&pa, raw.data_size, raw.data);
585 	if (rep == NULL)
586 		goto error;
587 
588 	status = rep->status;
589 	bool_msg__free_unpacked(rep, &pa);
590 
591 	if (status != 0) {
592 		printf("connection ID '%s' was disconnected\n", arg);
593 		ret = 0;
594 	} else {
595 		printf("could not disconnect ID '%s'\n", arg);
596 		ret = 1;
597 	}
598 
599 	goto cleanup;
600 
601  error:
602 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
603 	ret = 1;
604  cleanup:
605 	free_reply(&raw);
606 
607 	return ret;
608 }
609 
fix_ciphersuite(char * txt)610 static const char *fix_ciphersuite(char *txt)
611 {
612 	if (txt != NULL && txt[0] != 0) {
613 		if (strlen(txt) > 16 && strncmp(txt, "(DTLS", 5) == 0 &&
614 		    (strncmp(&txt[8], ")-(RSA)-", 8) == 0 || strncmp(&txt[8], ")-(PSK)-", 8) == 0)) {
615 			return txt + 16;
616 		}
617 	}
618 
619 	return "(no-dtls)";
620 }
621 
get_ip(const char * ip1,const char * ip2)622 static const char *get_ip(const char *ip1, const char *ip2)
623 {
624 	if (ip1 != NULL && ip1[0] != 0)
625 		return ip1;
626 	else
627 		return ip2;
628 }
629 
common_user_list(struct unix_ctx * ctx,UserListRep * rep,FILE * out,cmd_params_st * params)630 void common_user_list(struct unix_ctx *ctx, UserListRep *rep, FILE *out, cmd_params_st *params)
631 {
632 	unsigned i;
633 	const char *vpn_ip, *username;
634 	const char *dtls_ciphersuite;
635 	char tmpbuf[MAX_TMPSTR_SIZE];
636 	time_t t;
637 	struct tm *tm, _tm;
638 	char str_since[64];
639 
640 	if (HAVE_JSON(params)) {
641 		common_info_cmd(rep, out, params);
642 	} else for (i=0;i<rep->n_user;i++) {
643 		username = rep->user[i]->username;
644 		if (username == NULL || username[0] == 0)
645 			username = NO_USER;
646 
647 		vpn_ip = get_ip(rep->user[i]->local_ip, rep->user[i]->local_ip6);
648 
649 		/* add header */
650 		if (i == 0) {
651 			fprintf(out, "%8s %8s %8s %14s %14s %6s %7s %14s %9s\n",
652 				"id", "user", "vhost", "ip", "vpn-ip", "device",
653 				"since", "dtls-cipher", "status");
654 		}
655 
656 		t = rep->user[i]->conn_time;
657 		tm = localtime_r(&t, &_tm);
658 		strftime(str_since, sizeof(str_since), DATE_TIME_FMT, tm);
659 
660 		print_time_ival7(tmpbuf, time(0), t);
661 
662 		fprintf(out, "%8d %8s %8s %14s %14s %6s ",
663 			(int)rep->user[i]->id, username, rep->user[i]->vhost, rep->user[i]->ip, vpn_ip, rep->user[i]->tun);
664 
665 		dtls_ciphersuite = fix_ciphersuite(rep->user[i]->dtls_ciphersuite);
666 
667 		fprintf(out, "%s %14s %9s\n", tmpbuf, dtls_ciphersuite, ps_status_to_str(rep->user[i]->status, 0));
668 
669 		entries_add(ctx, username, strlen(username), rep->user[i]->id);
670 	}
671 }
672 
handle_list_users_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)673 int handle_list_users_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
674 {
675 	int ret;
676 	struct cmd_reply_st raw;
677 	UserListRep *rep = NULL;
678 	FILE *out;
679 	PROTOBUF_ALLOCATOR(pa, ctx);
680 
681 	init_reply(&raw);
682 
683 	entries_clear();
684 
685 	out = pager_start(params);
686 
687 	ret = send_cmd(ctx, CTL_CMD_LIST, NULL, NULL, NULL, &raw);
688 	if (ret < 0) {
689 		goto error;
690 	}
691 
692 	rep = user_list_rep__unpack(&pa, raw.data_size, raw.data);
693 	if (rep == NULL)
694 		goto error;
695 
696 	common_user_list(ctx, rep, out, params);
697 
698 	ret = 0;
699 	goto cleanup;
700 
701  error:
702 	ret = 1;
703 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
704 
705  cleanup:
706 	if (rep != NULL)
707 		user_list_rep__free_unpacked(rep, &pa);
708 
709 	free_reply(&raw);
710 	pager_stop(out);
711 
712 	return ret;
713 }
714 
shorten(void * cookie,unsigned session_id_size,unsigned small)715 static char *shorten(void *cookie, unsigned session_id_size, unsigned small)
716 {
717 	static char psid[SAFE_ID_SIZE];
718 
719 	assert(session_id_size <= SAFE_ID_SIZE);
720 	memcpy(psid, cookie, session_id_size);
721 
722 	if (small)
723 		psid[6] = 0;
724 	else
725 		psid[SAFE_ID_SIZE-1] = 0;
726 
727 	return psid;
728 }
729 
730 static
session_list(struct unix_ctx * ctx,SecmListCookiesReplyMsg * rep,FILE * out,cmd_params_st * params,unsigned all)731 void session_list(struct unix_ctx *ctx, SecmListCookiesReplyMsg *rep, FILE *out, cmd_params_st *params,
732 		 unsigned all)
733 {
734 	unsigned i;
735 	const char *username;
736 	char tmpbuf[MAX_TMPSTR_SIZE] = "";
737 	time_t t;
738 	struct tm *tm, _tm;
739 	char str_since[65];
740 	const char *sid;
741 
742 	session_entries_clear();
743 
744 	if (HAVE_JSON(params)) {
745 		session_info_cmd(ctx, rep, out, params, NULL, all);
746 	} else for (i=0;i<rep->n_cookies;i++) {
747 		if (!all && rep->cookies[i]->status != PS_AUTH_COMPLETED)
748 			continue;
749 
750 		username = rep->cookies[i]->username;
751 		if (username == NULL || username[0] == 0)
752 			username = NO_USER;
753 
754 		/* add header */
755 		if (i == 0) {
756 			fprintf(out, "%6s %8s %8s %14s %24s %8s %8s\n",
757 				"session", "user", "vhost", "ip", "user agent", "created", "status");
758 		}
759 
760 		t = rep->cookies[i]->created;
761 		if (t > 0) {
762 			tm = localtime_r(&t, &_tm);
763 			strftime(str_since, sizeof(str_since), DATE_TIME_FMT, tm);
764 			print_time_ival7(tmpbuf, time(0), t);
765 		}
766 
767 		sid = shorten(rep->cookies[i]->safe_id.data, rep->cookies[i]->safe_id.len, 1);
768 		session_entries_add(ctx, sid);
769 
770 		fprintf(out, "%.6s %8s %8s %14s %.24s %8s %8s\n",
771 			sid, username, rep->cookies[i]->vhost, rep->cookies[i]->remote_ip,
772 			rep->cookies[i]->user_agent, tmpbuf, ps_status_to_str(rep->cookies[i]->status, 1));
773 	}
774 }
775 
776 static
handle_list_sessions_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params,unsigned all)777 int handle_list_sessions_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params, unsigned all)
778 {
779 	int ret;
780 	struct cmd_reply_st raw;
781 	SecmListCookiesReplyMsg *rep = NULL;
782 	FILE *out;
783 	PROTOBUF_ALLOCATOR(pa, ctx);
784 
785 	init_reply(&raw);
786 
787 	entries_clear();
788 
789 	out = pager_start(params);
790 
791 	ret = send_cmd(ctx, CTL_CMD_LIST_COOKIES, NULL, NULL, NULL, &raw);
792 	if (ret < 0) {
793 		goto error;
794 	}
795 
796 	rep = secm_list_cookies_reply_msg__unpack(&pa, raw.data_size, raw.data);
797 	if (rep == NULL)
798 		goto error;
799 
800 	session_list(ctx, rep, out, params, all);
801 
802 	ret = 0;
803 	goto cleanup;
804 
805  error:
806 	ret = 1;
807 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
808 
809  cleanup:
810 	if (rep != NULL)
811 		secm_list_cookies_reply_msg__free_unpacked(rep, &pa);
812 
813 	free_reply(&raw);
814 	pager_stop(out);
815 
816 	return ret;
817 }
818 
handle_show_session_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)819 int handle_show_session_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
820 {
821 	int ret;
822 	struct cmd_reply_st raw;
823 	SecmListCookiesReplyMsg *rep = NULL;
824 	FILE *out;
825 	const char *sid = (void*)arg;
826 	PROTOBUF_ALLOCATOR(pa, ctx);
827 
828 	if (arg == NULL || need_help(arg)) {
829 		check_cmd_help(rl_line_buffer);
830 		return 1;
831 	}
832 
833 	init_reply(&raw);
834 
835 	entries_clear();
836 
837 	out = pager_start(params);
838 
839 	ret = send_cmd(ctx, CTL_CMD_LIST_COOKIES, NULL, NULL, NULL, &raw);
840 	if (ret < 0) {
841 		goto error;
842 	}
843 
844 	rep = secm_list_cookies_reply_msg__unpack(&pa, raw.data_size, raw.data);
845 	if (rep == NULL)
846 		goto error;
847 
848 	session_info_cmd(ctx, rep, out, params, sid, 0);
849 
850 	ret = 0;
851 	goto cleanup;
852 
853  error:
854 	ret = 1;
855 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
856 
857  cleanup:
858 	if (rep != NULL)
859 		secm_list_cookies_reply_msg__free_unpacked(rep, &pa);
860 
861 	free_reply(&raw);
862 	pager_stop(out);
863 
864 	return ret;
865 }
866 
handle_list_valid_sessions_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)867 int handle_list_valid_sessions_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
868 {
869 	return handle_list_sessions_cmd(ctx, arg, params, 0);
870 }
871 
handle_list_all_sessions_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)872 int handle_list_all_sessions_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
873 {
874 	return handle_list_sessions_cmd(ctx, arg, params, 1);
875 }
876 
handle_list_iroutes_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)877 int handle_list_iroutes_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
878 {
879 	int ret;
880 	struct cmd_reply_st raw;
881 	UserListRep *rep = NULL;
882 	FILE *out;
883 	unsigned i, j;
884 	PROTOBUF_ALLOCATOR(pa, ctx);
885 
886 	init_reply(&raw);
887 
888 	entries_clear();
889 
890 	out = pager_start(params);
891 
892 	/* get all user info */
893 	ret = send_cmd(ctx, CTL_CMD_LIST, NULL, NULL, NULL, &raw);
894 	if (ret < 0) {
895 		goto error;
896 	}
897 
898 	rep = user_list_rep__unpack(&pa, raw.data_size, raw.data);
899 	if (rep == NULL)
900 		goto error;
901 
902 	/* print iroutes */
903 	if (NO_JSON(params)) {
904 		for (i=0;i<rep->n_user;i++) {
905 			const char *username, *vpn_ip;
906 
907 			username = rep->user[i]->username;
908 			if (username == NULL || username[0] == 0)
909 				username = NO_USER;
910 
911 			vpn_ip = get_ip(rep->user[i]->local_ip, rep->user[i]->local_ip6);
912 
913 			/* add header */
914 			if (i == 0) {
915 				fprintf(out, "%6s %8s %8s %6s %16s %28s\n",
916 					"id", "user", "vhost", "device", "vpn-ip", "iroute");
917 			}
918 
919 			for (j=0;j<rep->user[i]->n_iroutes;j++)
920 				fprintf(out, "%6d %8s %8s %6s %16s %28s\n",
921 					(int)rep->user[i]->id, username, rep->user[i]->vhost, rep->user[i]->tun, vpn_ip, rep->user[i]->iroutes[j]);
922 
923 		}
924 	} else {
925 		print_start_block(out, params);
926 		for (i=0;i<rep->n_user;i++) {
927 			const char *username, *vpn_ip;
928 
929 			username = rep->user[i]->username;
930 			if (username == NULL || username[0] == 0)
931 				username = NO_USER;
932 
933 			vpn_ip = get_ip(rep->user[i]->local_ip, rep->user[i]->local_ip6);
934 
935 			print_single_value_int(out, params, "ID", rep->user[i]->id, 1);
936 			print_single_value(out, params, "Username", username, 1);
937 			print_single_value(out, params, "vhost", rep->user[i]->vhost, 1);
938 			print_single_value(out, params, "Device", rep->user[i]->tun, 1);
939 			print_single_value(out, params, "IP", vpn_ip, 1);
940 			print_list_entries(out, params, "iRoutes", rep->user[i]->iroutes, rep->user[i]->n_iroutes, 1);
941 			print_single_value(out, params, "IP", vpn_ip, 0);
942 		}
943 		print_end_block(out, params, 0);
944 	}
945 
946 	ret = 0;
947 	goto cleanup;
948 
949  error:
950 	ret = 1;
951 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
952 
953  cleanup:
954 	if (rep != NULL)
955 		user_list_rep__free_unpacked(rep, &pa);
956 
957 	free_reply(&raw);
958 	pager_stop(out);
959 
960 	return ret;
961 }
962 
963 static
handle_list_banned_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params,unsigned points)964 int handle_list_banned_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params, unsigned points)
965 {
966 	int ret;
967 	struct cmd_reply_st raw;
968 	BanListRep *rep = NULL;
969 	unsigned i;
970 	char str_since[64];
971 	char tmpbuf[MAX_TMPSTR_SIZE];
972 	FILE *out;
973 	struct tm *tm, _tm;
974 	time_t t;
975 	PROTOBUF_ALLOCATOR(pa, ctx);
976 	char txt_ip[MAX_IP_STR];
977 	const char *tmp_str;
978 
979 	init_reply(&raw);
980 
981 	ip_entries_clear();
982 
983 	out = pager_start(params);
984 
985 	ret = send_cmd(ctx, CTL_CMD_LIST_BANNED, NULL, NULL, NULL, &raw);
986 	if (ret < 0) {
987 		goto error;
988 	}
989 
990 	rep = ban_list_rep__unpack(&pa, raw.data_size, raw.data);
991 	if (rep == NULL)
992 		goto error;
993 
994 	print_array_block(out, params);
995 
996 	for (i=0;i<rep->n_info;i++) {
997 		if (rep->info[i]->ip.len < 4)
998 			continue;
999 
1000 		if (rep->info[i]->ip.len == 16)
1001 			tmp_str = inet_ntop(AF_INET6, rep->info[i]->ip.data, txt_ip, sizeof(txt_ip));
1002 		else
1003 			tmp_str = inet_ntop(AF_INET, rep->info[i]->ip.data, txt_ip, sizeof(txt_ip));
1004 		if (tmp_str == NULL)
1005 			strlcpy(txt_ip, "(unknown)", sizeof(txt_ip));
1006 
1007 		/* add header */
1008 		if (points == 0) {
1009 			if (rep->info[i]->has_expires) {
1010 				t = rep->info[i]->expires;
1011 				tm = localtime_r(&t, &_tm);
1012 				strftime(str_since, sizeof(str_since), DATE_TIME_FMT, tm);
1013 			} else {
1014 				continue;
1015 			}
1016 
1017 			if (i == 0 && NO_JSON(params)) {
1018 				fprintf(out, "%14s %14s %30s\n",
1019 					"IP", "score", "expires");
1020 			}
1021 			print_start_block(out, params);
1022 
1023 			print_time_ival7(tmpbuf, t, time(0));
1024 
1025 			if (HAVE_JSON(params)) {
1026 				print_single_value(out, params, "IP", txt_ip, 1);
1027 				print_single_value_ex(out, params, "Since", str_since, tmpbuf, 1);
1028 				print_single_value_int(out, params, "Score", rep->info[i]->score, 0);
1029 			} else {
1030 				fprintf(out, "%14s %14u %30s (%s)\n",
1031 					txt_ip, (unsigned)rep->info[i]->score, str_since, tmpbuf);
1032 			}
1033 		} else {
1034 			if (i == 0 && NO_JSON(params)) {
1035 				fprintf(out, "%14s %14s\n",
1036 					"IP", "score");
1037 			}
1038 			print_start_block(out, params);
1039 
1040 			if (HAVE_JSON(params)) {
1041 				print_single_value(out, params, "IP", txt_ip, 1);
1042 				print_single_value_int(out, params, "Score", rep->info[i]->score, 0);
1043 			} else {
1044 				fprintf(out, "%14s %14u\n",
1045 					txt_ip, (unsigned)rep->info[i]->score);
1046 			}
1047 		}
1048 
1049 		print_end_block(out, params, i<(rep->n_info-1)?1:0);
1050 
1051 		ip_entries_add(ctx, txt_ip, strlen(txt_ip));
1052 	}
1053 
1054 	print_end_array_block(out, params);
1055 
1056 	ret = 0;
1057 	goto cleanup;
1058 
1059  error:
1060 	ret = 1;
1061 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
1062 
1063  cleanup:
1064 	if (rep != NULL)
1065 		ban_list_rep__free_unpacked(rep, &pa);
1066 
1067 	free_reply(&raw);
1068 	pager_stop(out);
1069 
1070 	return ret;
1071 }
1072 
handle_list_banned_ips_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)1073 int handle_list_banned_ips_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
1074 {
1075 	return handle_list_banned_cmd(ctx, arg, params, 0);
1076 }
1077 
handle_list_banned_points_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)1078 int handle_list_banned_points_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
1079 {
1080 	return handle_list_banned_cmd(ctx, arg, params, 1);
1081 }
1082 
1083 
int2str(char tmpbuf[MAX_TMPSTR_SIZE],int i)1084 static char *int2str(char tmpbuf[MAX_TMPSTR_SIZE], int i)
1085 {
1086 	tmpbuf[0] = 0;
1087 	snprintf(tmpbuf, MAX_TMPSTR_SIZE, "%d", i);
1088 	return tmpbuf;
1089 }
1090 
1091 static
common_info_cmd(UserListRep * args,FILE * out,cmd_params_st * params)1092 int common_info_cmd(UserListRep * args, FILE *out, cmd_params_st *params)
1093 {
1094 	char *username = "";
1095 	char *groupname = "";
1096 	char str_since[64];
1097 	char tmpbuf[MAX_TMPSTR_SIZE];
1098 	char tmpbuf2[MAX_TMPSTR_SIZE];
1099 	struct tm *tm, _tm;
1100 	time_t t;
1101 	unsigned at_least_one = 0;
1102 	int ret = 1, r;
1103 	unsigned i;
1104 	unsigned init_pager = 0;
1105 
1106 	if (out == NULL) {
1107 		out = pager_start(params);
1108 		init_pager = 1;
1109 	}
1110 
1111 	if (HAVE_JSON(params))
1112 		fprintf(out, "[\n");
1113 
1114 	for (i=0;i<args->n_user;i++) {
1115 		if (at_least_one > 0)
1116 			fprintf(out, "\n");
1117 
1118 		print_start_block(out, params);
1119 
1120 		print_single_value_int(out, params, "ID", args->user[i]->id, 1);
1121 
1122 		t = args->user[i]->conn_time;
1123 		tm = localtime_r(&t, &_tm);
1124 		strftime(str_since, sizeof(str_since), DATE_TIME_FMT, tm);
1125 
1126 		username = args->user[i]->username;
1127 		if (username == NULL || username[0] == 0)
1128 			username = NO_USER;
1129 
1130 
1131 		groupname = args->user[i]->groupname;
1132 		if (groupname == NULL || groupname[0] == 0)
1133 			groupname = NO_GROUP;
1134 
1135 		print_pair_value(out, params, "Username", username, "Groupname", groupname, 1);
1136 
1137 		print_single_value(out, params, "State", ps_status_to_str(args->user[i]->status, 0), 1);
1138 		print_single_value(out, params, "vhost", args->user[i]->vhost, 1);
1139 		if (args->user[i]->has_mtu != 0)
1140 			print_pair_value(out, params, "Device", args->user[i]->tun, "MTU", int2str(tmpbuf, args->user[i]->mtu), 1);
1141 		else
1142 			print_single_value(out, params, "Device", args->user[i]->tun, 1);
1143 		print_pair_value(out, params, "Remote IP", args->user[i]->ip, "Location", geo_lookup(args->user[i]->ip, tmpbuf, sizeof(tmpbuf)), 1);
1144 		print_single_value(out, params, "Local Device IP", args->user[i]->local_dev_ip, 1);
1145 
1146 		if (args->user[i]->local_ip != NULL && args->user[i]->local_ip[0] != 0 &&
1147 		    args->user[i]->remote_ip != NULL && args->user[i]->remote_ip[0] != 0) {
1148 			print_pair_value(out, params, "IPv4", args->user[i]->local_ip, "P-t-P IPv4", args->user[i]->remote_ip, 1);
1149 		}
1150 		if (args->user[i]->local_ip6 != NULL && args->user[i]->local_ip6[0] != 0 &&
1151 		    args->user[i]->remote_ip6 != NULL && args->user[i]->remote_ip6[0] != 0) {
1152 			print_pair_value(out, params, "IPv6", args->user[i]->local_ip6, "P-t-P IPv6", args->user[i]->remote_ip6, 1);
1153 		}
1154 
1155 		print_single_value(out, params, "User-Agent", args->user[i]->user_agent, 1);
1156 
1157 		if (args->user[i]->rx_per_sec > 0 || args->user[i]->tx_per_sec > 0) {
1158 			/* print limits */
1159 			char buf1[32];
1160 			char buf2[32];
1161 
1162 			if (args->user[i]->rx_per_sec > 0 && args->user[i]->tx_per_sec > 0) {
1163 				bytes2human(args->user[i]->rx_per_sec, buf1, sizeof(buf1), "/sec");
1164 				bytes2human(args->user[i]->tx_per_sec, buf2, sizeof(buf2), "/sec");
1165 
1166 				print_pair_value(out, params, "Limit RX", buf1, "TX", buf2, 1);
1167 			} else if (args->user[i]->tx_per_sec > 0) {
1168 				bytes2human(args->user[i]->tx_per_sec, buf1, sizeof(buf1), "/sec");
1169 				print_single_value(out, params, "Limit TX", buf1, 1);
1170 			} else if (args->user[i]->rx_per_sec > 0) {
1171 				bytes2human(args->user[i]->rx_per_sec, buf1, sizeof(buf1), "/sec");
1172 				print_single_value(out, params, "Limit RX", buf1, 1);
1173 			}
1174 		}
1175 
1176 		print_iface_stats(args->user[i]->tun, args->user[i]->conn_time, out, params, 1);
1177 
1178 		print_pair_value(out, params, "DPD", int2str(tmpbuf, args->user[i]->dpd), "KeepAlive", int2str(tmpbuf2, args->user[i]->keepalive), 1);
1179 
1180 		print_single_value(out, params, "Hostname", args->user[i]->hostname, 1);
1181 
1182 		print_time_ival7(tmpbuf, time(0), t);
1183 		print_single_value_ex(out, params, "Connected at", str_since, tmpbuf, 1);
1184 
1185 		if (HAVE_JSON(params)) {
1186 			print_single_value(out, params, "Full session", shorten(args->user[i]->safe_id.data, args->user[i]->safe_id.len, 0), 1);
1187 #ifdef OCSERV_0_11_6_COMPAT
1188 			/* compat with previous versions */
1189 			print_single_value(out, params, "Raw cookie", shorten(args->user[i]->safe_id.data, args->user[i]->safe_id.len, 0), 1);
1190 			print_single_value(out, params, "Cookie", shorten(args->user[i]->safe_id.data, args->user[i]->safe_id.len, 1), 1);
1191 #endif
1192 		}
1193 		print_single_value(out, params, "Session", shorten(args->user[i]->safe_id.data, args->user[i]->safe_id.len, 1), 1);
1194 
1195 		print_single_value(out, params, "TLS ciphersuite", args->user[i]->tls_ciphersuite, 1);
1196 		print_single_value(out, params, "DTLS cipher", args->user[i]->dtls_ciphersuite, 1);
1197 		print_pair_value(out, params, "CSTP compression", args->user[i]->cstp_compr, "DTLS compression", args->user[i]->dtls_compr, 1);
1198 
1199 		print_separator(out, params);
1200 		/* user network info */
1201 		if (print_list_entries(out, params, "DNS", args->user[i]->dns, args->user[i]->n_dns, 1) < 0)
1202 			goto error_parse;
1203 
1204 		if (print_list_entries(out, params, "NBNS", args->user[i]->nbns, args->user[i]->n_nbns, 1) < 0)
1205 			goto error_parse;
1206 
1207 		if (print_list_entries(out, params, "Split-DNS-Domains", args->user[i]->domains, args->user[i]->n_domains, 1) < 0)
1208 			goto error_parse;
1209 
1210 		if ((r = print_list_entries(out, params, "Routes", args->user[i]->routes, args->user[i]->n_routes, 1)) < 0)
1211 			goto error_parse;
1212 		if (r == 0) {
1213 			print_single_value(out, params, "Routes", "defaultroute", 1);
1214 		}
1215 
1216 		if (print_list_entries(out, params, "No-routes", args->user[i]->no_routes, args->user[i]->n_no_routes, 1) < 0)
1217 			goto error_parse;
1218 
1219 		if (print_list_entries(out, params, "iRoutes", args->user[i]->iroutes, args->user[i]->n_iroutes, 1) < 0)
1220 			goto error_parse;
1221 
1222 		print_single_value(out, params, "Restricted to routes", args->user[i]->restrict_to_routes?"True":"False", 1);
1223 
1224 		if (print_fwport_entries(out, params, "Restricted to ports", args->user[i]->fw_ports, args->user[i]->n_fw_ports, 0) < 0)
1225 			goto error_parse;
1226 
1227 		print_end_block(out, params, i<(args->n_user-1)?1:0);
1228 
1229 		at_least_one = 1;
1230 	}
1231 
1232 	if (HAVE_JSON(params))
1233 		fprintf(out, "]\n");
1234 
1235 	ret = 0;
1236 	goto cleanup;
1237 
1238  error_parse:
1239 	fprintf(stderr, "%s: message parsing error\n", __func__);
1240 	goto cleanup;
1241  cleanup:
1242 	if (at_least_one == 0) {
1243 		if (NO_JSON(params))
1244 			fprintf(out, "user or ID not found\n");
1245 		ret = 2;
1246 	}
1247 	if (init_pager)
1248 		pager_stop(out);
1249 
1250 	return ret;
1251 }
1252 
1253 static
session_info_cmd(void * ctx,SecmListCookiesReplyMsg * args,FILE * out,cmd_params_st * params,const char * lsid,unsigned all)1254 int session_info_cmd(void *ctx, SecmListCookiesReplyMsg * args, FILE *out,
1255 		    cmd_params_st *params, const char *lsid, unsigned all)
1256 {
1257 	const char *username, *groupname;
1258 	char str_since[65];
1259 	char str_since2[65];
1260 	struct tm *tm, _tm;
1261 	time_t t;
1262 	unsigned at_least_one = 0;
1263 	int ret = 1;
1264 	unsigned i;
1265 	const char *sid;
1266 	unsigned init_pager = 0;
1267 	unsigned int match_len = 0;
1268 	char tmpbuf[MAX_TMPSTR_SIZE];
1269 
1270 	if (lsid)
1271 		match_len = strlen(lsid);
1272 
1273 	if (out == NULL) {
1274 		out = pager_start(params);
1275 		init_pager = 1;
1276 	}
1277 
1278 	if (HAVE_JSON(params))
1279 		fprintf(out, "[\n");
1280 
1281 	session_entries_clear();
1282 
1283 	for (i=0;i<args->n_cookies;i++) {
1284 		if (!all && args->cookies[i]->status != PS_AUTH_COMPLETED && lsid == NULL)
1285 			continue;
1286 
1287 		sid = shorten(args->cookies[i]->safe_id.data, args->cookies[i]->safe_id.len, 1);
1288 		session_entries_add(ctx, sid);
1289 
1290 		if (lsid && strncmp(sid, lsid, match_len) != 0)
1291 			continue;
1292 
1293 		if (at_least_one > 0)
1294 			fprintf(out, "\n");
1295 
1296 		print_start_block(out, params);
1297 
1298 		print_single_value(out, params, "Session", sid, 1);
1299 		if (HAVE_JSON(params))
1300 			print_single_value(out, params, "Full session", shorten(args->cookies[i]->safe_id.data, args->cookies[i]->safe_id.len, 0), 1);
1301 		else
1302 			print_single_value(out, params, "Full session ID", shorten(args->cookies[i]->safe_id.data, args->cookies[i]->safe_id.len, 0), 1);
1303 
1304 		t = args->cookies[i]->created;
1305 
1306 		str_since[0] = 0;
1307 		str_since2[0] = 0;
1308 
1309 		if (t > 0) {
1310 			tm = localtime_r(&t, &_tm);
1311 			strftime(str_since, sizeof(str_since), DATE_TIME_FMT, tm);
1312 		}
1313 
1314 		t = args->cookies[i]->expires;
1315 
1316 		if (t > 0) {
1317 			tm = localtime_r(&t, &_tm);
1318 			strftime(str_since2, sizeof(str_since2), DATE_TIME_FMT, tm);
1319 		}
1320 		print_pair_value(out, params, "Created", str_since, "Expires", str_since2, 1);
1321 
1322 		print_single_value(out, params, "State", ps_status_to_str(args->cookies[i]->status, 1), 1);
1323 
1324 		username = args->cookies[i]->username;
1325 		if (username == NULL || username[0] == 0)
1326 			username = NO_USER;
1327 
1328 		groupname = args->cookies[i]->groupname;
1329 		if (groupname == NULL || groupname[0] == 0)
1330 			groupname = NO_GROUP;
1331 
1332 		print_pair_value(out, params, "Username", username, "Groupname", groupname, 1);
1333 		print_pair_value(out, params, "vhost", args->cookies[i]->vhost, "User-Agent", args->cookies[i]->user_agent, 1);
1334 		print_pair_value(out, params, "Remote IP", args->cookies[i]->remote_ip, "Location", geo_lookup(args->cookies[i]->remote_ip, tmpbuf, sizeof(tmpbuf)), 1);
1335 
1336 		if (HAVE_JSON(params)) {
1337 			/* old names for compatibility */
1338 			print_single_value_int(out, params, "session_is_open", args->cookies[i]->session_is_open, 1);
1339 			print_single_value_int(out, params, "tls_auth_ok", args->cookies[i]->tls_auth_ok, 1);
1340 			print_single_value_int(out, params, "in_use", args->cookies[i]->in_use, 1);
1341 		} else {
1342 			/* old names for compatibility */
1343 			print_pair_value(out, params, "In use", args->cookies[i]->in_use?"True":"False",
1344 					 "Activated", args->cookies[i]->session_is_open?"True":"False", 1);
1345 			print_single_value(out, params, "Certificate auth", args->cookies[i]->tls_auth_ok?"True":"False", 1);
1346 		}
1347 
1348 #ifdef OCSERV_0_11_6_COMPAT
1349 		if (HAVE_JSON(params)) {
1350 			/* compat with previous versions */
1351 			print_single_value(out, params, "Last Modified", str_since, 1);
1352 			print_single_value(out, params, "Raw cookie", shorten(args->cookies[i]->safe_id.data, args->cookies[i]->safe_id.len, 0), 1);
1353 			print_single_value(out, params, "Cookie", shorten(args->cookies[i]->safe_id.data, args->cookies[i]->safe_id.len, 1), 1);
1354 		}
1355 #endif
1356 
1357 		print_end_block(out, params, i<(args->n_cookies-1)?1:0);
1358 
1359 		at_least_one = 1;
1360 	}
1361 
1362 	if (HAVE_JSON(params))
1363 		fprintf(out, "]\n");
1364 
1365 	ret = 0;
1366 	goto cleanup;
1367 
1368  cleanup:
1369 	if (at_least_one == 0) {
1370 		if (NO_JSON(params))
1371 			fprintf(out, "Session ID not found or expired\n");
1372 		ret = 2;
1373 	}
1374 	if (init_pager)
1375 		pager_stop(out);
1376 
1377 	return ret;
1378 }
1379 
handle_show_user_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)1380 int handle_show_user_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
1381 {
1382 	int ret;
1383 	struct cmd_reply_st raw;
1384 	UserListRep *rep = NULL;
1385 	UsernameReq req = USERNAME_REQ__INIT;
1386 	PROTOBUF_ALLOCATOR(pa, ctx);
1387 
1388 	if (arg == NULL || need_help(arg)) {
1389 		check_cmd_help(rl_line_buffer);
1390 		return 1;
1391 	}
1392 
1393 	init_reply(&raw);
1394 
1395 	req.username = (void*)arg;
1396 
1397 	ret = send_cmd(ctx, CTL_CMD_USER_INFO, &req,
1398 		(pack_size_func)username_req__get_packed_size,
1399 		(pack_func)username_req__pack, &raw);
1400 	if (ret < 0) {
1401 		goto error;
1402 	}
1403 
1404 	rep = user_list_rep__unpack(&pa, raw.data_size, raw.data);
1405 	if (rep == NULL)
1406 		goto error;
1407 
1408 	ret = common_info_cmd(rep, NULL, params);
1409 	if (ret < 0)
1410 		goto error;
1411 
1412 
1413 
1414 	goto cleanup;
1415 
1416  error:
1417 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
1418 	ret = 1;
1419  cleanup:
1420 	if (rep != NULL)
1421 		user_list_rep__free_unpacked(rep, &pa);
1422 	free_reply(&raw);
1423 
1424 	return ret;
1425 }
1426 
dummy_sighandler(int signo)1427 static void dummy_sighandler(int signo)
1428 {
1429 	return;
1430 }
1431 
1432 
handle_events_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)1433 int handle_events_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
1434 {
1435 	uint8_t header[5];
1436 	int ret;
1437 	struct cmd_reply_st raw;
1438 	UserListRep *rep1 = NULL;
1439 	TopUpdateRep *rep2 = NULL;
1440 	uint32_t slength;
1441 	unsigned data_size;
1442 	uint8_t *data = NULL;
1443 	char tmpbuf[MAX_TMPSTR_SIZE];
1444 	PROTOBUF_ALLOCATOR(pa, ctx);
1445 	struct termios tio_old, tio_new;
1446 	SIGHANDLER_T old_sighandler;
1447 	fd_set rfds;
1448 
1449 	init_reply(&raw);
1450 
1451 	ret = send_cmd(ctx, CTL_CMD_TOP, NULL, 0, 0, &raw);
1452 	if (ret < 0) {
1453 		goto error;
1454 	}
1455 
1456 	rep1 = user_list_rep__unpack(&pa, raw.data_size, raw.data);
1457 	if (rep1 == NULL)
1458 		goto error;
1459 
1460 	common_user_list(ctx, rep1, stdout, params);
1461 
1462 	user_list_rep__free_unpacked(rep1, &pa);
1463 	rep1 = NULL;
1464 
1465 	fputs("\n", stdout);
1466 	fputs("Press 'q' or CTRL+C to quit\n\n", stdout);
1467 
1468 	old_sighandler = ocsignal(SIGINT, dummy_sighandler);
1469 	tcgetattr(STDIN_FILENO, &tio_old);
1470 	tio_new = tio_old;
1471 	tio_new.c_lflag &= ~(ICANON|ECHO);
1472 	tcsetattr(STDIN_FILENO, TCSANOW, &tio_new);
1473 
1474 	/* start listening for updates */
1475 	while(1) {
1476 		FD_ZERO(&rfds);
1477 #ifndef __clang_analyzer__
1478 		/* for some reason this confuses the clang static analyzer */
1479 		FD_SET(STDIN_FILENO, &rfds);
1480 #endif
1481 		FD_SET(ctx->fd, &rfds);
1482 
1483 		ret = select(MAX(STDIN_FILENO,ctx->fd)+1, &rfds, NULL, NULL, NULL);
1484 		if (ret == -1 && errno == EINTR) {
1485 			ret = 0;
1486 			break;
1487 		}
1488 
1489 		if (ret == -1) {
1490 			int e = errno;
1491 			fprintf(stderr, "events: select: %s\n", strerror(e));
1492 			ret = -1;
1493 			break;
1494 		}
1495 
1496 		if (FD_ISSET(STDIN_FILENO, &rfds)) {
1497 			ret = getchar();
1498 			if (ret == 'q' || ret == 'Q') {
1499 				ret = 0;
1500 				break;
1501 			}
1502 		}
1503 
1504 		if (!FD_ISSET(ctx->fd, &rfds))
1505 			continue;
1506 
1507 		assert(sizeof(header) == 1+sizeof(slength));
1508 		ret = force_read_timeout(ctx->fd, header, 1+sizeof(slength), DEFAULT_TIMEOUT);
1509 		if (ret == -1) {
1510 			int e = errno;
1511 			fprintf(stderr, "events: read1: %s\n", strerror(e));
1512 			ret = -1;
1513 			break;
1514 		}
1515 
1516 		if (ret == 0) {
1517 			fprintf(stderr, "events: server closed the connection\n");
1518 			ret = 0;
1519 			break;
1520 		}
1521 
1522 		if (ret != 1+sizeof(slength)) {
1523 			fprintf(stderr, "events: short read %d\n", ret);
1524 			ret = -1;
1525 			break;
1526 		}
1527 
1528 		if (header[0] != CTL_CMD_TOP_UPDATE_REP) {
1529 			fprintf(stderr, "events: Unexpected message '%d', expected '%d'\n", (int)header[0], (int)CTL_CMD_TOP_UPDATE_REP);
1530 			ret = -1;
1531 			break;
1532 		}
1533 
1534 		memcpy(&slength, &header[1], sizeof(slength));
1535 
1536 		data_size = slength;
1537 		data = talloc_size(ctx, slength);
1538 		if (data == NULL) {
1539 			fprintf(stderr, "events: memory error\n");
1540 			ret = -1;
1541 			break;
1542 		}
1543 
1544 		ret = force_read(ctx->fd, data, data_size);
1545 		if (ret == -1) {
1546 			int e = errno;
1547 			fprintf(stderr, "events: read: %s\n", strerror(e));
1548 			ret = -1;
1549 			break;
1550 		}
1551 
1552 		/* parse and print */
1553 		rep2 = top_update_rep__unpack(&pa, data_size, data);
1554 		if (rep2 == NULL)
1555 			goto error;
1556 
1557 		if (HAVE_JSON(params)) {
1558 			common_info_cmd(rep2->user, stdout, params);
1559 		} else {
1560 			if (rep2->connected) {
1561 				printf("%s: connected user '%s' (%u) from %s with IP %s\n",
1562 					rep2->user->user[0]->vhost,
1563 					rep2->user->user[0]->username,
1564 					rep2->user->user[0]->id,
1565 					rep2->user->user[0]->ip,
1566 					get_ip(rep2->user->user[0]->local_ip,
1567 					rep2->user->user[0]->local_ip6));
1568 
1569 				entries_add(ctx, rep2->user->user[0]->username, strlen(rep2->user->user[0]->username), rep2->user->user[0]->id);
1570 			} else {
1571 				print_time_ival7(tmpbuf, time(0), rep2->user->user[0]->conn_time);
1572 				printf("%s: disconnect user '%s' (%u) from %s with IP %s (reason: %s, time: %s)\n",
1573 					rep2->user->user[0]->vhost,
1574 					rep2->user->user[0]->username,
1575 					rep2->user->user[0]->id,
1576 					rep2->user->user[0]->ip,
1577 					get_ip(rep2->user->user[0]->local_ip, rep2->user->user[0]->local_ip6),
1578 					rep2->discon_reason_txt?rep2->discon_reason_txt:"unknown", tmpbuf);
1579 			}
1580 
1581 		}
1582 
1583 		top_update_rep__free_unpacked(rep2, &pa);
1584 		rep2 = NULL;
1585 	}
1586 
1587 	tcsetattr(STDIN_FILENO, TCSANOW, &tio_old);
1588 	ocsignal(SIGINT, old_sighandler);
1589 	goto cleanup;
1590 
1591  error:
1592 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
1593 	ret = 1;
1594  cleanup:
1595 	talloc_free(data);
1596 	// These are indeed dead code but if removed a minor change
1597 	// in the code above may result to either memory leak or
1598 	// something worse.
1599 	// coverity[dead_error_line : FALSE]
1600 	if (rep1 != NULL)
1601 		user_list_rep__free_unpacked(rep1, &pa);
1602 	// coverity[dead_error_line : FALSE]
1603 	if (rep2 != NULL)
1604 		top_update_rep__free_unpacked(rep2, &pa);
1605 	free_reply(&raw);
1606 
1607 	return ret;
1608 }
1609 
handle_show_id_cmd(struct unix_ctx * ctx,const char * arg,cmd_params_st * params)1610 int handle_show_id_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params)
1611 {
1612 	int ret;
1613 	struct cmd_reply_st raw;
1614 	UserListRep *rep = NULL;
1615 	unsigned id;
1616 	IdReq req = ID_REQ__INIT;
1617 	PROTOBUF_ALLOCATOR(pa, ctx);
1618 
1619 	if (arg != NULL)
1620 		id = atoi(arg);
1621 
1622 	if (arg == NULL || need_help(arg) || id == 0) {
1623 		check_cmd_help(rl_line_buffer);
1624 		return 1;
1625 	}
1626 
1627 	init_reply(&raw);
1628 
1629 	req.id = id;
1630 
1631 	ret = send_cmd(ctx, CTL_CMD_ID_INFO, &req,
1632 		(pack_size_func)id_req__get_packed_size,
1633 		(pack_func)id_req__pack, &raw);
1634 	if (ret < 0) {
1635 		goto error;
1636 	}
1637 
1638 	rep = user_list_rep__unpack(&pa, raw.data_size, raw.data);
1639 	if (rep == NULL)
1640 		goto error;
1641 
1642 	ret = common_info_cmd(rep, NULL, params);
1643 	if (ret < 0)
1644 		goto error;
1645 
1646 	goto cleanup;
1647 
1648  error:
1649 	fprintf(stderr, ERR_SERVER_UNREACHABLE);
1650 	ret = 1;
1651  cleanup:
1652 	if (rep != NULL)
1653 		user_list_rep__free_unpacked(rep, &pa);
1654 	free_reply(&raw);
1655 
1656 	return ret;
1657 }
1658 
conn_prehandle(struct unix_ctx * ctx)1659 int conn_prehandle(struct unix_ctx *ctx)
1660 {
1661 	ctx->fd = connect_to_ocserv(ctx->socket_file);
1662 	if (ctx->fd != -1)
1663 		ctx->is_open = 1;
1664 
1665 	return ctx->fd;
1666 }
1667 
conn_posthandle(struct unix_ctx * ctx)1668 void conn_posthandle(struct unix_ctx *ctx)
1669 {
1670 	if (ctx->is_open) {
1671 		close(ctx->fd);
1672 		ctx->is_open = 0;
1673 	}
1674 }
1675 
conn_init(void * pool,const char * file)1676 struct unix_ctx *conn_init(void *pool, const char *file)
1677 {
1678 struct unix_ctx *ctx;
1679 	ctx = talloc_zero(pool, struct unix_ctx);
1680 	if (ctx == NULL)
1681 		return NULL;
1682 	ctx->socket_file = file;
1683 
1684 	return ctx;
1685 }
1686 
conn_close(struct unix_ctx * conn)1687 void conn_close(struct unix_ctx* conn)
1688 {
1689 	talloc_free(conn);
1690 }
1691