1 /*
2  * Copyright (C) 2014-2016 Red Hat
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <config.h>
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/socket.h>
27 #include <signal.h>
28 #include <sys/un.h>
29 #include <main.h>
30 #include <vpn.h>
31 #include <cloexec.h>
32 #include <ip-lease.h>
33 
34 #include <errno.h>
35 #include <system.h>
36 #include <main-ctl.h>
37 #include <main-ban.h>
38 #include <ccan/container_of/container_of.h>
39 
40 #include <ctl.pb-c.h>
41 #include <str.h>
42 
43 typedef struct method_ctx {
44 	main_server_st *s;
45 	void *pool;
46 } method_ctx;
47 
48 static void method_top(method_ctx *ctx, int cfd, uint8_t * msg,
49 			      unsigned msg_size);
50 static void method_status(method_ctx *ctx, int cfd, uint8_t * msg,
51 			  unsigned msg_size);
52 static void method_list_users(method_ctx *ctx, int cfd, uint8_t * msg,
53 			      unsigned msg_size);
54 static void method_disconnect_user_name(method_ctx *ctx, int cfd,
55 					uint8_t * msg, unsigned msg_size);
56 static void method_disconnect_user_id(method_ctx *ctx, int cfd,
57 				      uint8_t * msg, unsigned msg_size);
58 static void method_unban_ip(method_ctx *ctx, int cfd,
59 				      uint8_t * msg, unsigned msg_size);
60 static void method_stop(method_ctx *ctx, int cfd, uint8_t * msg,
61 			unsigned msg_size);
62 static void method_reload(method_ctx *ctx, int cfd, uint8_t * msg,
63 			  unsigned msg_size);
64 static void method_user_info(method_ctx *ctx, int cfd, uint8_t * msg,
65 			     unsigned msg_size);
66 static void method_id_info(method_ctx *ctx, int cfd, uint8_t * msg,
67 			   unsigned msg_size);
68 static void method_list_banned(method_ctx *ctx, int cfd, uint8_t * msg,
69 			   unsigned msg_size);
70 static void method_list_cookies(method_ctx *ctx, int cfd, uint8_t * msg,
71 			   unsigned msg_size);
72 
73 typedef void (*method_func) (method_ctx *ctx, int cfd, uint8_t * msg,
74 			     unsigned msg_size);
75 
76 typedef struct {
77 	char *name;
78 	unsigned cmd;
79 	method_func func;
80 	unsigned indefinite; /* session remains open */
81 } ctl_method_st;
82 
83 #define ENTRY(cmd, func) \
84 	{#cmd, cmd, func, 0}
85 
86 #define ENTRY_INDEF(cmd, func) \
87 	{#cmd, cmd, func, 1}
88 
89 static const ctl_method_st methods[] = {
90 	ENTRY_INDEF(CTL_CMD_TOP, method_top),
91 	ENTRY(CTL_CMD_STATUS, method_status),
92 	ENTRY(CTL_CMD_RELOAD, method_reload),
93 	ENTRY(CTL_CMD_STOP, method_stop),
94 	ENTRY(CTL_CMD_LIST, method_list_users),
95 	ENTRY(CTL_CMD_LIST_BANNED, method_list_banned),
96 	ENTRY(CTL_CMD_LIST_COOKIES, method_list_cookies),
97 	ENTRY(CTL_CMD_USER_INFO, method_user_info),
98 	ENTRY(CTL_CMD_ID_INFO, method_id_info),
99 	ENTRY(CTL_CMD_UNBAN_IP, method_unban_ip),
100 	ENTRY(CTL_CMD_DISCONNECT_NAME, method_disconnect_user_name),
101 	ENTRY(CTL_CMD_DISCONNECT_ID, method_disconnect_user_id),
102 	{NULL, 0, NULL}
103 };
104 
ctl_handler_deinit(main_server_st * s)105 void ctl_handler_deinit(main_server_st * s)
106 {
107 	if (GETCONFIG(s)->use_occtl == 0)
108 		return;
109 
110 	if (s->ctl_fd >= 0) {
111 		/*mslog(s, NULL, LOG_DEBUG, "closing unix socket connection");*/
112 		close(s->ctl_fd);
113 		/*remove(OCSERV_UNIX_NAME); */
114 	}
115 }
116 
117 /* Initializes unix socket and stores the fd.
118  */
ctl_handler_init(main_server_st * s)119 int ctl_handler_init(main_server_st * s)
120 {
121 	int ret;
122 	struct sockaddr_un sa;
123 	int sd, e;
124 
125 	if (GETCONFIG(s)->use_occtl == 0 || GETPCONFIG(s)->occtl_socket_file == NULL) {
126 		mslog(s, NULL, LOG_INFO, "not using control unix socket");
127 		return 0;
128 	}
129 
130 	mslog(s, NULL, LOG_DEBUG, "initializing control unix socket: %s", GETPCONFIG(s)->occtl_socket_file);
131 	memset(&sa, 0, sizeof(sa));
132 	sa.sun_family = AF_UNIX;
133 	strlcpy(sa.sun_path, GETPCONFIG(s)->occtl_socket_file, sizeof(sa.sun_path));
134 	remove(GETPCONFIG(s)->occtl_socket_file);
135 
136 	sd = socket(AF_UNIX, SOCK_STREAM, 0);
137 	if (sd == -1) {
138 		e = errno;
139 		mslog(s, NULL, LOG_ERR, "could not create socket '%s': %s",
140 		      GETPCONFIG(s)->occtl_socket_file, strerror(e));
141 		return -1;
142 	}
143 
144 	umask(066);
145 	ret = bind(sd, (struct sockaddr *)&sa, SUN_LEN(&sa));
146 	if (ret == -1) {
147 		e = errno;
148 		mslog(s, NULL, LOG_ERR, "could not bind socket '%s': %s",
149 		      GETPCONFIG(s)->occtl_socket_file, strerror(e));
150 		close(sd);
151 		return -1;
152 	}
153 
154 	ret = chown(GETPCONFIG(s)->occtl_socket_file, GETPCONFIG(s)->uid, GETPCONFIG(s)->gid);
155 	if (ret == -1) {
156 		e = errno;
157 		mslog(s, NULL, LOG_ERR, "could not chown socket '%s': %s",
158 		      GETPCONFIG(s)->occtl_socket_file, strerror(e));
159 	}
160 
161 	ret = listen(sd, 1024);
162 	if (ret == -1) {
163 		e = errno;
164 		mslog(s, NULL, LOG_ERR, "could not listen to socket '%s': %s",
165 		      GETPCONFIG(s)->occtl_socket_file, strerror(e));
166 		close(sd);
167 		return -1;
168 	}
169 
170 	s->ctl_fd = sd;
171 	return sd;
172 }
173 
method_status(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)174 static void method_status(method_ctx *ctx, int cfd, uint8_t * msg,
175 			  unsigned msg_size)
176 {
177 	StatusRep rep = STATUS_REP__INIT;
178 	int ret;
179 	unsigned int i;
180 	uint32_t * sec_mod_pids;
181 
182 	sec_mod_pids = talloc_array(ctx->pool, uint32_t, ctx->s->sec_mod_instance_count);
183 	if (sec_mod_pids) {
184 		for (i = 0; i < ctx->s->sec_mod_instance_count; i ++) {
185 			sec_mod_pids[i] = ctx->s->sec_mod_instances[i].sec_mod_pid;
186 		}
187 	}
188 
189 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: status");
190 
191 	rep.status = 1;
192 	rep.pid = getpid();
193 	rep.start_time = ctx->s->stats.start_time;
194 	if (sec_mod_pids) {
195 		rep.sec_mod_pids = sec_mod_pids;
196 		rep.n_sec_mod_pids = ctx->s->sec_mod_instance_count;
197 	}
198 	rep.active_clients = ctx->s->stats.active_clients;
199 	rep.secmod_client_entries = 0;
200 	rep.stored_tls_sessions = 0;
201 	rep.max_auth_time = 0;
202 	rep.avg_auth_time = 0;
203 	for (i = 0; i < ctx->s->sec_mod_instance_count; i ++) {
204 		rep.secmod_client_entries += ctx->s->sec_mod_instances[i].secmod_client_entries;
205 		rep.stored_tls_sessions += ctx->s->sec_mod_instances[i].tlsdb_entries;
206 		rep.max_auth_time = MAX(rep.max_auth_time, ctx->s->sec_mod_instances[i].max_auth_time);
207 		rep.avg_auth_time = ctx->s->sec_mod_instances[i].avg_auth_time;
208 	}
209 	if (ctx->s->sec_mod_instance_count != 0) {
210 		rep.avg_auth_time /= ctx->s->sec_mod_instance_count;
211 	}
212 	rep.banned_ips = main_ban_db_elems(ctx->s);
213 
214 	rep.session_timeouts = ctx->s->stats.session_timeouts;
215 	rep.session_idle_timeouts = ctx->s->stats.session_idle_timeouts;
216 	rep.session_errors = ctx->s->stats.session_errors;
217 	rep.sessions_closed = ctx->s->stats.sessions_closed;
218 	rep.kbytes_in = ctx->s->stats.kbytes_in;
219 	rep.kbytes_out = ctx->s->stats.kbytes_out;
220 	rep.min_mtu = ctx->s->stats.min_mtu;
221 	rep.max_mtu = ctx->s->stats.max_mtu;
222 	rep.last_reset = ctx->s->stats.last_reset;
223 	rep.avg_session_mins = ctx->s->stats.avg_session_mins;
224 	rep.max_session_mins = ctx->s->stats.max_session_mins;
225 
226 	rep.auth_failures = ctx->s->stats.auth_failures;
227 	rep.total_auth_failures = ctx->s->stats.total_auth_failures;
228 	rep.total_sessions_closed = ctx->s->stats.total_sessions_closed;
229 #if defined(CAPTURE_LATENCY_SUPPORT)
230 	rep.latency_median_total = ctx->s->stats.current_latency_stats.median_total;
231 	rep.has_latency_median_total = true;
232 	rep.latency_rms_total = ctx->s->stats.current_latency_stats.rms_total;
233 	rep.has_latency_rms_total = true;
234 	rep.latency_sample_count = ctx->s->stats.current_latency_stats.sample_count;
235 	rep.has_latency_sample_count = true;
236 #endif
237 
238 	ret = send_msg(ctx->pool, cfd, CTL_CMD_STATUS_REP, &rep,
239 		       (pack_size_func) status_rep__get_packed_size,
240 		       (pack_func) status_rep__pack);
241 	if (ret < 0) {
242 		mslog(ctx->s, NULL, LOG_ERR, "error sending ctl reply");
243 	}
244 
245 	return;
246 }
247 
method_reload(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)248 static void method_reload(method_ctx *ctx, int cfd, uint8_t * msg,
249 			  unsigned msg_size)
250 {
251 	BoolMsg rep = BOOL_MSG__INIT;
252 	int ret;
253 
254 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: reload");
255 
256 	ev_feed_signal_event (main_loop, SIGHUP);
257 
258 	rep.status = 1;
259 
260 	ret = send_msg(ctx->pool, cfd, CTL_CMD_RELOAD_REP, &rep,
261 		       (pack_size_func) bool_msg__get_packed_size,
262 		       (pack_func) bool_msg__pack);
263 	if (ret < 0) {
264 		mslog(ctx->s, NULL, LOG_ERR, "error sending ctl reply");
265 	}
266 
267 	return;
268 }
269 
method_stop(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)270 static void method_stop(method_ctx *ctx, int cfd, uint8_t * msg,
271 			unsigned msg_size)
272 {
273 	BoolMsg rep = BOOL_MSG__INIT;
274 	int ret;
275 
276 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: stop");
277 
278 	ev_feed_signal_event (main_loop, SIGTERM);
279 
280 	rep.status = 1;
281 
282 	ret = send_msg(ctx->pool, cfd, CTL_CMD_STOP_REP, &rep,
283 		       (pack_size_func) bool_msg__get_packed_size,
284 		       (pack_func) bool_msg__pack);
285 	if (ret < 0) {
286 		mslog(ctx->s, NULL, LOG_ERR, "error sending ctl reply");
287 	}
288 
289 	return;
290 }
291 
292 #define IPBUF_SIZE 64
append_user_info(method_ctx * ctx,UserListRep * list,struct proc_st * ctmp)293 static int append_user_info(method_ctx *ctx,
294 			    UserListRep * list,
295 			    struct proc_st *ctmp)
296 {
297 	uint32_t tmp;
298 	char *ipbuf;
299 	char *strtmp;
300 	UserInfoRep *rep;
301 	char *safe_id;
302 
303 	list->user =
304 	    talloc_realloc(ctx->pool, list->user, UserInfoRep *, (1 + list->n_user));
305 	if (list->user == NULL)
306 		return -1;
307 
308 	rep = talloc(ctx->pool, UserInfoRep);
309 	if (rep == NULL)
310 		return -1;
311 
312 	safe_id = talloc_size(ctx->pool, SAFE_ID_SIZE);
313 	if (safe_id == NULL)
314 		return -1;
315 
316 	list->user[list->n_user] = rep;
317 	list->n_user++;
318 
319 	user_info_rep__init(rep);
320 
321 	/* ID: pid */
322 	rep->id = ctmp->pid;
323 	rep->username = ctmp->username;
324 	rep->groupname = ctmp->groupname;
325 	rep->vhost = VHOSTNAME(ctmp->vhost);
326 
327 	ipbuf = talloc_size(ctx->pool, IPBUF_SIZE);
328 	if (ipbuf == NULL)
329 		return -1;
330 
331 	strtmp =
332 	    human_addr2((struct sockaddr *)&ctmp->remote_addr,
333 			ctmp->remote_addr_len, ipbuf, IPBUF_SIZE, 0);
334 	if (strtmp == NULL)
335 		strtmp = "";
336 	rep->ip = strtmp;
337 
338 	ipbuf = talloc_size(ctx->pool, IPBUF_SIZE);
339 	if (ipbuf == NULL)
340 		return -1;
341 
342 	strtmp =
343 	    human_addr2((struct sockaddr *)&ctmp->our_addr,
344 			ctmp->our_addr_len, ipbuf, IPBUF_SIZE, 0);
345 	if (strtmp == NULL)
346 		strtmp = "";
347 	rep->local_dev_ip = strtmp;
348 
349 	rep->tun = ctmp->tun_lease.name;
350 
351 	ipbuf = talloc_size(ctx->pool, IPBUF_SIZE);
352 	if (ipbuf == NULL)
353 		return -1;
354 
355 	strtmp = NULL;
356 	if (ctmp->ipv4 != NULL)
357 		strtmp =
358 		    human_addr2((struct sockaddr *)&ctmp->ipv4->rip,
359 				ctmp->ipv4->rip_len, ipbuf, IPBUF_SIZE, 0);
360 	if (strtmp == NULL)
361 		strtmp = "";
362 	rep->local_ip = strtmp;
363 
364 	ipbuf = talloc_size(ctx->pool, IPBUF_SIZE);
365 	if (ipbuf == NULL)
366 		return -1;
367 
368 	strtmp = NULL;
369 	if (ctmp->ipv4 != NULL)
370 		strtmp =
371 		    human_addr2((struct sockaddr *)&ctmp->ipv4->lip,
372 				ctmp->ipv4->lip_len, ipbuf, IPBUF_SIZE, 0);
373 	if (strtmp == NULL)
374 		strtmp = "";
375 	rep->remote_ip = strtmp;
376 
377 	/* IPv6 */
378 
379 	ipbuf = talloc_size(ctx->pool, IPBUF_SIZE);
380 	if (ipbuf == NULL)
381 		return -1;
382 
383 	strtmp = NULL;
384 	if (ctmp->ipv6 != NULL)
385 		strtmp =
386 		    human_addr2((struct sockaddr *)&ctmp->ipv6->rip,
387 				ctmp->ipv6->rip_len, ipbuf, IPBUF_SIZE, 0);
388 	if (strtmp == NULL)
389 		strtmp = "";
390 	rep->local_ip6 = strtmp;
391 
392 	ipbuf = talloc_size(ctx->pool, IPBUF_SIZE);
393 	if (ipbuf == NULL)
394 		return -1;
395 
396 	strtmp = NULL;
397 	if (ctmp->ipv6 != NULL)
398 		strtmp =
399 		    human_addr2((struct sockaddr *)&ctmp->ipv6->lip,
400 				ctmp->ipv6->lip_len, ipbuf, IPBUF_SIZE, 0);
401 	if (strtmp == NULL)
402 		strtmp = "";
403 	rep->remote_ip6 = strtmp;
404 
405 	rep->conn_time = ctmp->conn_time;
406 	rep->hostname = ctmp->hostname;
407 	rep->user_agent = ctmp->user_agent;
408 
409 	rep->status = ctmp->status;
410 
411 	rep->tls_ciphersuite = ctmp->tls_ciphersuite;
412 	rep->dtls_ciphersuite = ctmp->dtls_ciphersuite;
413 
414 	calc_safe_id(ctmp->sid, sizeof(ctmp->sid), safe_id, SAFE_ID_SIZE);
415 	rep->safe_id.data = (unsigned char*)safe_id;
416 	rep->safe_id.len = SAFE_ID_SIZE;
417 
418 	rep->cstp_compr = ctmp->cstp_compr;
419 	rep->dtls_compr = ctmp->dtls_compr;
420 	if (ctmp->mtu > 0) {
421 		rep->mtu = ctmp->mtu;
422 		rep->has_mtu = 1;
423 	}
424 
425 	if (ctmp->config) {
426 		rep->restrict_to_routes = ctmp->config->restrict_user_to_routes;
427 
428 		tmp = ctmp->config->rx_per_sec;
429 		tmp *= 1000;
430 		rep->has_rx_per_sec = ctmp->config->has_rx_per_sec;
431 		rep->rx_per_sec = tmp;
432 
433 		tmp = ctmp->config->tx_per_sec;
434 		tmp *= 1000;
435 		rep->has_tx_per_sec = ctmp->config->has_tx_per_sec;
436 		rep->tx_per_sec = tmp;
437 
438 		rep->dpd = ctmp->config->dpd;
439 
440 		rep->keepalive = ctmp->config->keepalive;
441 		if (ctmp->vhost) {
442 			rep->domains = ctmp->vhost->perm_config.config->split_dns;
443 			rep->n_domains = ctmp->vhost->perm_config.config->split_dns_size;
444 		}
445 
446 		rep->dns = ctmp->config->dns;
447 		rep->n_dns = ctmp->config->n_dns;
448 
449 		rep->nbns = ctmp->config->nbns;
450 		rep->n_nbns = ctmp->config->n_nbns;
451 
452 		rep->n_routes = ctmp->config->n_routes;
453 		rep->routes = ctmp->config->routes;
454 
455 		rep->n_no_routes = ctmp->config->n_no_routes;
456 		rep->no_routes = ctmp->config->no_routes;
457 
458 		rep->iroutes = ctmp->config->iroutes;
459 		rep->n_iroutes = ctmp->config->n_iroutes;
460 
461 		rep->n_fw_ports = ctmp->config->n_fw_ports;
462 		rep->fw_ports = ctmp->config->fw_ports;
463 	}
464 
465 	return 0;
466 }
467 
method_list_users(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)468 static void method_list_users(method_ctx *ctx, int cfd, uint8_t * msg,
469 			      unsigned msg_size)
470 {
471 	UserListRep rep = USER_LIST_REP__INIT;
472 	struct proc_st *ctmp = NULL;
473 	int ret;
474 
475 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: list-users");
476 
477 	list_for_each(&ctx->s->proc_list.head, ctmp, list) {
478 		ret = append_user_info(ctx, &rep, ctmp);
479 		if (ret < 0) {
480 			mslog(ctx->s, NULL, LOG_ERR,
481 			      "error appending user info to reply");
482 			goto error;
483 		}
484 	}
485 
486 	ret = send_msg(ctx->pool, cfd, CTL_CMD_LIST_REP, &rep,
487 		       (pack_size_func) user_list_rep__get_packed_size,
488 		       (pack_func) user_list_rep__pack);
489 	if (ret < 0) {
490 		mslog(ctx->s, NULL, LOG_ERR, "error sending ctl reply");
491 	}
492 
493  error:
494 	return;
495 }
496 
method_top(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)497 static void method_top(method_ctx *ctx, int cfd, uint8_t * msg,
498 			      unsigned msg_size)
499 {
500 	/* we send the initial user list, and the we send a TOP reply message
501 	 * once a user connects/disconnects. */
502 
503 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: top");
504 
505 	/* we can only have a single top listener */
506 	if (ctx->s->top_fd == -1)
507 		ctx->s->top_fd = cfd;
508 
509 	method_list_users(ctx, cfd, msg, msg_size);
510 }
511 
append_ban_info(method_ctx * ctx,BanListRep * list,struct ban_entry_st * e)512 static int append_ban_info(method_ctx *ctx,
513 			   BanListRep *list,
514 			   struct ban_entry_st *e)
515 {
516 	BanInfoRep *rep;
517 	main_server_st *s = ctx->s;
518 
519 	list->info =
520 	    talloc_realloc(ctx->pool, list->info, BanInfoRep *, (1 + list->n_info));
521 	if (list->info == NULL)
522 		return -1;
523 
524 	rep = list->info[list->n_info] = talloc(ctx->pool, BanInfoRep);
525 	if (rep == NULL)
526 		return -1;
527 	list->n_info++;
528 
529 	ban_info_rep__init(rep);
530 
531 	rep->ip.data = e->ip.ip;
532 	rep->ip.len = e->ip.size;
533 	rep->score = e->score;
534 
535 	if (GETCONFIG(s)->max_ban_score > 0 && e->score >= GETCONFIG(s)->max_ban_score) {
536 		rep->expires = e->expires;
537 		rep->has_expires = 1;
538 	}
539 
540 	return 0;
541 }
542 
method_list_banned(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)543 static void method_list_banned(method_ctx *ctx, int cfd, uint8_t * msg,
544 			      unsigned msg_size)
545 {
546 	BanListRep rep = BAN_LIST_REP__INIT;
547 	struct ban_entry_st *e = NULL;
548 	struct htable *db = ctx->s->ban_db;
549 	int ret;
550 	struct htable_iter iter;
551 
552 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: list-banned-ips");
553 
554 	e = htable_first(db, &iter);
555 	while (e != NULL) {
556 		ret = append_ban_info(ctx, &rep, e);
557 		if (ret < 0) {
558 			mslog(ctx->s, NULL, LOG_ERR,
559 			      "error appending ban info to reply");
560 			goto error;
561 		}
562 		e = htable_next(db, &iter);
563 	}
564 
565 	ret = send_msg(ctx->pool, cfd, CTL_CMD_LIST_BANNED_REP, &rep,
566 		       (pack_size_func) ban_list_rep__get_packed_size,
567 		       (pack_func) ban_list_rep__pack);
568 	if (ret < 0) {
569 		mslog(ctx->s, NULL, LOG_ERR, "error sending ban list reply");
570 	}
571 
572  error:
573 	return;
574 }
575 
method_list_cookies(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)576 static void method_list_cookies(method_ctx *ctx, int cfd, uint8_t * msg,
577 			      unsigned msg_size)
578 {
579 	SecmListCookiesReplyMsg reply = SECM_LIST_COOKIES_REPLY_MSG__INIT;
580 	SecmListCookiesReplyMsg ** sub_replies = NULL;
581 	CookieIntMsg ** cookies = NULL;
582 	PROTOBUF_ALLOCATOR(pa, ctx->pool);
583 
584 	size_t total_cookies = 0;
585 	unsigned int i;
586 	unsigned int j;
587 	unsigned int k;
588 	int ret;
589 
590 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: list-cookies");
591 
592 	sub_replies = talloc_zero_array(ctx->pool, SecmListCookiesReplyMsg*, ctx->s->sec_mod_instance_count);
593 	if (!sub_replies) {
594 		goto reply_and_exit;
595 	}
596 
597 	for (i = 0; i < ctx->s->sec_mod_instance_count; i++) {
598 		SecmListCookiesReplyMsg * sub_reply = NULL;
599 		ret = send_msg(ctx->pool, ctx->s->sec_mod_instances[i].sec_mod_fd_sync, CMD_SECM_LIST_COOKIES,
600 				NULL, NULL, NULL);
601 		if (ret < 0) {
602 			mslog(ctx->s, NULL, LOG_ERR, "error sending list cookies to sec-mod!");
603 			continue;
604 		}
605 		ret = recv_msg(ctx->pool, ctx->s->sec_mod_instances[i].sec_mod_fd_sync, CMD_SECM_LIST_COOKIES_REPLY,
606 				(void*)&sub_reply, (unpack_func)secm_list_cookies_reply_msg__unpack, MAIN_SEC_MOD_TIMEOUT);
607 		if (ret < 0) {
608 			mslog(ctx->s, NULL, LOG_ERR, "error receiving list cookies reply");
609 			continue;
610 		}
611 
612 		if (sub_reply) {
613 			sub_replies[i] = sub_reply;
614 			total_cookies += sub_reply->n_cookies;
615 		}
616 	}
617 
618 	cookies = talloc_zero_array(ctx->pool, CookieIntMsg*, total_cookies);
619 	if (!cookies) {
620 		goto reply_and_exit;
621 	}
622 
623 	k = 0;
624 	for (i = 0; i < ctx->s->sec_mod_instance_count; i++) {
625 		if (sub_replies[i] == NULL) {
626 			continue;
627 		}
628 
629 		for (j = 0; j < sub_replies[i]->n_cookies; j++) {
630 			cookies[k++] = sub_replies[i]->cookies[j];
631 		}
632 	}
633 
634 reply_and_exit:
635 	reply.cookies = cookies;
636 	reply.n_cookies = total_cookies;
637 
638 	ret = send_msg(ctx->pool, cfd, CTL_CMD_LIST_COOKIES_REP, &reply,
639 		       (pack_size_func) secm_list_cookies_reply_msg__get_packed_size,
640 		       (pack_func) secm_list_cookies_reply_msg__pack);
641 	if (ret < 0) {
642 		mslog(ctx->s, NULL, LOG_ERR, "error sending list cookies reply");
643 	}
644 
645 	if (sub_replies) {
646 		for (i = 0; i < ctx->s->sec_mod_instance_count; i++) {
647 			if (sub_replies[i] == NULL) {
648 				continue;
649 			}
650 			secm_list_cookies_reply_msg__free_unpacked(sub_replies[i], &pa);
651 		}
652 		talloc_free(sub_replies);
653 	}
654 
655 	if (cookies) {
656 		talloc_free(cookies);
657 	}
658 	return;
659 }
660 
single_info_common(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size,const char * user,unsigned id)661 static void single_info_common(method_ctx *ctx, int cfd, uint8_t * msg,
662 			       unsigned msg_size, const char *user, unsigned id)
663 {
664 	UserListRep rep = USER_LIST_REP__INIT;
665 	int ret;
666 	unsigned found_user = 0;
667 	struct proc_st *ctmp = NULL;
668 
669 	if (user != NULL)
670 		mslog(ctx->s, NULL, LOG_INFO, "providing info for user '%s'", user);
671 	else
672 		mslog(ctx->s, NULL, LOG_INFO, "providing info for ID '%u'", id);
673 
674 	list_for_each(&ctx->s->proc_list.head, ctmp, list) {
675 		if (user == NULL) {	/* id */
676 			if (id == 0 || id == -1 || id != ctmp->pid) {
677 				continue;
678 			}
679 		} else {	/* username */
680 			if (strcmp(ctmp->username, user) != 0) {
681 				continue;
682 			}
683 		}
684 
685 		ret = append_user_info(ctx, &rep, ctmp);
686 		if (ret < 0) {
687 			mslog(ctx->s, NULL, LOG_ERR,
688 			      "error appending user info to reply");
689 			goto error;
690 		}
691 
692 		found_user = 1;
693 
694 		if (id != 0)	/* id -> one a single element */
695 			break;
696 	}
697 
698 	if (found_user == 0) {
699 		if (user != NULL)
700 			mslog(ctx->s, NULL, LOG_INFO, "could not find user '%s'",
701 			      user);
702 		else
703 			mslog(ctx->s, NULL, LOG_INFO, "could not find ID '%u'", id);
704 	}
705 
706 	ret = send_msg(ctx->pool, cfd, CTL_CMD_LIST_REP, &rep,
707 		       (pack_size_func) user_list_rep__get_packed_size,
708 		       (pack_func) user_list_rep__pack);
709 	if (ret < 0) {
710 		mslog(ctx->s, NULL, LOG_ERR, "error sending ctl reply");
711 	}
712 
713  error:
714 	return;
715 }
716 
method_user_info(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)717 static void method_user_info(method_ctx *ctx, int cfd, uint8_t * msg,
718 			     unsigned msg_size)
719 {
720 	UsernameReq *req;
721 
722 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: user_info (name)");
723 
724 	req = username_req__unpack(NULL, msg_size, msg);
725 	if (req == NULL) {
726 		mslog(ctx->s, NULL, LOG_ERR, "error parsing user_info request");
727 		return;
728 	}
729 
730 	single_info_common(ctx, cfd, msg, msg_size, req->username, 0);
731 	username_req__free_unpacked(req, NULL);
732 
733 	return;
734 }
735 
method_id_info(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)736 static void method_id_info(method_ctx *ctx, int cfd, uint8_t * msg,
737 			   unsigned msg_size)
738 {
739 	IdReq *req;
740 
741 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: user_info (id)");
742 
743 	req = id_req__unpack(NULL, msg_size, msg);
744 	if (req == NULL) {
745 		mslog(ctx->s, NULL, LOG_ERR, "error parsing id_info request");
746 		return;
747 	}
748 
749 	single_info_common(ctx, cfd, msg, msg_size, NULL, req->id);
750 	id_req__free_unpacked(req, NULL);
751 
752 	return;
753 }
754 
method_unban_ip(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)755 static void method_unban_ip(method_ctx *ctx,
756 			    int cfd, uint8_t * msg,
757 			    unsigned msg_size)
758 {
759 	UnbanReq *req;
760 	BoolMsg rep = BOOL_MSG__INIT;
761 	int ret;
762 
763 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: unban IP");
764 
765 	req = unban_req__unpack(NULL, msg_size, msg);
766 	if (req == NULL) {
767 		mslog(ctx->s, NULL, LOG_ERR,
768 		      "error parsing unban IP request");
769 		return;
770 	}
771 
772 	if (remove_ip_from_ban_list(ctx->s, req->ip.data, req->ip.len) != 0) {
773 		rep.status = 1;
774 	}
775 
776 	unban_req__free_unpacked(req, NULL);
777 
778 	ret = send_msg(ctx->pool, cfd, CTL_CMD_UNBAN_IP_REP, &rep,
779 		       (pack_size_func) bool_msg__get_packed_size,
780 		       (pack_func) bool_msg__pack);
781 	if (ret < 0) {
782 		mslog(ctx->s, NULL, LOG_ERR, "error sending unban IP ctl reply");
783 	}
784 
785 	return;
786 }
787 
method_disconnect_user_name(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)788 static void method_disconnect_user_name(method_ctx *ctx,
789 					int cfd, uint8_t * msg,
790 					unsigned msg_size)
791 {
792 	UsernameReq *req;
793 	BoolMsg rep = BOOL_MSG__INIT;
794 	struct proc_st *cpos;
795 	struct proc_st *ctmp = NULL;
796 	int ret;
797 
798 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: disconnect_name");
799 
800 	req = username_req__unpack(NULL, msg_size, msg);
801 	if (req == NULL) {
802 		mslog(ctx->s, NULL, LOG_ERR,
803 		      "error parsing disconnect_name request");
804 		return;
805 	}
806 
807 	/* got the name. Try to disconnect */
808 	list_for_each_safe(&ctx->s->proc_list.head, ctmp, cpos, list) {
809 		if (strcmp(ctmp->username, req->username) == 0) {
810 			disconnect_proc(ctx->s, ctmp);
811 			rep.status = 1;
812 		}
813 	}
814 
815 	username_req__free_unpacked(req, NULL);
816 
817 	ret = send_msg(ctx->pool, cfd, CTL_CMD_DISCONNECT_NAME_REP, &rep,
818 		       (pack_size_func) bool_msg__get_packed_size,
819 		       (pack_func) bool_msg__pack);
820 	if (ret < 0) {
821 		mslog(ctx->s, NULL, LOG_ERR, "error sending ctl reply");
822 	}
823 
824 	return;
825 }
826 
method_disconnect_user_id(method_ctx * ctx,int cfd,uint8_t * msg,unsigned msg_size)827 static void method_disconnect_user_id(method_ctx *ctx, int cfd,
828 				      uint8_t * msg, unsigned msg_size)
829 {
830 	IdReq *req;
831 	BoolMsg rep = BOOL_MSG__INIT;
832 	struct proc_st *cpos;
833 	struct proc_st *ctmp = NULL;
834 	int ret;
835 
836 	mslog(ctx->s, NULL, LOG_DEBUG, "ctl: disconnect_id");
837 
838 	req = id_req__unpack(NULL, msg_size, msg);
839 	if (req == NULL) {
840 		mslog(ctx->s, NULL, LOG_ERR, "error parsing disconnect_id request");
841 		return;
842 	}
843 
844 	/* got the ID. Try to disconnect */
845 	list_for_each_safe(&ctx->s->proc_list.head, ctmp, cpos, list) {
846 		if (ctmp->pid == req->id) {
847 			disconnect_proc(ctx->s, ctmp);
848 			rep.status = 1;
849 
850 			if (req->id != -1)
851 				break;
852 		}
853 	}
854 
855 	/* reply */
856 	id_req__free_unpacked(req, NULL);
857 
858 	ret = send_msg(ctx->pool, cfd, CTL_CMD_DISCONNECT_ID_REP, &rep,
859 		       (pack_size_func) bool_msg__get_packed_size,
860 		       (pack_func) bool_msg__pack);
861 	if (ret < 0) {
862 		mslog(ctx->s, NULL, LOG_ERR, "error sending ctl reply");
863 	}
864 
865 	return;
866 }
867 
868 struct ctl_watcher_st {
869 	int fd;
870 	struct ev_io ctl_cmd_io;
871 };
872 
ctl_cmd_wacher_cb(EV_P_ ev_io * w,int revents)873 static void ctl_cmd_wacher_cb(EV_P_ ev_io *w, int revents)
874 {
875 	main_server_st *s = ev_userdata(main_loop);
876 	int ret;
877 	size_t length;
878 	uint8_t cmd;
879 	uint8_t buffer[256];
880 	method_ctx ctx;
881 	struct ctl_watcher_st *wst = container_of(w, struct ctl_watcher_st, ctl_cmd_io);
882 	unsigned i, indef = 0;
883 
884 	ctx.s = s;
885 	ctx.pool = talloc_new(wst);
886 
887 	if (ctx.pool == NULL)
888 		goto fail;
889 
890 	/* read request */
891 	ret = recv_msg_data(wst->fd, &cmd, buffer, sizeof(buffer), NULL);
892 	if (ret < 0) {
893 		mslog(s, NULL, LOG_ERR, "error receiving ctl data");
894 		goto fail;
895 	}
896 
897 	length = ret;
898 
899 	for (i = 0;; i++) {
900 		if (methods[i].cmd == 0) {
901 			mslog(s, NULL, LOG_INFO,
902 			      "unknown unix ctl message: 0x%.1x",
903 			      (unsigned)cmd);
904 			break;
905 		} else if (methods[i].cmd == cmd) {
906 			indef = methods[i].indefinite;
907 			methods[i].func(&ctx, wst->fd, buffer, length);
908 			break;
909 		}
910 	}
911 
912 	if (indef) {
913 		talloc_free(ctx.pool);
914 		return;
915 	}
916  fail:
917  	if (s->top_fd == wst->fd)
918  		s->top_fd = -1;
919  	close(wst->fd);
920  	ev_io_stop(EV_A_ w);
921  	talloc_free(wst);
922  	return;
923 }
924 
ctl_handle_commands(main_server_st * s)925 static void ctl_handle_commands(main_server_st * s)
926 {
927 	int cfd = -1, e, ret;
928 	struct sockaddr_un sa;
929 	socklen_t sa_len;
930 	struct ctl_watcher_st *wst;
931 
932 	sa_len = sizeof(sa);
933 	cfd = accept(s->ctl_fd, (struct sockaddr *)&sa, &sa_len);
934 	if (cfd == -1) {
935 		e = errno;
936 		mslog(s, NULL, LOG_ERR,
937 		      "error accepting control connection: %s", strerror(e));
938 		goto fail;
939 	}
940 
941 	ret = check_upeer_id("ctl", GETPCONFIG(s)->debug, cfd, 0, 0, NULL, NULL);
942 	if (ret < 0) {
943 		mslog(s, NULL, LOG_ERR, "ctl: unauthorized connection");
944 		goto fail;
945 	}
946 
947 	set_cloexec_flag(cfd, 1);
948 
949 	wst = talloc(s, struct ctl_watcher_st);
950 	if (wst == NULL)
951 		goto fail;
952 
953 	wst->fd = cfd;
954 
955 	ev_io_init(&wst->ctl_cmd_io, ctl_cmd_wacher_cb, wst->fd, EV_READ);
956 	ev_io_start(main_loop, &wst->ctl_cmd_io);
957 
958 	return;
959  fail:
960 	if (cfd != -1)
961 		close(cfd);
962 }
963 
ctl_handler_set_fds(main_server_st * s,ev_io * watcher)964 void ctl_handler_set_fds(main_server_st * s, ev_io *watcher)
965 {
966 	if (GETCONFIG(s)->use_occtl == 0)
967 		return;
968 
969 	ev_io_set(watcher, s->ctl_fd, EV_READ);
970 }
971 
ctl_handler_run_pending(main_server_st * s,ev_io * watcher)972 void ctl_handler_run_pending(main_server_st* s, ev_io *watcher)
973 {
974 	if (GETCONFIG(s)->use_occtl == 0)
975 		return;
976 
977 	ctl_handle_commands(s);
978 }
979 
ctl_handler_notify(main_server_st * s,struct proc_st * proc,unsigned connect)980 void ctl_handler_notify (main_server_st* s, struct proc_st *proc, unsigned connect)
981 {
982 	TopUpdateRep rep = TOP_UPDATE_REP__INIT;
983 	UserListRep list = USER_LIST_REP__INIT;
984 	int ret;
985 	method_ctx ctx;
986 	void *pool = talloc_new(proc);
987 
988 	if (s->top_fd == -1)
989 		return;
990 
991 	if (pool == NULL) {
992 		goto fail;
993 	}
994 
995 	ctx.s = s;
996 	ctx.pool = pool;
997 
998 	mslog(s, NULL, LOG_DEBUG, "ctl: top update");
999 
1000 	rep.connected = connect;
1001 	if (connect == 0 && proc->discon_reason) {
1002 		rep.has_discon_reason = 1;
1003 		rep.discon_reason = proc->discon_reason;
1004 		rep.discon_reason_txt = (char*)discon_reason_to_str(proc->discon_reason);
1005 	}
1006 
1007 	ret = append_user_info(&ctx, &list, proc);
1008 	if (ret < 0) {
1009 		mslog(s, NULL, LOG_ERR,
1010 		      "error appending user info to reply");
1011 		goto fail;
1012 	}
1013 	rep.user = &list;
1014 
1015 	ret = send_msg(pool, s->top_fd, CTL_CMD_TOP_UPDATE_REP, &rep,
1016 		       (pack_size_func) top_update_rep__get_packed_size,
1017 		       (pack_func) top_update_rep__pack);
1018 	if (ret < 0) {
1019 		mslog(s, NULL, LOG_ERR, "error sending ctl reply");
1020 		goto fail;
1021 	}
1022 
1023 	talloc_free(pool);
1024 	return;
1025  fail:
1026 	talloc_free(pool);
1027  	s->top_fd = -1;
1028 }
1029