From: Timo Sirainen Date: Sun, 12 Dec 2021 23:22:31 +0000 (+0200) Subject: anvil, doveadm: Add support for connection GUIDs X-Git-Tag: 2.4.0~4538 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=25cb26840dc95a0d21e44668770e2e2eada89268;p=thirdparty%2Fdovecot%2Fcore.git anvil, doveadm: Add support for connection GUIDs These are anvil-specific GUIDs that can be used to refer to a specific connection. --- diff --git a/src/anvil/anvil-connection.c b/src/anvil/anvil-connection.c index f9a2673268..cc1c932f20 100644 --- a/src/anvil/anvil-connection.c +++ b/src/anvil/anvil-connection.c @@ -68,6 +68,7 @@ anvil_connection_request(struct anvil_connection *conn, const char *const *args, const char **error_r) { const char *cmd = args[0]; + guid_128_t conn_guid; struct connect_limit_key key; unsigned int value, checksum; time_t stamp; @@ -88,7 +89,15 @@ anvil_connection_request(struct anvil_connection *conn, *error_r = "CONNECT: Invalid ident string"; return -1; } - connect_limit_connect(connect_limit, pid, &key); + if (args[0] == NULL) { + *error_r = "CONNECT: Missing conn-guid"; + return -1; + } + if (guid_128_from_string(args[0], conn_guid) < 0) { + *error_r = "CONNECT: Invalid conn-guid"; + return -1; + } + connect_limit_connect(connect_limit, pid, &key, conn_guid); } else if (strcmp(cmd, "DISCONNECT") == 0) { if (args[0] == NULL || args[1] == NULL) { *error_r = "DISCONNECT: Not enough parameters"; @@ -103,7 +112,15 @@ anvil_connection_request(struct anvil_connection *conn, *error_r = "DISCONNECT: Invalid ident string"; return -1; } - connect_limit_disconnect(connect_limit, pid, &key); + if (args[0] == NULL) { + *error_r = "DISCONNECT: Missing conn-guid"; + return -1; + } + if (guid_128_from_string(args[0], conn_guid) < 0) { + *error_r = "DISCONNECT: Invalid conn-guid"; + return -1; + } + connect_limit_disconnect(connect_limit, pid, &key, conn_guid); } else if (strcmp(cmd, "CONNECT-DUMP") == 0) { connect_limit_dump(connect_limit, conn->output); } else if (strcmp(cmd, "KILL") == 0) { diff --git a/src/anvil/connect-limit.c b/src/anvil/connect-limit.c index 4927c60bd7..310b62a151 100644 --- a/src/anvil/connect-limit.c +++ b/src/anvil/connect-limit.c @@ -18,6 +18,7 @@ struct session { /* points to userip_hash keys */ struct userip *userip; pid_t pid; + guid_128_t conn_guid; unsigned int refcount; }; @@ -50,12 +51,18 @@ static int userip_cmp(const struct userip *userip1, static unsigned int session_hash(const struct session *session) { - return userip_hash(session->userip) ^ session->pid; + return userip_hash(session->userip) ^ + guid_128_hash(session->conn_guid) ^ session->pid; } static int session_cmp(const struct session *session1, const struct session *session2) { + /* conn-guids should be unique, but only if they're not empty */ + int ret = guid_128_cmp(session1->conn_guid, session2->conn_guid); + if (ret != 0) + return ret; + if (session1->pid < session2->pid) return -1; else if (session1->pid > session2->pid) @@ -103,7 +110,8 @@ unsigned int connect_limit_lookup(struct connect_limit *limit, } void connect_limit_connect(struct connect_limit *limit, pid_t pid, - const struct connect_limit_key *key) + const struct connect_limit_key *key, + const guid_128_t conn_guid) { struct session *session; struct userip *userip; @@ -131,11 +139,13 @@ void connect_limit_connect(struct connect_limit *limit, pid_t pid, .userip = userip, .pid = pid, }; + guid_128_copy(session_lookup.conn_guid, conn_guid); session = hash_table_lookup(limit->session_hash, &session_lookup); if (session == NULL) { session = i_new(struct session, 1); session->userip = userip; session->pid = pid; + guid_128_copy(session->conn_guid, conn_guid); session->refcount = 1; hash_table_insert(limit->session_hash, session, session); } else { @@ -143,6 +153,11 @@ void connect_limit_connect(struct connect_limit *limit, pid_t pid, } } +static void session_free(struct session *session) +{ + i_free(session); +} + static void userip_hash_unref(struct connect_limit *limit, const struct userip *userip_lookup) @@ -168,7 +183,8 @@ userip_hash_unref(struct connect_limit *limit, } void connect_limit_disconnect(struct connect_limit *limit, pid_t pid, - const struct connect_limit_key *key) + const struct connect_limit_key *key, + const guid_128_t conn_guid) { struct session *session; struct userip userip_lookup = { @@ -181,19 +197,20 @@ void connect_limit_disconnect(struct connect_limit *limit, pid_t pid, .userip = &userip_lookup, .pid = pid, }; + guid_128_copy(session_lookup.conn_guid, conn_guid); session = hash_table_lookup(limit->session_hash, &session_lookup); if (session == NULL) { i_error("connect limit: disconnection for unknown " - "(pid=%s, user=%s, service=%s, ip=%s)", + "(pid=%s, user=%s, service=%s, ip=%s, conn_guid=%s)", dec2str(pid), key->username, key->service, - net_ip2addr(&key->ip)); + net_ip2addr(&key->ip), guid_128_to_string(conn_guid)); return; } if (--session->refcount == 0) { hash_table_remove(limit->session_hash, session); - i_free(session); + session_free(session); } userip_hash_unref(limit, &userip_lookup); @@ -212,7 +229,7 @@ void connect_limit_disconnect_pid(struct connect_limit *limit, pid_t pid) hash_table_remove(limit->session_hash, session); for (; session->refcount > 0; session->refcount--) userip_hash_unref(limit, session->userip); - i_free(session); + session_free(session); } } hash_table_iterate_deinit(&iter); @@ -237,6 +254,8 @@ void connect_limit_dump(struct connect_limit *limit, struct ostream *output) str_append_c(str, '\t'); if (session->userip->ip.family != 0) str_append(str, net_ip2addr(&session->userip->ip)); + str_append_c(str, '\t'); + str_append_tabescaped(str, guid_128_to_string(session->conn_guid)); str_append_c(str, '\n'); ret = o_stream_send(output, str_data(str), str_len(str)); } T_END; diff --git a/src/anvil/connect-limit.h b/src/anvil/connect-limit.h index 0d24782d0e..eb5300d27e 100644 --- a/src/anvil/connect-limit.h +++ b/src/anvil/connect-limit.h @@ -2,6 +2,7 @@ #define CONNECT_LIMIT_H #include "net.h" +#include "guid.h" struct connect_limit_key { /* User's primary username */ @@ -19,9 +20,11 @@ unsigned int connect_limit_lookup(struct connect_limit *limit, const struct connect_limit_key *key); void connect_limit_connect(struct connect_limit *limit, pid_t pid, - const struct connect_limit_key *key); + const struct connect_limit_key *key, + const guid_128_t conn_guid); void connect_limit_disconnect(struct connect_limit *limit, pid_t pid, - const struct connect_limit_key *key); + const struct connect_limit_key *key, + const guid_128_t conn_guid); void connect_limit_disconnect_pid(struct connect_limit *limit, pid_t pid); void connect_limit_dump(struct connect_limit *limit, struct ostream *output); diff --git a/src/doveadm/doveadm-who.c b/src/doveadm/doveadm-who.c index a562998b73..d1d4cf9fb3 100644 --- a/src/doveadm/doveadm-who.c +++ b/src/doveadm/doveadm-who.c @@ -83,8 +83,8 @@ static int who_parse_line(const char *line, struct who_line *line_r) const char *const *args = t_strsplit_tabescaped(line); i_zero(line_r); - /* */ - if (str_array_length(args) < 5) + /* */ + if (str_array_length(args) < 6) return -1; if (str_to_pid(args[0], &line_r->pid) < 0) @@ -97,6 +97,10 @@ static int who_parse_line(const char *line, struct who_line *line_r) if (net_addr2ip(args[4], &line_r->ip) < 0) return -1; } + if (args[5][0] != '\0') { + if (guid_128_from_string(args[5], line_r->conn_guid) < 0) + return -1; + } return 0; } diff --git a/src/doveadm/doveadm-who.h b/src/doveadm/doveadm-who.h index 57c663a95d..121637e3c5 100644 --- a/src/doveadm/doveadm-who.h +++ b/src/doveadm/doveadm-who.h @@ -1,9 +1,12 @@ #ifndef DOVEADM_WHO_H #define DOVEADM_WHO_H +#include "guid.h" + struct who_line { const char *username; const char *service; + guid_128_t conn_guid; struct ip_addr ip; pid_t pid; unsigned int refcount;