From: Timo Sirainen Date: Tue, 11 Jan 2022 12:17:46 +0000 (+0200) Subject: doveadm who/kick: Add support for -f parameter X-Git-Tag: 2.4.0~4489 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=86ddaaa32c8adfc5cf1e9fcfaeb337963a0ac733;p=thirdparty%2Fdovecot%2Fcore.git doveadm who/kick: Add support for -f parameter This is similar to what "doveadm proxy kick" has, i.e. list/kick users based on their alternative usernames (user_* passdb fields). --- diff --git a/src/doveadm/doveadm-kick.c b/src/doveadm/doveadm-kick.c index a53e9def16..eb4b301357 100644 --- a/src/doveadm/doveadm-kick.c +++ b/src/doveadm/doveadm-kick.c @@ -77,6 +77,10 @@ static void kick_users_get_via_who(struct kick_context *ctx) p_array_init(&ctx->kicks, ctx->who.pool, 64); struct doveadm_who_iter *iter = doveadm_who_iter_init(ctx->who.anvil_path); + if (!doveadm_who_iter_init_filter(iter, &ctx->who.filter)) { + doveadm_who_iter_deinit(&iter); + return; + } struct who_line who_line; while (doveadm_who_iter_next(iter, &who_line)) { if (!who_line_filter_match(&who_line, &ctx->who.filter)) @@ -125,12 +129,14 @@ static void kick_users_via_anvil(struct kick_context *ctx) static void cmd_kick(struct doveadm_cmd_context *cctx) { - const char *const *masks; + const char *passdb_field, *const *masks; struct kick_context ctx; i_zero(&ctx); if (!doveadm_cmd_param_str(cctx, "socket-path", &(ctx.who.anvil_path))) ctx.who.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL); + if (!doveadm_cmd_param_str(cctx, "passdb-field", &passdb_field)) + passdb_field = NULL; if (!doveadm_cmd_param_array(cctx, "mask", &masks)) { doveadm_exit_code = EX_USAGE; i_error("user and/or ip[/bits] must be specified."); @@ -139,7 +145,7 @@ static void cmd_kick(struct doveadm_cmd_context *cctx) ctx.conn_type = cctx->conn_type; ctx.who.pool = pool_alloconly_create("kick pids", 10240); - if (who_parse_args(&ctx.who, masks)!=0) { + if (who_parse_args(&ctx.who, passdb_field, masks) != 0) { pool_unref(&ctx.who.pool); return; } @@ -157,9 +163,10 @@ static void cmd_kick(struct doveadm_cmd_context *cctx) struct doveadm_cmd_ver2 doveadm_cmd_kick_ver2 = { .name = "kick", .cmd = cmd_kick, - .usage = "[-a ] [|]", + .usage = "[-a ] [-f ] [|]", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_PARAM('a',"socket-path",CMD_PARAM_STR,0) +DOVEADM_CMD_PARAM('f',"passdb-field",CMD_PARAM_STR,0) DOVEADM_CMD_PARAM('\0',"mask",CMD_PARAM_ARRAY,CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END }; diff --git a/src/doveadm/doveadm-who.c b/src/doveadm/doveadm-who.c index a2d7efacc6..fa3d2789d8 100644 --- a/src/doveadm/doveadm-who.c +++ b/src/doveadm/doveadm-who.c @@ -156,7 +156,8 @@ static void who_aggregate_line(struct who_context *ctx, array_push_back(&user->pids, &line->pid); } -int who_parse_args(struct who_context *ctx, const char *const *masks) +int who_parse_args(struct who_context *ctx, const char *alt_username_field, + const char *const *masks) { struct ip_addr net_ip; unsigned int i, net_bits; @@ -179,6 +180,13 @@ int who_parse_args(struct who_context *ctx, const char *const *masks) ctx->filter.username = masks[i]; } } + if (alt_username_field != NULL && ctx->filter.username == NULL) { + i_error("Username must be given with passdb-field parameter"); + doveadm_exit_code = EX_USAGE; + return -1; + } + ctx->filter.alt_username_field = alt_username_field; + ctx->filter.alt_username_idx = UINT_MAX; return 0; } @@ -224,6 +232,22 @@ struct doveadm_who_iter *doveadm_who_iter_init(const char *anvil_path) return iter; } +bool doveadm_who_iter_init_filter(struct doveadm_who_iter *iter, + struct who_filter *filter) +{ + if (filter->alt_username_field == NULL) + return TRUE; + + for (unsigned int i = 0; i < iter->alt_username_fields_count; i++) { + if (strcmp(filter->alt_username_field, + iter->alt_username_fields[i]) == 0) { + filter->alt_username_idx = i; + return TRUE; + } + } + return FALSE; +} + bool doveadm_who_iter_next(struct doveadm_who_iter *iter, struct who_line *who_line_r) { @@ -347,9 +371,25 @@ static void who_print(struct who_context *ctx) bool who_line_filter_match(const struct who_line *line, const struct who_filter *filter) { - if (filter->username != NULL) { + unsigned int i; + + if (filter->username == NULL) + ; + else if (filter->alt_username_field == NULL) { if (!wildcard_match_icase(line->username, filter->username)) return FALSE; + } else { + i_assert(filter->alt_username_idx != UINT_MAX); + if (line->alt_usernames == NULL) + return FALSE; + for (i = 0; line->alt_usernames[i] != NULL; i++) { + if (i == filter->alt_username_idx) + break; + } + if (i != filter->alt_username_idx || + !wildcard_match_icase(line->alt_usernames[i], + filter->username)) + return FALSE; } if (filter->net_bits > 0) { if (!net_is_in_network(&line->ip, &filter->net_ip, @@ -382,20 +422,22 @@ who_print_line(struct who_context *ctx, struct doveadm_who_iter *iter, static void cmd_who(struct doveadm_cmd_context *cctx) { - const char *const *masks; + const char *passdb_field, *const *masks; struct who_context ctx; bool separate_connections = FALSE; i_zero(&ctx); if (!doveadm_cmd_param_str(cctx, "socket-path", &(ctx.anvil_path))) ctx.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL); + if (!doveadm_cmd_param_str(cctx, "passdb-field", &passdb_field)) + passdb_field = NULL; (void)doveadm_cmd_param_bool(cctx, "separate-connections", &separate_connections); ctx.pool = pool_alloconly_create("who users", 10240); hash_table_create(&ctx.users, ctx.pool, 0, who_user_hash, who_user_cmp); if (doveadm_cmd_param_array(cctx, "mask", &masks)) { - if (who_parse_args(&ctx, masks) != 0) { + if (who_parse_args(&ctx, passdb_field, masks) != 0) { hash_table_destroy(&ctx.users); pool_unref(&ctx.pool); return; @@ -418,8 +460,10 @@ static void cmd_who(struct doveadm_cmd_context *cctx) doveadm_print_header_simple("dest_ip"); for (unsigned int i = 0; i < iter->alt_username_fields_count; i++) doveadm_print_header_simple(iter->alt_username_fields[i]); - while (doveadm_who_iter_next(iter, &who_line)) - who_print_line(&ctx, iter, &who_line); + if (doveadm_who_iter_init_filter(iter, &ctx.filter)) { + while (doveadm_who_iter_next(iter, &who_line)) + who_print_line(&ctx, iter, &who_line); + } } if (doveadm_who_iter_deinit(&iter) < 0) doveadm_exit_code = EX_TEMPFAIL; @@ -431,10 +475,11 @@ static void cmd_who(struct doveadm_cmd_context *cctx) struct doveadm_cmd_ver2 doveadm_cmd_who_ver2 = { .name = "who", .cmd = cmd_who, - .usage = "[-a ] [-1] [] []", + .usage = "[-a ] [-1] [-f ] [] []", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_PARAM('a',"socket-path", CMD_PARAM_STR, 0) DOVEADM_CMD_PARAM('1',"separate-connections", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('f',"passdb-field", CMD_PARAM_STR, 0) DOVEADM_CMD_PARAM('\0',"mask", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END }; diff --git a/src/doveadm/doveadm-who.h b/src/doveadm/doveadm-who.h index 7466222511..c24c23ffb0 100644 --- a/src/doveadm/doveadm-who.h +++ b/src/doveadm/doveadm-who.h @@ -16,6 +16,10 @@ struct who_line { struct who_filter { const char *username; + + const char *alt_username_field; + unsigned int alt_username_idx; + struct ip_addr net_ip; unsigned int net_bits; }; @@ -31,12 +35,16 @@ struct who_context { typedef void who_callback_t(struct who_context *ctx, const struct who_line *line); -int who_parse_args(struct who_context *ctx, const char *const *masks); +int who_parse_args(struct who_context *ctx, const char *alt_username_field, + const char *const *masks); bool who_line_filter_match(const struct who_line *line, const struct who_filter *filter); struct doveadm_who_iter *doveadm_who_iter_init(const char *anvil_path); +/* Returns TRUE if ok, FALSE if filter can never match anything. */ +bool doveadm_who_iter_init_filter(struct doveadm_who_iter *iter, + struct who_filter *filter); bool doveadm_who_iter_next(struct doveadm_who_iter *iter, struct who_line *who_line_r); int doveadm_who_iter_deinit(struct doveadm_who_iter **_iter);