Merge pull request #1976 from matt335672/fail2ban_support

Fail2ban support (#1076)
This commit is contained in:
matt335672 2021-11-18 10:11:12 +00:00 committed by GitHub
commit ce23c824ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 165 additions and 52 deletions

View File

@ -1389,11 +1389,9 @@ g_sck_accept(int sck, char *addr, int addr_bytes, char *port, int port_bytes)
}
/*****************************************************************************/
/*
* TODO: this function writes not only IP address, name is confusing
*/
void
g_write_ip_address(int rcv_sck, char *ip_address, int bytes)
g_write_connection_description(int rcv_sck, char *description, int bytes)
{
char *addr;
int port;
@ -1454,18 +1452,57 @@ g_write_ip_address(int rcv_sck, char *ip_address, int bytes)
if (ok)
{
g_snprintf(ip_address, bytes, "%s:%d - socket: %d", addr, port, rcv_sck);
g_snprintf(description, bytes, "%s:%d - socket: %d", addr, port, rcv_sck);
}
}
if (!ok)
{
g_snprintf(ip_address, bytes, "NULL:NULL - socket: %d", rcv_sck);
g_snprintf(description, bytes, "NULL:NULL - socket: %d", rcv_sck);
}
g_free(addr);
}
/*****************************************************************************/
const char *g_get_ip_from_description(const char *description,
char *ip, int bytes)
{
if (bytes > 0)
{
/* Look for the space after ip:port */
const char *end = g_strchr(description, ' ');
if (end == NULL)
{
end = description; /* Means we've failed */
}
else
{
/* Look back for the last ':' */
while (end > description && *end != ':')
{
--end;
}
}
if (end == description)
{
g_snprintf(ip, bytes, "<unknown>");
}
else if ((end - description) < (bytes - 1))
{
g_strncpy(ip, description, end - description);
}
else
{
g_strncpy(ip, description, bytes - 1);
}
}
return ip;
}
/*****************************************************************************/
void
g_sleep(int msecs)

View File

@ -93,7 +93,18 @@ int g_sck_socket_ok(int sck);
int g_sck_can_send(int sck, int millis);
int g_sck_can_recv(int sck, int millis);
int g_sck_select(int sck1, int sck2);
void g_write_ip_address(int rcv_sck, char *ip_address, int bytes);
void g_write_connection_description(int rcv_sck,
char *description, int bytes);
/**
* Extracts the IP address from the connection description
* @param description Connection description (from
* g_write_connection_description())
* @param ip buffer to write IP address to
* @param bytes Size of ip buffer
* @return Pointer to IP for convenience
*/
const char *g_get_ip_from_description(const char *description,
char *ip, int bytes);
void g_sleep(int msecs);
tintptr g_create_wait_obj(const char *name);
tintptr g_create_wait_obj_from_socket(tintptr socket, int write);

View File

@ -91,7 +91,7 @@ struct xrdp_client_info
int rdp5_performanceflags;
int brush_cache_code; /* 0 = no cache 1 = 8x8 standard cache
2 = arbitrary dimensions */
char client_ip[256];
char connection_description[256];
int max_bpp;
int jpeg; /* non standard bitmap cache v2 cap */
int offscreen_support_level;

View File

@ -378,8 +378,10 @@ xrdp_rdp_create(struct xrdp_session *session, struct trans *trans)
self->client_info.cache3_entries = 262;
self->client_info.cache3_size = 4096;
/* load client ip info */
bytes = sizeof(self->client_info.client_ip) - 1;
g_write_ip_address(trans->sck, self->client_info.client_ip, bytes);
bytes = sizeof(self->client_info.connection_description) - 1;
g_write_connection_description(trans->sck,
self->client_info.connection_description,
bytes);
self->mppc_enc = mppc_enc_new(PROTO_RDP_50);
#if defined(XRDP_NEUTRINORDP)
self->rfx_enc = rfx_context_new();

View File

@ -307,24 +307,24 @@ scp_session_set_directory(struct SCP_SESSION *s, const char *str)
/*******************************************************************/
int
scp_session_set_client_ip(struct SCP_SESSION *s, const char *str)
scp_session_set_connection_description(struct SCP_SESSION *s, const char *str)
{
if (0 == str)
{
LOG(LOG_LEVEL_WARNING, "[session:%d] set_client_ip: null ip", __LINE__);
LOG(LOG_LEVEL_WARNING, "[session:%d] set_connection_description: null description", __LINE__);
return 1;
}
if (0 != s->client_ip)
if (0 != s->connection_description)
{
g_free(s->client_ip);
g_free(s->connection_description);
}
s->client_ip = g_strdup(str);
s->connection_description = g_strdup(str);
if (0 == s->client_ip)
if (0 == s->connection_description)
{
LOG(LOG_LEVEL_WARNING, "[session:%d] set_client_ip: strdup error", __LINE__);
LOG(LOG_LEVEL_WARNING, "[session:%d] set_connection_description: strdup error", __LINE__);
return 1;
}
@ -439,7 +439,7 @@ scp_session_destroy(struct SCP_SESSION *s)
g_free(s->domain);
g_free(s->program);
g_free(s->directory);
g_free(s->client_ip);
g_free(s->connection_description);
g_free(s->errstr);
g_free(s);
}
@ -464,7 +464,7 @@ scp_session_clone(const struct SCP_SESSION *s)
result->domain = g_strdup(s->domain);
result->program = g_strdup(s->program);
result->directory = g_strdup(s->directory);
result->client_ip = g_strdup(s->client_ip);
result->connection_description = g_strdup(s->connection_description);
/* Did all the string copies succeed? */
if ((s->username != NULL && result->username == NULL) ||
@ -474,7 +474,7 @@ scp_session_clone(const struct SCP_SESSION *s)
(s->domain != NULL && result->domain == NULL) ||
(s->program != NULL && result->program == NULL) ||
(s->directory != NULL && result->directory == NULL) ||
(s->client_ip != NULL && result->client_ip == NULL))
(s->connection_description != NULL && result->connection_description == NULL))
{
scp_session_destroy(result);
result = NULL;

View File

@ -85,7 +85,7 @@ int
scp_session_set_directory(struct SCP_SESSION *s, const char *str);
int
scp_session_set_client_ip(struct SCP_SESSION *s, const char *str);
scp_session_set_connection_description(struct SCP_SESSION *s, const char *str);
int
scp_session_set_hostname(struct SCP_SESSION *s, const char *str);

View File

@ -84,7 +84,7 @@ struct SCP_SESSION
char *domain;
char *program;
char *directory;
char *client_ip;
char *connection_description;
tui8 guid[16];
/* added for state */
int current_cmd;

View File

@ -355,13 +355,13 @@ scp_v0s_accept(struct trans *atrans, struct SCP_SESSION *session)
if (s_check_rem(in_s, 2))
{
/* reading client IP address */
if (!in_string16(in_s, buf, "client IP"))
if (!in_string16(in_s, buf, "connection description"))
{
return SCP_SERVER_STATE_SIZE_ERR;
}
if (buf[0] != '\0')
{
scp_session_set_client_ip(session, buf);
scp_session_set_connection_description(session, buf);
}
}
}

View File

@ -77,17 +77,18 @@ scp_v0_process(struct trans *t, struct SCP_SESSION *s)
else if (data)
{
s_item = session_get_bydata(s->username, s->width, s->height,
s->bpp, s->type, s->client_ip);
s->bpp, s->type, s->connection_description);
if (s_item != 0)
{
display = s_item->display;
g_memcpy(s->guid, s_item->guid, 16);
if (0 != s->client_ip)
if (0 != s->connection_description)
{
LOG( LOG_LEVEL_INFO, "++ reconnected session: username %s, "
"display :%d.0, session_pid %d, ip %s",
s->username, display, s_item->pid, s->client_ip);
s->username, display, s_item->pid,
s->connection_description);
}
else
{
@ -109,10 +110,10 @@ scp_v0_process(struct trans *t, struct SCP_SESSION *s)
g_random((char *)guid, 16);
scp_session_set_guid(s, guid);
if (0 != s->client_ip)
if (0 != s->connection_description)
{
LOG(LOG_LEVEL_INFO, "++ created session (access granted): "
"username %s, ip %s", s->username, s->client_ip);
"username %s, ip %s", s->username, s->connection_description);
}
else
{
@ -157,8 +158,15 @@ scp_v0_process(struct trans *t, struct SCP_SESSION *s)
}
else
{
LOG(LOG_LEVEL_INFO, "Username or password error for user: %s",
s->username);
char ip[64];
g_get_ip_from_description(s->connection_description, ip, sizeof(ip));
/*
* The message is intended for use by fail2ban, so for
* future-proofing we only log the IP address rather than the
* connection description */
LOG(LOG_LEVEL_INFO,
"AUTHFAIL: user=%s ip=%s time=%d",
s->username, ip, g_time1());
scp_v0s_deny_connection(t);
}
if (do_auth_end)

View File

@ -79,9 +79,17 @@ scp_v1_process1(struct trans *t, struct SCP_SESSION *s)
}
else
{
char ip[64];
g_get_ip_from_description(s->connection_description,
ip, sizeof(ip));
/*
* The message is intended for use by fail2ban, so for
* future-proofing we only log the IP address rather than the
* connection description */
LOG(LOG_LEVEL_INFO,
"AUTHFAIL: user=%s ip=%s time=%d",
s->username, ip, g_time1());
scp_v1s_deny_connection(t, "Login failed");
LOG(LOG_LEVEL_INFO, "Login failed for user %s. "
"Connection terminated", s->username);
return SCP_SERVER_STATE_END;
}
return SCP_SERVER_STATE_OK;
@ -108,10 +116,10 @@ scp_v1_process1(struct trans *t, struct SCP_SESSION *s)
LOG(LOG_LEVEL_DEBUG, "No disconnected sessions for this user "
"- we create a new one");
if (0 != s->client_ip)
if (0 != s->connection_description)
{
LOG(LOG_LEVEL_INFO, "++ created session (access granted): "
"username %s, ip %s", s->username, s->client_ip);
"username %s, ip %s", s->username, s->connection_description);
}
else
{
@ -219,9 +227,9 @@ scp_v1_process43(struct trans *t, struct SCP_SESSION *s)
{
LOG(LOG_LEVEL_ERROR, "scp_v1s_reconnect_session failed");
}
if (0 != s->client_ip)
if (0 != s->connection_description)
{
LOG(LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d, ip %s", s->username, display, sitem->pid, s->client_ip);
LOG(LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d, ip %s", s->username, display, sitem->pid, s->connection_description);
}
else
{

View File

@ -92,10 +92,11 @@ dumpItemsToString(struct list *self, char *outstr, int len)
/******************************************************************************/
struct session_item *
session_get_bydata(const char *name, int width, int height, int bpp, int type,
const char *client_ip)
const char *connection_description)
{
struct session_chain *tmp;
enum SESMAN_CFG_SESS_POLICY policy = g_cfg->sess.policy;
char ip[64];
tmp = g_sessions;
@ -115,27 +116,49 @@ session_get_bydata(const char *name, int width, int height, int bpp, int type,
return 0;
}
if ((policy & SESMAN_CFG_SESS_POLICY_I) != 0)
{
/* We'll need to compare on IP addresses */
g_get_ip_from_description(connection_description, ip, sizeof(ip));
}
else
{
ip[0] = '\0';
}
LOG(LOG_LEVEL_DEBUG,
"session_get_bydata: search policy %d U %s W %d H %d bpp %d T %d IP %s",
policy, name, width, height, bpp, type, client_ip);
policy, name, width, height, bpp, type, connection_description);
while (tmp != 0)
{
char tmp_ip[64];
if ((policy & SESMAN_CFG_SESS_POLICY_I) != 0)
{
g_get_ip_from_description(tmp->item->connection_description,
tmp_ip, sizeof (tmp_ip));
}
else
{
tmp_ip[0] = '\0';
}
LOG(LOG_LEVEL_DEBUG,
"session_get_bydata: try %p U %s W %d H %d bpp %d T %d IP %s",
tmp->item,
tmp->item->name,
tmp->item->width, tmp->item->height,
tmp->item->bpp, tmp->item->type,
tmp->item->client_ip);
tmp->item->connection_description);
if (g_strncmp(name, tmp->item->name, 255) == 0 &&
(!(policy & SESMAN_CFG_SESS_POLICY_D) ||
(tmp->item->width == width && tmp->item->height == height)) &&
(!(policy & SESMAN_CFG_SESS_POLICY_I) ||
(g_strncmp_d(client_ip, tmp->item->client_ip, ':', 255) == 0)) &&
(g_strcmp(ip, tmp_ip) == 0)) &&
(!(policy & SESMAN_CFG_SESS_POLICY_C) ||
(g_strncmp(client_ip, tmp->item->client_ip, 255) == 0)) &&
(g_strncmp(connection_description, tmp->item->connection_description, 255) == 0)) &&
tmp->item->bpp == bpp &&
tmp->item->type == type)
{
@ -925,14 +948,14 @@ session_start_fork(tbus data, tui8 type, struct SCP_SESSION *s)
LOG(LOG_LEVEL_INFO, "Starting session: session_pid %d, "
"display :%d.0, width %d, height %d, bpp %d, client ip %s, "
"user name %s",
pid, display, s->width, s->height, s->bpp, s->client_ip, s->username);
pid, display, s->width, s->height, s->bpp, s->connection_description, s->username);
temp->item->pid = pid;
temp->item->display = display;
temp->item->width = s->width;
temp->item->height = s->height;
temp->item->bpp = s->bpp;
temp->item->data = data;
g_strncpy(temp->item->client_ip, s->client_ip, 255); /* store client ip data */
g_strncpy(temp->item->connection_description, s->connection_description, 255); /* store client ip data */
g_strncpy(temp->item->name, s->username, 255);
g_memcpy(temp->item->guid, s->guid, 16);
@ -1064,7 +1087,7 @@ session_kill(int pid)
/* deleting the session */
LOG(LOG_LEVEL_INFO,
"++ terminated session: username %s, display :%d.0, session_pid %d, ip %s",
tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->client_ip);
tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->connection_description);
g_free(tmp->item);
if (prev == 0)

View File

@ -75,7 +75,7 @@ struct session_item
struct session_date connect_time;
struct session_date disconnect_time;
struct session_date idle_time;
char client_ip[256];
char connection_description[256];
tui8 guid[16];
};
@ -93,7 +93,7 @@ struct session_chain
*/
struct session_item *
session_get_bydata(const char *name, int width, int height, int bpp, int type,
const char *client_ip);
const char *connection_description);
#ifndef session_find_item
#define session_find_item(a, b, c, d, e, f) session_get_bydata(a, b, c, d, e, f);
#endif

View File

@ -261,10 +261,10 @@ xrdp_mm_send_login(struct xrdp_mm *self)
out_uint16_be(s, index);
out_uint8a(s, self->wm->client_info->directory, index);
/* send client ip */
index = g_strlen(self->wm->client_info->client_ip);
/* send client connection description */
index = g_strlen(self->wm->client_info->connection_description);
out_uint16_be(s, index);
out_uint8a(s, self->wm->client_info->client_ip, index);
out_uint8a(s, self->wm->client_info->connection_description, index);
s_mark_end(s);
@ -1765,6 +1765,7 @@ xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s)
char port[256];
tui8 guid[16];
tui8 *pguid;
char username[256];
rv = 0;
in_uint16_be(s, ok);
@ -1775,11 +1776,19 @@ xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s)
in_uint8a(s, guid, 16);
pguid = guid;
}
if (xrdp_mm_get_value(self, "username",
username, sizeof(username) - 1) != 0)
{
g_strcpy(username, "???");
}
if (ok)
{
self->display = display;
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"login successful for display %d", display);
"login successful for user %s on display %d",
username, display);
if (xrdp_mm_setup_mod1(self) == 0)
{
@ -1804,8 +1813,23 @@ xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s)
}
else
{
char displayinfo[64];
if (display == 0)
{
/* A returned display of zero doesn't mean anything useful, and
* can confuse the user. It's most likely authentication has
* failed and no display was allocated */
displayinfo[0] = '\0';
}
else
{
g_snprintf(displayinfo, sizeof(displayinfo),
" on display %d", display);
}
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"login failed for display %d", display);
"login failed for user %s%s",
username, displayinfo);
xrdp_wm_show_log(self->wm);
if (self->wm->hide_log_window)
{