diff --git a/libipm/ercp.c b/libipm/ercp.c index 6602c570..a96f5170 100644 --- a/libipm/ercp.c +++ b/libipm/ercp.c @@ -43,6 +43,9 @@ msgno_to_str(unsigned short n) (n == E_ERCP_CONNECT_SESSION_REQUEST) ? "ERCP_CONNECT_SESSION_REQUEST" : + (n == E_ERCP_CLIENT_CONNECT_EVENT) ? "ERCP_CLIENT_CONNECT_EVENT" : + (n == E_ERCP_CLIENT_DISCONNECT_EVENT) ? "ERCP_CLIENT_DISCONNECT_EVENT" : + NULL; } @@ -168,7 +171,7 @@ ercp_send_session_announce_event(struct trans *trans, bpp, &guid_descriptor, start_ip_addr, - start_time); + (int64_t)start_time); } /*****************************************************************************/ @@ -237,24 +240,28 @@ ercp_send_session_finished_event(struct trans *trans) int ercp_send_connect_session_request(struct trans *trans, int scp_fd, + const char *client_ip, + const char *client_name, unsigned int scp_flags) { return libipm_msg_out_simple_send( trans, (int)E_ERCP_CONNECT_SESSION_REQUEST, - "hu", scp_fd, scp_flags); + "hssu", scp_fd, client_ip, client_name, scp_flags); } /*****************************************************************************/ - int ercp_get_connect_session_request(struct trans *trans, int *scp_fd, + const char **client_ip, + const char **client_name, unsigned int *scp_flags) { /* Intermediate values */ uint32_t i_flags; - int rv = libipm_msg_in_parse(trans, "hu", scp_fd, &i_flags); + int rv = libipm_msg_in_parse(trans, "hssu", + scp_fd, client_ip, client_name, &i_flags); if (rv == 0) { *scp_flags = i_flags; @@ -262,3 +269,66 @@ ercp_get_connect_session_request(struct trans *trans, return rv; } + +/*****************************************************************************/ + +int +ercp_send_client_connect_event(struct trans *trans, + const char *client_ip, + const char *client_name, + time_t connect_time) +{ + return libipm_msg_out_simple_send( + trans, (int)E_ERCP_CLIENT_CONNECT_EVENT, + "ssx", client_ip, client_name, (int64_t)connect_time); +} + +/*****************************************************************************/ + +int +ercp_get_client_connect_event(struct trans *trans, + const char **client_ip, + const char **client_name, + time_t *connect_time) +{ + /* Intermediate values */ + int64_t i_connect_time; + + int rv = libipm_msg_in_parse(trans, "ssx", + client_ip, client_name, &i_connect_time); + if (rv == 0) + { + *connect_time = i_connect_time; + } + + return rv; +} + +/*****************************************************************************/ + +int +ercp_send_client_disconnect_event(struct trans *trans, + time_t disconnect_time) +{ + return libipm_msg_out_simple_send( + trans, (int)E_ERCP_CLIENT_DISCONNECT_EVENT, + "x", (int64_t)disconnect_time); +} + +/*****************************************************************************/ + +int +ercp_get_client_disconnect_event(struct trans *trans, + time_t *disconnect_time) +{ + /* Intermediate values */ + int64_t i_disconnect_time; + + int rv = libipm_msg_in_parse(trans, "x", &i_disconnect_time); + if (rv == 0) + { + *disconnect_time = i_disconnect_time; + } + + return rv; +} diff --git a/libipm/ercp.h b/libipm/ercp.h index 0d8e6a08..08f6d53d 100644 --- a/libipm/ercp.h +++ b/libipm/ercp.h @@ -47,8 +47,13 @@ enum ercp_msg_code E_ERCP_SESSION_ANNOUNCE_EVENT, // sesexec -> sesman E_ERCP_SESSION_FINISHED_EVENT, // sesexec -> sesman - E_ERCP_CONNECT_SESSION_REQUEST // sesman -> sesexec - // No E_EICP_CONNECT_SESSION_RESPONSE - response sent over SCP + // A connect session request has no matching response, but if + // successful, a client connect event will be generated. + E_ERCP_CONNECT_SESSION_REQUEST, // sesman -> sesexec + // No E_ERCP_CONNECT_SESSION_RESPONSE + + E_ERCP_CLIENT_CONNECT_EVENT, // sesexec -> sesman + E_ERCP_CLIENT_DISCONNECT_EVENT // sesexec -> sesman }; /* Common facilities */ @@ -236,14 +241,18 @@ ercp_send_session_finished_event(struct trans *trans); * A response is sent directly to the SCP client, rather than back * to sesman * - * @param trans EiCP transport + * @param trans ERCP transport * @param scp_fd SCP file descriptor for a response + * @param client_ip IP address of connecting client + * @param client_name Name of connecting client (from RDP client core info) * @param scp_flags Flags from scp_send_connect_session_request() * @return != 0 for error */ int ercp_send_connect_session_request(struct trans *trans, int scp_fd, + const char *client_ip, + const char *client_name, unsigned int scp_flags); /** @@ -258,13 +267,84 @@ ercp_send_connect_session_request(struct trans *trans, * * @param trans ERCP transport * @param[out] scp_fd SCP file descriptor for a response + * @param[out] client_ip IP address of connecting client + * @param[out] client_name Name of connecting client * @param[out] scp_flags Flags from scp_send_connect_session_request() * @return != 0 for error */ int ercp_get_connect_session_request(struct trans *trans, int *scp_fd, + const char **client_ip, + const char **client_name, unsigned int *scp_flags); +/** + * Send an E_ERCP_CLIENT_CONNECT_EVENT + * + * Direction : sesexec -> sesman + * + * This request tells sesman to update its connected client information + * + * @param trans ERCP transport + * @param client_ip IP address of connecting client + * @param client_name Name of connecting client (from RDP client core info) + * @param connect_time Time at which the connect event occurred + * @return != 0 for error + */ +int +ercp_send_client_connect_event(struct trans *trans, + const char *client_ip, + const char *client_name, + time_t connect_time); + +/** + * Get an E_ERCP_CLIENT_CONNECT_EVENT + * + * Direction : sesexec -> sesman + * + * This request tells sesman to update its connected client information + * + * @param trans ERCP transport + * @param[out] client_ip IP address of connecting client + * @param[out] client_name Name of connecting client (from RDP client core info) + * @param[out] connect_time Time at which the connect event occurred + * @return != 0 for error + */ +int +ercp_get_client_connect_event(struct trans *trans, + const char **client_ip, + const char **client_name, + time_t *connect_time); + +/** + * Send an E_ERCP_CLIENT_DISCONNECT_EVENT + * + * Direction : sesexec -> sesman + * + * This request tells sesman to update its connected client information + * + * @param trans ERCP transport + * @param disconnect_time Time at which the disconnect event occurred + * @return != 0 for error + */ +int +ercp_send_client_disconnect_event(struct trans *trans, + time_t disconnect_time); + +/** + * Get an E_ERCP_CLIENT_DISCONNECT_EVENT + * + * Direction : sesexec -> sesman + * + * This request tells sesman to update its connected client information + * + * @param trans ERCP transport + * @param[out] disconnect_time Time at which the disconnect event occurred + * @return != 0 for error + */ +int +ercp_get_client_disconnect_event(struct trans *trans, + time_t *disconnect_time); #endif /* ERCP_H */ diff --git a/libipm/scp.c b/libipm/scp.c index 6e48dbd6..df992417 100644 --- a/libipm/scp.c +++ b/libipm/scp.c @@ -525,6 +525,8 @@ scp_get_create_session_response(struct trans *trans, int scp_send_connect_session_request(struct trans *trans, const struct guid *guid, + const char *client_ip, + const char *client_name, unsigned int flags) { struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) }; @@ -532,7 +534,7 @@ scp_send_connect_session_request(struct trans *trans, return libipm_msg_out_simple_send( trans, (int)E_SCP_CONNECT_SESSION_REQUEST, - "Bu", &guid_descriptor, flags); + "Bssu", &guid_descriptor, client_ip, client_name, flags); } /*****************************************************************************/ @@ -540,13 +542,17 @@ scp_send_connect_session_request(struct trans *trans, int scp_get_connect_session_request(struct trans *trans, struct guid *guid, + const char **client_ip, + const char **client_name, unsigned int *flags) { struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) }; /* Intermediate values */ uint32_t i_flags; - int rv = libipm_msg_in_parse( trans, "Bu", &guid_descriptor, &i_flags); + int rv = libipm_msg_in_parse(trans, "Bssu", + &guid_descriptor, client_ip, client_name, + &i_flags); if (rv == 0) { @@ -737,7 +743,7 @@ scp_send_list_sessions_response( rv = libipm_msg_out_simple_send( trans, (int)E_SCP_LIST_SESSIONS_RESPONSE, - "iiuyqqyxis", + "iiuyqqyxisssx", status, info->sid, info->display, @@ -745,9 +751,12 @@ scp_send_list_sessions_response( info->width, info->height, info->bpp, - info->start_time, + (int64_t)info->start_time, info->uid, - info->start_ip_addr); + info->start_ip_addr, + info->client_ip, + info->client_name, + (int64_t)info->last_connect_disconnect); } return rv; @@ -785,10 +794,13 @@ scp_get_list_sessions_response( int64_t i_start_time; int32_t i_uid; char *i_start_ip_addr; + char *i_client_ip; + char *i_client_name; + int64_t i_last_connect_disconnect; rv = libipm_msg_in_parse( trans, - "iuyqqyxis", + "iuyqqyxisssx", &i_sid, &i_display, &i_type, @@ -797,25 +809,35 @@ scp_get_list_sessions_response( &i_bpp, &i_start_time, &i_uid, - &i_start_ip_addr); + &i_start_ip_addr, + &i_client_ip, + &i_client_name, + &i_last_connect_disconnect); if (rv == 0) { /* Allocate a block of memory large enough for the * structure result, and the strings it contains */ unsigned int len = sizeof(struct scp_session_info) + - g_strlen(i_start_ip_addr) + 1; + g_strlen(i_start_ip_addr) + 1 + + g_strlen(i_client_ip) + 1 + + g_strlen(i_client_name) + 1; if ((p = (struct scp_session_info *)g_malloc(len, 1)) == NULL) { *status = E_SCP_LS_NO_MEMORY; } else { - /* Set up the string pointers in the block to point - * into the memory allocated after the block */ - p->start_ip_addr = + /* Set a pointer to access the strings after the block */ + char *memptr = (char *)p + sizeof(struct scp_session_info); - +#define COPY_STRING(ptr,src) \ + { \ + size_t len = strlen(src) + 1; \ + (ptr) = memptr; \ + memcpy(memptr, src, len); \ + memptr += len; \ + } /* Copy the data over */ p->sid = i_sid; p->display = i_display; @@ -825,7 +847,11 @@ scp_get_list_sessions_response( p->bpp = i_bpp; p->start_time = i_start_time; p->uid = i_uid; - g_strcpy(p->start_ip_addr, i_start_ip_addr); + COPY_STRING(p->start_ip_addr, i_start_ip_addr); + COPY_STRING(p->client_ip, i_client_ip); + COPY_STRING(p->client_name, i_client_name); + p->last_connect_disconnect = i_last_connect_disconnect; +#undef COPY_STRING } } } diff --git a/libipm/scp.h b/libipm/scp.h index fb68d0b8..a0179c64 100644 --- a/libipm/scp.h +++ b/libipm/scp.h @@ -421,6 +421,8 @@ scp_get_create_session_response(struct trans *trans, * * @param trans SCP transport * @param guid Session guid + * @param client_ip IP address of connecting client + * @param client_name Name of connecting client (from RDP client core info) * @param flags Flags which affect the returned FDs * @return != 0 for error * @@ -429,6 +431,8 @@ scp_get_create_session_response(struct trans *trans, int scp_send_connect_session_request(struct trans *trans, const struct guid *guid, + const char *client_ip, + const char *client_name, unsigned int flags); @@ -437,12 +441,16 @@ scp_send_connect_session_request(struct trans *trans, * * @param trans SCP transport * @param[out] guid Session guid + * @param[out] client_ip IP address of connecting client + * @param[out] client_name Name of connecting client * @param[out] flags Flags which affect the returned FDs * @return != 0 for error */ int scp_get_connect_session_request(struct trans *trans, struct guid *guid, + const char **client_ip, + const char **client_name, unsigned int *flags); /** diff --git a/libipm/scp_application_types.h b/libipm/scp_application_types.h index 1c5630dd..421aed58 100644 --- a/libipm/scp_application_types.h +++ b/libipm/scp_application_types.h @@ -59,6 +59,9 @@ struct scp_session_info time_t start_time; ///< When session was created uid_t uid; ///< Username for session char *start_ip_addr; ///< IP address of starting client + char *client_ip; ///< Current client IP + char *client_name; ///< Current client name + time_t last_connect_disconnect; ///< Time of last client connect/disconnect }; /** diff --git a/sesman/ercp_process.c b/sesman/ercp_process.c index e34ae2d6..ea1e9efc 100644 --- a/sesman/ercp_process.c +++ b/sesman/ercp_process.c @@ -91,6 +91,51 @@ process_session_finished_event(struct session_item *si) si->sesexec_trans->status = TRANS_STATUS_DOWN; } +/******************************************************************************/ +static int +process_client_connect_event(struct session_item *si) +{ + int rv; + const char *client_ip; + const char *client_name; + time_t connect_time; + + rv = ercp_get_client_connect_event(si->sesexec_trans, + &client_ip, &client_name, &connect_time); + if (rv == 0) + { + strlcpy(si->client_ip, client_ip, sizeof(si->client_ip)); + strlcpy(si->client_name, client_name, sizeof(si->client_name)); + si->last_connect_disconnect = connect_time; + LOG(LOG_LEVEL_INFO, + "sesman: Session on display :%d is connected from client '%s'", + si->display, si->client_name); + } + + return rv; +} + +/******************************************************************************/ +static int +process_client_disconnect_event(struct session_item *si) +{ + int rv; + time_t disconnect_time; + + rv = ercp_get_client_disconnect_event(si->sesexec_trans, &disconnect_time); + if (rv == 0) + { + si->client_ip[0] = '\0'; + si->client_name[0] = '\0'; + si->last_connect_disconnect = disconnect_time; + LOG(LOG_LEVEL_INFO, + "sesman: Session on display :%d has no client connection", + si->display); + } + + return rv; +} + /******************************************************************************/ int ercp_process(struct session_item *si) @@ -108,11 +153,19 @@ ercp_process(struct session_item *si) process_session_finished_event(si); break; + case E_ERCP_CLIENT_CONNECT_EVENT: + rv = process_client_connect_event(si); + break; + + case E_ERCP_CLIENT_DISCONNECT_EVENT: + rv = process_client_disconnect_event(si); + break; + default: { char buff[64]; ercp_msgno_to_str(msgno, buff, sizeof(buff)); - LOG(LOG_LEVEL_ERROR, "Ignored EICP message %s", buff); + LOG(LOG_LEVEL_ERROR, "Ignored ERCP message %s", buff); } } return rv; diff --git a/sesman/scp_process.c b/sesman/scp_process.c index 819b51c6..40b0e820 100644 --- a/sesman/scp_process.c +++ b/sesman/scp_process.c @@ -576,10 +576,13 @@ process_connect_session_request(struct scp_list_item *sli) int rv; /* Client parameters describing new session */ struct guid guid; + const char *client_ip; + const char *client_name; unsigned int flags; enum scp_sconnect_status status = E_SCP_SCONNECT_OK; - rv = scp_get_connect_session_request(sli->client_trans, &guid, &flags); + rv = scp_get_connect_session_request(sli->client_trans, &guid, + &client_ip, &client_name, &flags); if (rv == 0) { @@ -615,6 +618,8 @@ process_connect_session_request(struct scp_list_item *sli) ercp_stat = ercp_send_connect_session_request( s_item->sesexec_trans, sli->client_trans->sck, + client_ip, + client_name, flags); if (ercp_stat != 0) diff --git a/sesman/sesexec/ercp_server.c b/sesman/sesexec/ercp_server.c index 434de3f7..7702e30b 100644 --- a/sesman/sesexec/ercp_server.c +++ b/sesman/sesexec/ercp_server.c @@ -72,8 +72,10 @@ handle_connect_session_request(struct trans *self) { int scp_fd = -1; unsigned int scp_flags; - - int rv = ercp_get_connect_session_request(self, &scp_fd, &scp_flags); + const char *client_ip; + const char *client_name; + int rv = ercp_get_connect_session_request(self, &scp_fd, &client_ip, + &client_name, &scp_flags); if (rv == 0) { struct trans *scp_trans; @@ -107,10 +109,20 @@ handle_connect_session_request(struct trans *self) scp_status = get_session_fds(g_session_data, scp_flags, &display_fd, &chan_fd); - // Tell sesman about the new client connection - if (g_ecp_trans != NULL) + if (scp_status == E_SCP_SCONNECT_OK) { - /// TODO: client connect event + // Tell sesman about the new client connection + strlcpy(g_client_ip, client_ip, sizeof(g_client_ip)); + strlcpy(g_client_name, client_name, sizeof(g_client_name)); + g_last_connect_disconnect = time(NULL); + + if (g_ecp_trans != NULL) + { + (void)ercp_send_client_connect_event( + g_ecp_trans, g_client_ip, g_client_name, + g_last_connect_disconnect); + + } } // Pass the session file descriptors to the client diff --git a/sesman/sesexec/sesexec.c b/sesman/sesexec/sesexec.c index 788b7908..7d0cb259 100644 --- a/sesman/sesexec/sesexec.c +++ b/sesman/sesexec/sesexec.c @@ -74,6 +74,9 @@ pid_t g_pid; struct trans *g_ecp_trans; struct trans *g_ccp_trans; +char g_client_ip[MAX_PEER_ADDRSTRLEN]; +char g_client_name[INFO_CLIENT_NAME_BYTES_UTF8]; +time_t g_last_connect_disconnect; /* * Module-scope globals @@ -486,7 +489,17 @@ sesexec_main_loop(void) // xrdp has gone away. LOG(LOG_LEVEL_INFO, "sesexec_main_loop: " "xrdp has exited"); - // TODO: Tell sesman xrdp has exited + + g_client_ip[0] = '\0'; + g_client_name[0] = '\0'; + g_last_connect_disconnect = time(NULL); + + if (g_ecp_trans != NULL) + { + (void)ercp_send_client_disconnect_event( + g_ecp_trans, g_last_connect_disconnect); + + } close_ccp_trans(); } else diff --git a/sesman/sesexec/sesexec.h b/sesman/sesexec/sesexec.h index fa0dc2d5..55db60f8 100644 --- a/sesman/sesexec/sesexec.h +++ b/sesman/sesexec/sesexec.h @@ -30,6 +30,7 @@ #include #include "ccp_application_types.h" +#include "xrdp_constants.h" struct config_sesman; struct trans; @@ -106,6 +107,21 @@ extern struct trans *g_ecp_trans; */ extern struct trans *g_ccp_trans; +/** + * Last connected client IP address + */ +extern char g_client_ip[MAX_PEER_ADDRSTRLEN]; + +/** + * Last connected client name + */ +extern char g_client_name[INFO_CLIENT_NAME_BYTES_UTF8]; + +/** + * Last connect / disconnect time + */ +extern time_t g_last_connect_disconnect; + /** * Callback to process incoming ERCP data */ diff --git a/sesman/sesexec/sesexec_discover.c b/sesman/sesexec/sesexec_discover.c index 5d573aa2..955d6167 100644 --- a/sesman/sesexec/sesexec_discover.c +++ b/sesman/sesexec/sesexec_discover.c @@ -101,6 +101,20 @@ discover_trans_conn_in(struct trans *trans, struct trans *new_trans) &sp->guid, g_login_info->ip_addr, session_get_start_time(g_session_data)); + + // Tell semsan about the last client connect or disconnect + if (g_ccp_trans != NULL) + { + (void)ercp_send_client_connect_event(new_trans, + g_client_ip, + g_client_name, + g_last_connect_disconnect); + } + else + { + (void)ercp_send_client_disconnect_event(new_trans, + g_last_connect_disconnect); + } } } return rv; diff --git a/sesman/session_list.c b/sesman/session_list.c index 4b42992b..073b8b23 100644 --- a/sesman/session_list.c +++ b/sesman/session_list.c @@ -336,18 +336,23 @@ session_list_get_byuid(const uid_t *uid, unsigned int *cnt, unsigned int flags) if (SESSION_IN_USE(si) && (uid == NULL || *uid == si->uid)) { - (sess[index]).sid = si->sesexec_pid; - (sess[index]).display = si->display; - (sess[index]).type = si->type; - (sess[index]).height = si->start_height; - (sess[index]).width = si->start_width; - (sess[index]).bpp = si->bpp; - (sess[index]).start_time = si->start_time; - (sess[index]).uid = si->uid; - (sess[index]).start_ip_addr = g_strdup(si->start_ip_addr); + sess[index].sid = si->sesexec_pid; + sess[index].display = si->display; + sess[index].type = si->type; + sess[index].height = si->start_height; + sess[index].width = si->start_width; + sess[index].bpp = si->bpp; + sess[index].start_time = si->start_time; + sess[index].uid = si->uid; + sess[index].start_ip_addr = g_strdup(si->start_ip_addr); + sess[index].client_ip = g_strdup(si->client_ip); + sess[index].client_name = g_strdup(si->client_name); + sess[index].last_connect_disconnect = si->last_connect_disconnect; /* Check for string allocation failures */ - if ((sess[index]).start_ip_addr == NULL) + if (sess[index].start_ip_addr == NULL || + sess[index].client_ip == NULL || + sess[index].client_name == NULL) { free_session_info_list(sess, *cnt); (*cnt) = 0; @@ -390,6 +395,8 @@ free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt) for (i = 0 ; i < cnt ; ++i) { g_free(sesslist[i].start_ip_addr); + g_free(sesslist[i].client_ip); + g_free(sesslist[i].client_name); } } diff --git a/sesman/session_list.h b/sesman/session_list.h index 01296170..bca1acb4 100644 --- a/sesman/session_list.h +++ b/sesman/session_list.h @@ -68,6 +68,9 @@ struct session_item struct guid guid; char start_ip_addr[MAX_PEER_ADDRSTRLEN]; time_t start_time; + char client_ip[MAX_PEER_ADDRSTRLEN]; + char client_name[INFO_CLIENT_NAME_BYTES_UTF8]; + time_t last_connect_disconnect; }; /** diff --git a/sesman/tools/sesadmin.c b/sesman/tools/sesadmin.c index 2265c056..70074d05 100644 --- a/sesman/tools/sesadmin.c +++ b/sesman/tools/sesadmin.c @@ -151,6 +151,21 @@ print_session(const struct scp_session_info *s) { printf("\tStart IP address: %s\n", s->start_ip_addr); } + if (s->client_ip[0] != '\0' && s->client_name[0] != '\0') + { + printf("\tConnection state: connected\n"); + printf("\tConnected client IP: %s\n", s->client_ip); + printf("\tConnected client name: %s\n", s->client_name); + printf("\tConnection start time: %s\n", + ctime(&s->last_connect_disconnect)); + } + else + { + printf("\tConnection state: disconnected\n"); + printf("\tConnection end time: %s\n", + (s->last_connect_disconnect == 0) ? "-" : + ctime(&s->last_connect_disconnect)); + } g_free(username); } diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index f3ced9e6..700ffc34 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -363,7 +363,10 @@ xrdp_mm_get_session_fds(struct xrdp_mm *self) } rv = scp_send_connect_session_request(self->sesman_trans, - &self->guid, flags); + &self->guid, + self->wm->client_info->client_ip, + self->wm->client_info->client_name, + flags); return rv; }