]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm kick: Add support for kicking multiple usernames
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 25 Mar 2025 10:11:26 +0000 (12:11 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Sun, 30 Mar 2025 19:41:17 +0000 (19:41 +0000)
src/doveadm/doveadm-kick.c
src/doveadm/doveadm-who.c
src/doveadm/doveadm-who.h

index 380467a013e9222859fd76c58bf937b15f01b636..204e6c0615e8992594820b27285c5e48a91fcad5 100644 (file)
@@ -154,10 +154,14 @@ static void cmd_kick(struct doveadm_cmd_context *cctx)
        if (ctx.who.filter.net_bits == 0 &&
            ctx.who.filter.dest_ip.family == 0 &&
            !ctx.who.filter.username_wildcards) {
-               /* kick a single [alternative] user's all connections */
+               /* kick explicit [alternative] usernames' all connections */
+               const char *username;
                p_array_init(&ctx.kicks, ctx.who.pool, 1);
-               struct kick_session *session = array_append_space(&ctx.kicks);
-               session->username = ctx.who.filter.username;
+               array_foreach_elem(&ctx.who.filter.usernames, username) {
+                       struct kick_session *session =
+                               array_append_space(&ctx.kicks);
+                       session->username = username;
+               }
        } else {
                /* Complex kick filter. Iterate all connections and figure out
                   locally which ones to kick. */
@@ -170,7 +174,7 @@ static void cmd_kick(struct doveadm_cmd_context *cctx)
 
 #define DOVEADM_CMD_KICK_FIELDS \
        .cmd = cmd_kick, \
-       .usage = "[-a <anvil socket path>] [-f <passdb field>] [-h <dest host>] <user mask>[|]<ip/bits>", \
+       .usage = "[-a <anvil socket path>] [-f <passdb field>] [-h <dest host>] <user mask>[|]<ip/bits> [<user mask> [...]]", \
 DOVEADM_CMD_PARAMS_START \
 DOVEADM_CMD_PARAM('a',"socket-path",CMD_PARAM_STR,0) \
 DOVEADM_CMD_PARAM('f',"passdb-field",CMD_PARAM_STR,0) \
index 336112028ce07723d5fa257960083c61d4a229ce..2aae5ed684bb08f02de9fcec80e58b50605e229a 100644 (file)
@@ -173,13 +173,7 @@ who_parse_masks(struct who_context *ctx, const char *const *masks)
                        ctx->filter.net_ip = net_ip;
                        ctx->filter.net_bits = net_bits;
                } else {
-                       if (ctx->filter.username != NULL) {
-                               e_error(ctx->event,
-                                       "Multiple username masks not supported");
-                               doveadm_exit_code = EX_USAGE;
-                               return -1;
-                       }
-                       ctx->filter.username = masks[i];
+                       array_push_back(&ctx->filter.usernames, &masks[i]);
                        if (strpbrk(masks[i], "*?") != NULL)
                                ctx->filter.username_wildcards = TRUE;
                }
@@ -195,11 +189,12 @@ int who_parse_args(struct who_context *ctx, const char *alt_username_field,
        if (dest_ip != NULL)
                ctx->filter.dest_ip = *dest_ip;
 
+       t_array_init(&ctx->filter.usernames, 4);
        if (masks != NULL) {
                if (who_parse_masks(ctx, masks) < 0)
                        return -1;
        }
-       if (alt_username_field != NULL && ctx->filter.username == NULL) {
+       if (alt_username_field != NULL && array_is_empty(&ctx->filter.usernames)) {
                e_error(ctx->event,
                        "Username must be given with passdb-field parameter");
                doveadm_exit_code = EX_USAGE;
@@ -318,13 +313,26 @@ int doveadm_who_iter_deinit(struct doveadm_who_iter **_iter,
        return failed ? -1 : 0;
 }
 
+static bool who_filter_match_username(const struct who_filter *filter,
+                                     const char *username)
+{
+       if (array_is_empty(&filter->usernames))
+               return TRUE;
+
+       const char *filter_username;
+       array_foreach_elem(&filter->usernames, filter_username) {
+               if (wildcard_match_icase(username, filter_username))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
 static bool who_user_filter_match(const struct who_user *user,
                                  const struct who_filter *filter)
 {
-       if (filter->username != NULL) {
-               if (!wildcard_match_icase(user->username, filter->username))
-                       return FALSE;
-       }
+       if (!who_filter_match_username(filter, user->username))
+               return FALSE;
+
        if (filter->net_bits > 0) {
                const struct ip_addr *ip;
                bool ret = FALSE;
@@ -398,10 +406,10 @@ bool who_line_filter_match(const struct who_line *line,
 {
        unsigned int i;
 
-       if (filter->username == NULL)
+       if (array_is_empty(&filter->usernames))
                ;
        else if (filter->alt_username_field == NULL) {
-               if (!wildcard_match_icase(line->username, filter->username))
+               if (!who_filter_match_username(filter, line->username))
                        return FALSE;
        } else {
                i_assert(filter->alt_username_idx != UINT_MAX);
@@ -412,8 +420,7 @@ bool who_line_filter_match(const struct who_line *line,
                                break;
                }
                if (i != filter->alt_username_idx ||
-                   !wildcard_match_icase(line->alt_usernames[i],
-                                         filter->username))
+                   !who_filter_match_username(filter, line->alt_usernames[i]))
                        return FALSE;
        }
        if (filter->net_bits > 0) {
index f068b1c14f4d4eecbfc6de5bead37620fddeb28b..16d821d859e91ad175c8596172fed17b2ea71f61 100644 (file)
@@ -15,7 +15,7 @@ struct who_line {
 
 
 struct who_filter {
-       const char *username;
+       ARRAY_TYPE(const_string) usernames;
        bool username_wildcards;
 
        const char *alt_username_field;