]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
anvil: Add support for KICK_TYPE_SIGNAL_WITH_SOCKET
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 3 Feb 2022 15:20:26 +0000 (16:20 +0100)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Sun, 13 Feb 2022 10:23:26 +0000 (10:23 +0000)
This provides (mostly) race-free SIGTERM kick that doesn't kick the wrong
user.

src/anvil/anvil-connection.c
src/anvil/connect-limit.h

index 2c773c718776871220d513b06a3a7a37fb4421f4..039e79a4bf5b7852eb30f4f8a46156cb395072cb 100644 (file)
@@ -127,6 +127,9 @@ static int str_to_kick_type(const char *str, enum kick_type *kick_type_r)
        case 'A':
                *kick_type_r = KICK_TYPE_ADMIN_SOCKET;
                break;
+       case 'W':
+               *kick_type_r = KICK_TYPE_SIGNAL_WITH_SOCKET;
+               break;
        default:
                return -1;
        }
@@ -230,8 +233,12 @@ kick_user_iter(struct anvil_connection *conn, struct connect_limit_iter *iter,
                        }
                        break;
                case KICK_TYPE_ADMIN_SOCKET:
+               case KICK_TYPE_SIGNAL_WITH_SOCKET:
                        str_truncate(cmd, 0);
-                       str_append(cmd, "KICK-USER\t");
+                       if (result.kick_type == KICK_TYPE_SIGNAL_WITH_SOCKET)
+                               str_append(cmd, "KICK-USER-SIGNAL\t");
+                       else
+                               str_append(cmd, "KICK-USER\t");
                        str_append_tabescaped(cmd, result.username);
                        if (!guid_128_is_empty(result.conn_guid) &&
                            add_conn_guid) {
@@ -244,6 +251,14 @@ kick_user_iter(struct anvil_connection *conn, struct connect_limit_iter *iter,
                        kick->cmd_refcount++;
                        admin_cmd_send(result.service, result.pid, str_c(cmd),
                                       kick_user_callback, kick);
+                       if (result.kick_type == KICK_TYPE_SIGNAL_WITH_SOCKET) {
+                               if (kill(result.pid, SIGTERM) == 0)
+                                       kick->kick_count++;
+                               else if (errno != ESRCH) {
+                                       i_error("kill(%ld) failed: %m",
+                                               (long)result.pid);
+                               }
+                       }
                        break;
                }
                prev_pid = result.pid;
index 80492e99057ed3192e5f960db9ce2baf58b7f44f..1af28acea370e592f83391e69744d8eebd1a2d6c 100644 (file)
@@ -12,6 +12,10 @@ enum kick_type {
        /* 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,
+       /* Use KICK-USER command together with TERM signal. The SIGTERM handler
+          reads and processes the KICK-USER command. This way if there's a
+          race condition wrong process isn't killed. */
+       KICK_TYPE_SIGNAL_WITH_SOCKET,
 };
 
 struct connect_limit_key {