From: Timo Sirainen Date: Mon, 17 Jan 2022 22:25:09 +0000 (+0100) Subject: anvil: Add kick-type parameter for CONNECT X-Git-Tag: 2.4.0~4522 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cde4c3a82c5979d1fae7d2393baa0b87eb359e65;p=thirdparty%2Fdovecot%2Fcore.git anvil: Add kick-type parameter for CONNECT This indicates how the process supports kicking users. --- diff --git a/src/anvil/anvil-connection.c b/src/anvil/anvil-connection.c index 0ad686f966..ae01034f81 100644 --- a/src/anvil/anvil-connection.c +++ b/src/anvil/anvil-connection.c @@ -63,6 +63,24 @@ connect_limit_key_parse(const char *const **_args, return TRUE; } +static int str_to_kick_type(const char *str, enum kick_type *kick_type_r) +{ + switch (str[0]) { + case 'N': + *kick_type_r = KICK_TYPE_NONE; + break; + case 'S': + *kick_type_r = KICK_TYPE_SIGNAL; + break; + case 'A': + *kick_type_r = KICK_TYPE_ADMIN_SOCKET; + break; + default: + return -1; + } + return str[1] == '\0' ? 0 : -1; +} + static int anvil_connection_request(struct anvil_connection *conn, const char *const *args, const char **error_r) @@ -94,7 +112,17 @@ anvil_connection_request(struct anvil_connection *conn, *error_r = "CONNECT: Invalid ident string"; return -1; } - connect_limit_connect(connect_limit, pid, &key, conn_guid); + /* extra parameters: */ + enum kick_type kick_type = KICK_TYPE_NONE; + if (args[0] != NULL) { + if (str_to_kick_type(args[0], &kick_type) < 0) { + *error_r = "CONNECT: Invalid kick_type"; + return -1; + } + args++; + } + connect_limit_connect(connect_limit, pid, &key, + conn_guid, kick_type); } else if (strcmp(cmd, "DISCONNECT") == 0) { if (args[0] == NULL || args[1] == NULL) { *error_r = "DISCONNECT: Not enough parameters"; diff --git a/src/anvil/connect-limit.c b/src/anvil/connect-limit.c index c15ab3244f..8464782f33 100644 --- a/src/anvil/connect-limit.c +++ b/src/anvil/connect-limit.c @@ -12,6 +12,7 @@ struct process { pid_t pid; + enum kick_type kick_type; struct session *sessions; }; @@ -123,7 +124,7 @@ static struct process *process_lookup(struct connect_limit *limit, pid_t pid) static void session_link_process(struct connect_limit *limit, struct session *session, - pid_t pid) + pid_t pid, enum kick_type kick_type) { struct process *process; @@ -138,6 +139,9 @@ session_link_process(struct connect_limit *limit, struct session *session, session->process = process; DLLIST_PREPEND_FULL(&process->sessions, session, process_prev, process_next); + /* The kick_type shouldn't change for the process, but keep updating + it anyway. */ + process->kick_type = kick_type; } static void @@ -157,7 +161,8 @@ session_unlink_process(struct connect_limit *limit, struct session *session) void connect_limit_connect(struct connect_limit *limit, pid_t pid, const struct connect_limit_key *key, - const guid_128_t conn_guid) + const guid_128_t conn_guid, + enum kick_type kick_type) { struct session *session, *first_user_session; struct userip *userip; @@ -206,7 +211,7 @@ void connect_limit_connect(struct connect_limit *limit, pid_t pid, session->userip = userip; guid_128_copy(session->conn_guid, conn_guid); - session_link_process(limit, session, pid); + session_link_process(limit, session, pid, kick_type); const uint8_t *conn_guid_p = session->conn_guid; hash_table_insert(limit->session_hash, conn_guid_p, session); DLLIST_PREPEND_FULL(&first_user_session, session, @@ -362,6 +367,7 @@ connect_limit_iter_begin(struct connect_limit *limit, const char *username) while (session != NULL) { struct connect_limit_iter_result *result = array_append_space(&iter->results); + result->kick_type = session->process->kick_type; result->pid = session->process->pid; result->service = session->userip->service; guid_128_copy(result->conn_guid, session->conn_guid); diff --git a/src/anvil/connect-limit.h b/src/anvil/connect-limit.h index 4552e3f8e8..30b5971a38 100644 --- a/src/anvil/connect-limit.h +++ b/src/anvil/connect-limit.h @@ -4,6 +4,16 @@ #include "net.h" #include "guid.h" +enum kick_type { + /* This process doesn't support kicking users */ + KICK_TYPE_NONE, + /* User kicking should be done by sending TERM signal */ + KICK_TYPE_SIGNAL, + /* User kicking should be done by sending KICK-USER command to the + process's admin socket or the existing anvil connection. */ + KICK_TYPE_ADMIN_SOCKET, +}; + struct connect_limit_key { /* User's primary username */ const char *username; @@ -14,6 +24,7 @@ struct connect_limit_key { }; struct connect_limit_iter_result { + enum kick_type kick_type; pid_t pid; const char *service; guid_128_t conn_guid; @@ -27,7 +38,8 @@ 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 guid_128_t conn_guid); + const guid_128_t conn_guid, + enum kick_type kick_type); void connect_limit_disconnect(struct connect_limit *limit, pid_t pid, const struct connect_limit_key *key, const guid_128_t conn_guid);