doveadm-who.c revision f6b8ff28fe15eff03e0127f11cd122d3eb872e2e
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2009-2017 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void who_user_ip(const struct who_user *user, struct ip_addr *ip_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const struct ip_addr *ip = array_idx(&user->ips, 0);
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainenstatic unsigned int who_user_hash(const struct who_user *user)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int who_user_cmp(const struct who_user *user1,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strcmp(user1->username, user2->username) != 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strcmp(user1->service, user2->service) != 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* tracking only IP addresses, not usernames */
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenwho_user_has_ip(const struct who_user *user, const struct ip_addr *ip)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int who_parse_line(const char *line, struct who_line *line_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *const *args = t_strsplit_tabescaped(line);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *ident = args[0];
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen const char *p, *ip_str;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* ident = service/ip/username (imap, pop3)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ip_str = t_strdup_until(p, line_r->username++);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (str_to_uint(refcount_str, &line_r->refcount) < 0)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic bool who_user_has_pid(struct who_user *user, pid_t pid)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenstatic void who_aggregate_line(struct who_context *ctx,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen user = hash_table_lookup(ctx->users, &lookup_user);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen user->username = p_strdup(ctx->pool, line->username);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen user->service = p_strdup(ctx->pool, line->service);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (line->ip.family != 0 && !who_user_has_ip(user, &line->ip))
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainenint who_parse_args(struct who_context *ctx, const char *const *masks)
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen unsigned int i, net_bits;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (net_parse_range(masks[i], &net_ip, &net_bits) == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_error("Multiple network masks not supported");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_error("Multiple username masks not supported");
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainenvoid who_lookup(struct who_context *ctx, who_callback_t *callback)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen#define ANVIL_HANDSHAKE "VERSION\tanvil\t1\t0\n"
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen#define ANVIL_CMD ANVIL_HANDSHAKE"CONNECT-DUMP\n"
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk const char *line;
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen if (write(fd, ANVIL_CMD, strlen(ANVIL_CMD)) < 0)
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen i_fatal("write(%s) failed: %m", ctx->anvil_path);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen input = i_stream_create_fd_autoclose(&fd, (size_t)-1);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen i_fatal("read(%s) failed: %s", ctx->anvil_path,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenstatic bool who_user_filter_match(const struct who_user *user,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (!wildcard_match_icase(user->username, filter->username))
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainenstatic void who_print_user(const struct who_user *user)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen doveadm_print(dec2str(user->connection_count));
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen doveadm_print_header("username", "username", 0);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen while (hash_table_iterate(iter, ctx->users, &user, &user)) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen if (who_user_filter_match(user, &ctx->filter)) T_BEGIN {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenbool who_line_filter_match(const struct who_line *line,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!wildcard_match_icase(line->username, filter->username))
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!net_is_in_network(&line->ip, &filter->net_ip,
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainenstatic void who_print_line(struct who_context *ctx,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen unsigned int i;
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen if (!who_line_filter_match(line, &ctx->filter))
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen for (i = 0; i < line->refcount; i++) T_BEGIN {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic void cmd_who(struct doveadm_cmd_context *cctx)
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen const char *const *masks;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (!doveadm_cmd_param_str(cctx, "socket-path", &(ctx.anvil_path)))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ctx.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen (void)doveadm_cmd_param_bool(cctx, "separate-connections", &separate_connections);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ctx.pool = pool_alloconly_create("who users", 10240);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen hash_table_create(&ctx.users, ctx.pool, 0, who_user_hash, who_user_cmp);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (doveadm_cmd_param_array(cctx, "mask", &masks)) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstruct doveadm_cmd_ver2 doveadm_cmd_who_ver2 = {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen .usage = "[-a <anvil socket path>] [-1] [<user mask>] [<ip/bits>]",
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo SirainenDOVEADM_CMD_PARAM('a',"socket-path", CMD_PARAM_STR, 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo SirainenDOVEADM_CMD_PARAM('1',"separate-connections", CMD_PARAM_BOOL, 0)