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