From fe28fd15cdaa735524b9cac4e3a4a6c70a05638a Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 13 Nov 2015 16:00:12 +0100 Subject: [PATCH] Added occtl command 'show events', as well as the corresponding command in main This allows the main process to handle a single listener which will get all information about new and disconnecting users. --- src/common/common.c | 26 ++++ src/common/common.h | 1 + src/common/ctl.proto | 8 ++ src/main-ctl-unix.c | 93 +++++++++++++- src/main-ctl.h | 1 + src/main-misc.c | 3 +- src/main-sec-mod-cmd.c | 2 + src/main-user.c | 3 + src/main.c | 2 + src/main.h | 2 + src/occtl/ctl.h | 2 + src/occtl/occtl.c | 11 +- src/occtl/occtl.h | 1 + src/occtl/unix.c | 275 ++++++++++++++++++++++++++++++++++++----- src/sec-mod-auth.c | 2 + 15 files changed, 387 insertions(+), 45 deletions(-) diff --git a/src/common/common.c b/src/common/common.c index 1f5f275d..9df47f09 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -93,6 +93,32 @@ static char tmp[32]; } } +const char* discon_reason_to_str(unsigned reason) +{ +static char tmp[32]; + + switch(reason) { + case 0: + case REASON_ANY: + return "unspecified"; + case REASON_USER_DISCONNECT: + return "user disconnected"; + case REASON_SERVER_DISCONNECT: + return "server disconnected"; + case REASON_IDLE_TIMEOUT: + return "idle timeout"; + case REASON_DPD_TIMEOUT: + return "DPD timeout"; + case REASON_ERROR: + return "unspecified error"; + case REASON_SESSION_TIMEOUT: + return "session timeout"; + default: + snprintf(tmp, sizeof(tmp), "unknown (%u)", reason); + return tmp; + } +} + ssize_t force_write(int sockfd, const void *buf, size_t len) { int left = len; diff --git a/src/common/common.h b/src/common/common.h index b9ae3e75..76d3611b 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -69,6 +69,7 @@ int recv_socket_msg(void *pool, int fd, uint8_t cmd, int *socketfd, void** msg, unpack_func, unsigned timeout); const char* cmd_request_to_str(unsigned cmd); +const char* discon_reason_to_str(unsigned reason); ssize_t oc_recvfrom_at(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen, diff --git a/src/common/ctl.proto b/src/common/ctl.proto index edd06dad..39826ca5 100644 --- a/src/common/ctl.proto +++ b/src/common/ctl.proto @@ -57,6 +57,14 @@ message user_list_rep repeated user_info_rep user = 1; } +message top_update_rep +{ + required uint32 connected = 1; + optional uint32 discon_reason = 2; + optional string discon_reason_txt = 3; + required user_list_rep user = 4; +} + message username_req { required string username = 1; diff --git a/src/main-ctl-unix.c b/src/main-ctl-unix.c index ab0895a3..9c8ea268 100644 --- a/src/main-ctl-unix.c +++ b/src/main-ctl-unix.c @@ -45,6 +45,8 @@ typedef struct method_ctx { void *pool; } method_ctx; +static void method_top(method_ctx *ctx, int cfd, uint8_t * msg, + unsigned msg_size); static void method_status(method_ctx *ctx, int cfd, uint8_t * msg, unsigned msg_size); static void method_list_users(method_ctx *ctx, int cfd, uint8_t * msg, @@ -73,12 +75,17 @@ typedef struct { char *name; unsigned cmd; method_func func; + unsigned indefinite; /* session remains open */ } ctl_method_st; #define ENTRY(cmd, func) \ - {#cmd, cmd, func} + {#cmd, cmd, func, 0} + +#define ENTRY_INDEF(cmd, func) \ + {#cmd, cmd, func, 1} static const ctl_method_st methods[] = { + ENTRY_INDEF(CTL_CMD_TOP, method_top), ENTRY(CTL_CMD_STATUS, method_status), ENTRY(CTL_CMD_RELOAD, method_reload), ENTRY(CTL_CMD_STOP, method_stop), @@ -403,7 +410,6 @@ static void method_list_users(method_ctx *ctx, int cfd, uint8_t * msg, mslog(ctx->s, NULL, LOG_DEBUG, "ctl: list-users"); - list_for_each(&ctx->s->proc_list.head, ctmp, list) { ret = append_user_info(ctx, &rep, ctmp); if (ret < 0) { @@ -424,6 +430,21 @@ static void method_list_users(method_ctx *ctx, int cfd, uint8_t * msg, return; } +static void method_top(method_ctx *ctx, int cfd, uint8_t * msg, + unsigned msg_size) +{ + /* we send the initial user list, and the we send a TOP reply message + * once a user connects/disconnects. */ + + mslog(ctx->s, NULL, LOG_DEBUG, "ctl: top"); + + /* we can only have a single top listener */ + if (ctx->s->top_fd == -1) + ctx->s->top_fd = cfd; + + method_list_users(ctx, cfd, msg, msg_size); +} + static int append_ban_info(method_ctx *ctx, BanListRep *list, struct ban_entry_st *e) @@ -707,13 +728,18 @@ static void ctl_cmd_wacher_cb(EV_P_ ev_io *w, int revents) unsigned buffer_size; method_ctx ctx; struct ctl_watcher_st *wst = container_of(w, struct ctl_watcher_st, ctl_cmd_io); - unsigned i; + unsigned i, indef = 0; ctx.s = s; - ctx.pool = wst; + ctx.pool = talloc_new(wst); + + if (ctx.pool == NULL) + goto fail; /* read request */ ret = recv(wst->fd, buffer, sizeof(buffer), 0); + if (ret == 0) + goto fail; if (ret < 3) { if (ret == -1) { @@ -726,6 +752,7 @@ static void ctl_cmd_wacher_cb(EV_P_ ev_io *w, int revents) } goto fail; } + memcpy(&length, &buffer[1], 2); buffer_size = ret - 3; @@ -743,13 +770,19 @@ static void ctl_cmd_wacher_cb(EV_P_ ev_io *w, int revents) (unsigned)buffer[0]); break; } else if (methods[i].cmd == buffer[0]) { + indef = methods[i].indefinite; methods[i].func(&ctx, wst->fd, buffer + 3, buffer_size); break; } } - return; + if (indef) { + talloc_free(ctx.pool); + return; + } fail: + if (s->top_fd == wst->fd) + s->top_fd = -1; close(wst->fd); ev_io_stop(EV_A_ w); talloc_free(wst); @@ -810,3 +843,53 @@ void ctl_handler_run_pending(main_server_st* s, ev_io *watcher) ctl_handle_commands(s); } + +void ctl_handler_notify (main_server_st* s, struct proc_st *proc, unsigned connect) +{ + TopUpdateRep rep = TOP_UPDATE_REP__INIT; + UserListRep list = USER_LIST_REP__INIT; + int ret; + method_ctx ctx; + void *pool = talloc_new(proc); + + if (s->top_fd == -1) + return; + + if (pool == NULL) { + goto fail; + } + + ctx.s = s; + ctx.pool = pool; + + mslog(s, NULL, LOG_DEBUG, "ctl: top update"); + + rep.connected = connect; + if (connect == 0 && proc->discon_reason) { + rep.has_discon_reason = 1; + rep.discon_reason = proc->discon_reason; + rep.discon_reason_txt = (char*)discon_reason_to_str(proc->discon_reason); + } + + ret = append_user_info(&ctx, &list, proc); + if (ret < 0) { + mslog(s, NULL, LOG_ERR, + "error appending user info to reply"); + goto fail; + } + rep.user = &list; + + ret = send_msg(pool, s->top_fd, CTL_CMD_TOP_UPDATE_REP, &rep, + (pack_size_func) top_update_rep__get_packed_size, + (pack_func) top_update_rep__pack); + if (ret < 0) { + mslog(s, NULL, LOG_ERR, "error sending ctl reply"); + goto fail; + } + + talloc_free(pool); + return; + fail: + talloc_free(pool); + s->top_fd = -1; +} diff --git a/src/main-ctl.h b/src/main-ctl.h index 3e107856..cdac36c2 100644 --- a/src/main-ctl.h +++ b/src/main-ctl.h @@ -9,5 +9,6 @@ void ctl_handler_deinit(main_server_st* s); void ctl_handler_set_fds(main_server_st* s, ev_io *watcher); void ctl_handler_run_pending(main_server_st* s, ev_io *watcher); +void ctl_handler_notify (main_server_st* s, struct proc_st *proc, unsigned connect); #endif diff --git a/src/main-misc.c b/src/main-misc.c index 21a1f301..eeb0ad45 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -181,7 +181,8 @@ struct proc_st *ctmp; */ void remove_proc(main_server_st * s, struct proc_st *proc, unsigned flags) { - mslog(s, proc, LOG_INFO, "user disconnected (rx: %"PRIu64", tx: %"PRIu64")", proc->bytes_in, proc->bytes_out); + mslog(s, proc, LOG_INFO, "user disconnected (reason: %s, rx: %"PRIu64", tx: %"PRIu64")", + discon_reason_to_str(proc->discon_reason), proc->bytes_in, proc->bytes_out); ev_io_stop(EV_A_ &proc->io); ev_child_stop(EV_A_ &proc->ev_child); diff --git a/src/main-sec-mod-cmd.c b/src/main-sec-mod-cmd.c index c4cafa32..2f642e7e 100644 --- a/src/main-sec-mod-cmd.c +++ b/src/main-sec-mod-cmd.c @@ -528,6 +528,8 @@ int session_close(main_server_st * s, struct proc_st *proc) proc->bytes_out = msg->bytes_out; if (msg->has_secmod_client_entries) s->secmod_client_entries = msg->secmod_client_entries; + if (msg->has_discon_reason) + proc->discon_reason = msg->discon_reason; cli_stats_msg__free_unpacked(msg, &pa); diff --git a/src/main-user.c b/src/main-user.c index 6152806e..af54f22b 100644 --- a/src/main-user.c +++ b/src/main-user.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -436,6 +437,7 @@ int user_connected(main_server_st *s, struct proc_st* proc) { int ret; + ctl_handler_notify(s,proc, 1); add_utmp_entry(s, proc); ret = call_script(s, proc, 1); @@ -447,6 +449,7 @@ int ret; void user_disconnected(main_server_st *s, struct proc_st* proc) { + ctl_handler_notify(s,proc, 0); remove_utmp_entry(s, proc); call_script(s, proc, 0); } diff --git a/src/main.c b/src/main.c index c81c1a7f..e845cf31 100644 --- a/src/main.c +++ b/src/main.c @@ -975,6 +975,7 @@ static void listen_watcher_cb (EV_P_ ev_io *w, int revents) sigprocmask(SIG_SETMASK, &sig_default_set, NULL); close(cmd_fd[0]); clear_lists(s); + if (s->top_fd != -1) close(s->top_fd); close(s->sec_mod_fd); close(s->sec_mod_fd_sync); @@ -1195,6 +1196,7 @@ int main(int argc, char** argv) write_pid_file(); + s->top_fd = -1; s->sec_mod_fd = run_sec_mod(s, &s->sec_mod_fd_sync); ret = ctl_handler_init(s); if (ret < 0) { diff --git a/src/main.h b/src/main.h index 0fcce21f..b889ba5b 100644 --- a/src/main.h +++ b/src/main.h @@ -155,6 +155,7 @@ typedef struct proc_st { * Cli stats message. */ uint64_t bytes_in; uint64_t bytes_out; + uint32_t discon_reason; /* filled on session close */ unsigned applied_iroutes; /* whether the iroutes in the config have been successfully applied */ @@ -223,6 +224,7 @@ typedef struct main_server_st { /* This one is on worker pool */ struct worker_st *ws; + int top_fd; int ctl_fd; int sec_mod_fd; /* messages are sent and received async */ diff --git a/src/occtl/ctl.h b/src/occtl/ctl.h index 3a684244..abe1202d 100644 --- a/src/occtl/ctl.h +++ b/src/occtl/ctl.h @@ -14,6 +14,7 @@ enum { CTL_CMD_DISCONNECT_ID, CTL_CMD_LIST_BANNED, CTL_CMD_UNBAN_IP, + CTL_CMD_TOP, CTL_CMD_STATUS_REP = 101, CTL_CMD_RELOAD_REP, @@ -23,6 +24,7 @@ enum { CTL_CMD_DISCONNECT_ID_REP, CTL_CMD_UNBAN_IP_REP, CTL_CMD_LIST_BANNED_REP, + CTL_CMD_TOP_UPDATE_REP }; #endif diff --git a/src/occtl/occtl.c b/src/occtl/occtl.c index e06d6d81..aaba1a31 100644 --- a/src/occtl/occtl.c +++ b/src/occtl/occtl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Red Hat + * Copyright (C) 2014, 2015 Red Hat * * Author: Nikos Mavrogiannopoulos * @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -67,6 +67,8 @@ static const commands_st commands[] = { "Prints information on the specified user", 1, 1), ENTRY("show id", "[ID]", handle_show_id_cmd, "Prints information on the specified ID", 1, 1), + ENTRY("show events", NULL, handle_events_cmd, + "Provides information about connecting users", 1, 1), ENTRY("stop", "now", handle_stop_cmd, "Terminates the server", 1, 1), ENTRY("reset", NULL, handle_reset_cmd, "Resets the screen and terminal", @@ -498,7 +500,7 @@ void initialize_readline(void) #ifdef HAVE_ORIG_READLINE rl_clear_signals(); #endif - signal(SIGINT, handle_sigint); + ocsignal(SIGINT, handle_sigint); } static int single_cmd(int argc, char **argv, void *pool, const char *file, cmd_params_st *params) @@ -533,8 +535,7 @@ int main(int argc, char **argv) exit(1); } - signal(SIGPIPE, SIG_IGN); - + ocsignal(SIGPIPE, SIG_IGN); if (argc > 1) { while (argc > 1 && argv[1][0] == '-') { diff --git a/src/occtl/occtl.h b/src/occtl/occtl.h index 5d26e2b8..b71b471c 100644 --- a/src/occtl/occtl.h +++ b/src/occtl/occtl.h @@ -86,5 +86,6 @@ int handle_unban_ip_cmd(CONN_TYPE * conn, const char *arg, cmd_params_st *params int handle_disconnect_id_cmd(CONN_TYPE * conn, const char *arg, cmd_params_st *params); int handle_reload_cmd(CONN_TYPE * conn, const char *arg, cmd_params_st *params); int handle_stop_cmd(CONN_TYPE * conn, const char *arg, cmd_params_st *params); +int handle_events_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params); #endif diff --git a/src/occtl/unix.c b/src/occtl/unix.c index 3e5b1182..2da48317 100644 --- a/src/occtl/unix.c +++ b/src/occtl/unix.c @@ -34,7 +34,12 @@ #include #include +#include +#include #include +#include +#include +#include #include #include #include @@ -56,6 +61,7 @@ static uint8_t msg_map[] = { [CTL_CMD_LIST] = CTL_CMD_LIST_REP, [CTL_CMD_LIST_BANNED] = CTL_CMD_LIST_BANNED_REP, [CTL_CMD_USER_INFO] = CTL_CMD_LIST_REP, + [CTL_CMD_TOP] = CTL_CMD_LIST_REP, [CTL_CMD_ID_INFO] = CTL_CMD_LIST_REP, [CTL_CMD_DISCONNECT_NAME] = CTL_CMD_DISCONNECT_NAME_REP, [CTL_CMD_DISCONNECT_ID] = CTL_CMD_DISCONNECT_ID_REP, @@ -526,35 +532,35 @@ int handle_disconnect_id_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_s return ret; } -int handle_list_users_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params) +static const char *fix_ciphersuite(char *txt) +{ + if (txt != NULL && txt[0] != 0) { + if (strlen(txt) > 16 && strncmp(txt, "(DTLS", 5) == 0 && + strncmp(&txt[8], ")-(RSA)-", 8) == 0) { + return txt + 16; + } + } + + return "(no dtls)"; +} + +static const char *get_ip(const char *ip1, const char *ip2) +{ + if (ip1 != NULL && ip1[0] != 0) + return ip1; + else + return ip2; +} + +void common_user_list(struct unix_ctx *ctx, UserListRep *rep, FILE *out, cmd_params_st *params) { - int ret; - struct cmd_reply_st raw; - UserListRep *rep = NULL; unsigned i; const char *vpn_ip, *groupname, *username; const char *dtls_ciphersuite; char tmpbuf[MAX_TMPSTR_SIZE]; - FILE *out; time_t t; struct tm *tm; char str_since[64]; - PROTOBUF_ALLOCATOR(pa, ctx); - - init_reply(&raw); - - entries_clear(); - - out = pager_start(params); - - ret = send_cmd(ctx, CTL_CMD_LIST, NULL, NULL, NULL, &raw); - if (ret < 0) { - goto error; - } - - rep = user_list_rep__unpack(&pa, raw.data_size, raw.data); - if (rep == NULL) - goto error; if (HAVE_JSON(params)) { common_info_cmd(rep, out, params); @@ -563,10 +569,7 @@ int handle_list_users_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st * if (username == NULL || username[0] == 0) username = NO_USER; - if (rep->user[i]->local_ip != NULL && rep->user[i]->local_ip[0] != 0) - vpn_ip = rep->user[i]->local_ip; - else - vpn_ip = rep->user[i]->local_ip6; + vpn_ip = get_ip(rep->user[i]->local_ip, rep->user[i]->local_ip6); /* add header */ if (i == 0) { @@ -588,18 +591,38 @@ int handle_list_users_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st * fprintf(out, "%8d %8s %8s %14s %14s %6s ", (int)rep->user[i]->id, username, groupname, rep->user[i]->ip, vpn_ip, rep->user[i]->tun); - dtls_ciphersuite = rep->user[i]->dtls_ciphersuite; - if (dtls_ciphersuite != NULL && dtls_ciphersuite[0] != 0) { - if (strlen(dtls_ciphersuite) > 16 && strncmp(dtls_ciphersuite, "(DTLS", 5) == 0 && - strncmp(&dtls_ciphersuite[8], ")-(RSA)-", 8) == 0) - dtls_ciphersuite += 16; - fprintf(out, "%s %14s %9s\n", tmpbuf, dtls_ciphersuite, rep->user[i]->status); - } else { - fprintf(out, "%s %14s %9s\n", tmpbuf, "(no dtls)", rep->user[i]->status); - } + dtls_ciphersuite = fix_ciphersuite(rep->user[i]->dtls_ciphersuite); + + fprintf(out, "%s %14s %9s\n", tmpbuf, dtls_ciphersuite, rep->user[i]->status); entries_add(ctx, username, strlen(username), rep->user[i]->id); } +} + +int handle_list_users_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params) +{ + int ret; + struct cmd_reply_st raw; + UserListRep *rep = NULL; + FILE *out; + PROTOBUF_ALLOCATOR(pa, ctx); + + init_reply(&raw); + + entries_clear(); + + out = pager_start(params); + + ret = send_cmd(ctx, CTL_CMD_LIST, NULL, NULL, NULL, &raw); + if (ret < 0) { + goto error; + } + + rep = user_list_rep__unpack(&pa, raw.data_size, raw.data); + if (rep == NULL) + goto error; + + common_user_list(ctx, rep, out, params); ret = 0; goto cleanup; @@ -924,6 +947,8 @@ int handle_show_user_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *p if (ret < 0) goto error; + + goto cleanup; error: @@ -937,6 +962,188 @@ int handle_show_user_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *p return ret; } +static void dummy_sighandler(int signo) +{ + return; +} + + +int handle_events_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params) +{ + uint8_t header[3]; + int ret; + struct cmd_reply_st raw; + UserListRep *rep1 = NULL; + TopUpdateRep *rep2 = NULL; + uint16_t length; + unsigned data_size; + uint8_t *data = NULL; + char *groupname; + char tmpbuf[MAX_TMPSTR_SIZE]; + PROTOBUF_ALLOCATOR(pa, ctx); + struct termios tio_old, tio_new; + sighandler_t old_sighandler; + + init_reply(&raw); + + ret = send_cmd(ctx, CTL_CMD_TOP, NULL, 0, 0, &raw); + if (ret < 0) { + goto error; + } + + rep1 = user_list_rep__unpack(&pa, raw.data_size, raw.data); + if (rep1 == NULL) + goto error; + + common_user_list(ctx, rep1, stdout, params); + + user_list_rep__free_unpacked(rep1, &pa); + rep1 = NULL; + + fputs("\n", stdout); + fputs("Press 'q' or CTRL+C to quit\n\n", stdout); + + old_sighandler = ocsignal(SIGINT, dummy_sighandler); + tcgetattr(STDIN_FILENO, &tio_old); + tio_new = tio_old; + tio_new.c_lflag &= ~(ICANON|ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &tio_new); + + /* start listening for updates */ + while(1) { + fd_set rfds; + + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + FD_SET(ctx->fd, &rfds); + + ret = select(MAX(STDIN_FILENO,ctx->fd)+1, &rfds, NULL, NULL, NULL); + if (ret == -1 && errno == EINTR) { + ret = 0; + break; + } + + if (ret == -1) { + int e = errno; + fprintf(stderr, "top: select: %s\n", strerror(e)); + ret = -1; + break; + } + + if (FD_ISSET(STDIN_FILENO, &rfds)) { + ret = getchar(); + if (ret == 'q' || ret == 'Q') { + ret = 0; + break; + } + } + + if (!FD_ISSET(ctx->fd, &rfds)) + continue; + + ret = read(ctx->fd, header, 3); + if (ret == -1) { + int e = errno; + fprintf(stderr, "top: read1: %s\n", strerror(e)); + ret = -1; + break; + } + + if (ret == 0) { + fprintf(stderr, "top: server closed the connection\n"); + ret = 0; + break; + } + + if (ret != 3) { + fprintf(stderr, "top: short read %d\n", ret); + ret = -1; + break; + } + + if (header[0] != CTL_CMD_TOP_UPDATE_REP) { + fprintf(stderr, "top: Unexpected message '%d', expected '%d'\n", (int)header[0], (int)CTL_CMD_TOP_UPDATE_REP); + ret = -1; + break; + } + + memcpy(&length, &header[1], 2); + + data_size = length; + data = talloc_size(ctx, length); + if (data == NULL) { + fprintf(stderr, "top: memory error\n"); + ret = -1; + break; + } + + ret = read(ctx->fd, data, data_size); + if (ret == -1) { + int e = errno; + fprintf(stderr, "top: read: %s\n", strerror(e)); + ret = -1; + break; + } + + /* parse and print */ + rep2 = top_update_rep__unpack(&pa, data_size, data); + if (rep2 == NULL) + goto error; + + if (HAVE_JSON(params)) { + if (rep2->connected == 0) + rep2->user->user[0]->status = talloc_strdup(rep2, "disconnected"); + else + rep2->user->user[0]->status = talloc_strdup(rep2, "connected"); + common_info_cmd(rep2->user, stdout, params); + } else { + groupname = rep2->user->user[0]->groupname; + if (groupname == NULL || groupname[0] == 0) + groupname = NO_GROUP; + + if (rep2->connected) { + printf("connected user '%s' (%u) from %s with IP %s\n", + rep2->user->user[0]->username, + rep2->user->user[0]->id, + rep2->user->user[0]->ip, + get_ip(rep2->user->user[0]->local_ip, + rep2->user->user[0]->local_ip6)); + + entries_add(ctx, rep2->user->user[0]->username, strlen(rep2->user->user[0]->username), rep2->user->user[0]->id); + } else { + print_time_ival7(tmpbuf, time(0), rep2->user->user[0]->conn_time); + printf("disconnect user '%s' (%u) from %s with IP %s (reason: %s, time: %s)\n", + rep2->user->user[0]->username, + rep2->user->user[0]->id, + rep2->user->user[0]->ip, + get_ip(rep2->user->user[0]->local_ip, rep2->user->user[0]->local_ip6), + rep2->discon_reason_txt?rep2->discon_reason_txt:"unknown", tmpbuf); + } + + } + + top_update_rep__free_unpacked(rep2, &pa); + rep2 = NULL; + } + + tcsetattr(STDIN_FILENO, TCSANOW, &tio_old); + ocsignal(SIGINT, old_sighandler); + goto cleanup; + + error: + fprintf(stderr, ERR_SERVER_UNREACHABLE); + ret = 1; + cleanup: + talloc_free(data); + if (rep1 != NULL) + user_list_rep__free_unpacked(rep1, &pa); + if (rep2 != NULL) + top_update_rep__free_unpacked(rep2, &pa); + free_reply(&raw); + + return ret; +} + int handle_show_id_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *params) { int ret; diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index 338df973..8e07d659 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -537,6 +537,8 @@ int handle_sec_auth_session_close(sec_mod_st *sec, int fd, const SecAuthSessionM rep.bytes_in = e->stats.bytes_in; rep.bytes_out = e->stats.bytes_out; rep.has_secmod_client_entries = 1; + rep.has_discon_reason = 1; + rep.discon_reason = e->discon_reason; rep.secmod_client_entries = sec_mod_client_db_elems(sec); ret = send_msg(e, fd, SM_CMD_AUTH_CLI_STATS, &rep,