doveadm-who.c revision c03f712279c54fc29368a914375a4c66855d253b
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2009-2014 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "array.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "net.h"
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen#include "istream.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "wildcard-match.h"
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen#include "hash.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "str.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "doveadm.h"
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen#include "doveadm-print.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "doveadm-who.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen#include <stdio.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen#include <unistd.h>
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
5a6343181a5183b1ae1c39d40fc5a1deb3b840d9Timo Sirainenstruct who_user {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *username;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *service;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ARRAY(struct ip_addr) ips;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ARRAY(pid_t) pids;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int connection_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic unsigned int who_user_hash(const struct who_user *user)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return str_hash(user->username) + str_hash(user->service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int who_user_cmp(const struct who_user *user1,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct who_user *user2)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(user1->username, user2->username) != 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (strcmp(user1->service, user2->service) != 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenstatic bool
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenwho_user_has_ip(const struct who_user *user, const struct ip_addr *ip)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen{
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen const struct ip_addr *ex_ip;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen array_foreach(&user->ips, ex_ip) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (net_ip_compare(ex_ip, ip))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
104318260228780a5c6b3181b3401e8e504e2776Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int who_parse_line(const char *line, struct who_line *line_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const *args = t_strsplit_tab(line);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *ident = args[0];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *pid_str = args[1];
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen const char *refcount_str = args[2];
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen const char *p, *ip_str;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen memset(line_r, 0, sizeof(*line_r));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen p = strchr(ident, '/');
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen line_r->pid = strtoul(pid_str, NULL, 10);
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen line_r->service = t_strdup_until(ident, p++);
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen line_r->username = strchr(p, '/');
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen if (line_r->username == NULL)
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen return -1;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen line_r->refcount = atoi(refcount_str);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen ip_str = t_strdup_until(p, line_r->username++);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen (void)net_addr2ip(ip_str, &line_r->ip);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen return 0;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen}
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainenstatic bool who_user_has_pid(struct who_user *user, pid_t pid)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen{
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen const pid_t *ex_pid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen array_foreach(&user->pids, ex_pid) {
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen if (*ex_pid == pid)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void who_aggregate_line(struct who_context *ctx,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const struct who_line *line)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct who_user *user, lookup_user;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen lookup_user.username = line->username;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen lookup_user.service = line->service;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user = hash_table_lookup(ctx->users, &lookup_user);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (user == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user = p_new(ctx->pool, struct who_user, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->username = p_strdup(ctx->pool, line->username);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->service = p_strdup(ctx->pool, line->service);
7fe37c2b0e4cd2a39896ab16e47eb418a59e3934Timo Sirainen p_array_init(&user->ips, ctx->pool, 3);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen p_array_init(&user->pids, ctx->pool, 8);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen hash_table_insert(ctx->users, user, user);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->connection_count += line->refcount;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen if (line->ip.family != 0 && !who_user_has_ip(user, &line->ip))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_append(&user->ips, &line->ip, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (!who_user_has_pid(user, line->pid))
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen array_append(&user->pids, &line->pid, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid who_parse_args(struct who_context *ctx, char **args)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen struct ip_addr net_ip;
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen unsigned int net_bits;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen while (args[1] != NULL) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (net_parse_range(args[1], &net_ip, &net_bits) == 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (ctx->filter.net_bits != 0)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen usage();
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen ctx->filter.net_ip = net_ip;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen ctx->filter.net_bits = net_bits;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen } else {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen if (ctx->filter.username != NULL)
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen usage();
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen ctx->filter.username = args[1];
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen args++;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen}
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid who_lookup(struct who_context *ctx, who_callback_t *callback)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define ANVIL_HANDSHAKE "VERSION\tanvil\t1\t0\n"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define ANVIL_CMD ANVIL_HANDSHAKE"CONNECT-DUMP\n"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream *input;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen const char *line;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int fd;
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen fd = doveadm_connect(ctx->anvil_path);
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen net_set_nonblock(fd, FALSE);
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen input = i_stream_create_fd(fd, (size_t)-1, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (write(fd, ANVIL_CMD, strlen(ANVIL_CMD)) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_fatal("write(%s) failed: %m", ctx->anvil_path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) {
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainen if (*line == '\0')
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen T_BEGIN {
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen struct who_line who_line;
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (who_parse_line(line, &who_line) < 0)
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen i_error("Invalid input: %s", line);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen else
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen callback(ctx, &who_line);
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen } T_END;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (input->stream_errno != 0)
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen i_fatal("read(%s) failed: %m", ctx->anvil_path);
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_destroy(&input);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen}
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainenstatic bool who_user_filter_match(const struct who_user *user,
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen const struct who_filter *filter)
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (filter->username != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!wildcard_match_icase(user->username, filter->username))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (filter->net_bits > 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct ip_addr *ip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool ret = FALSE;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen array_foreach(&user->ips, ip) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (net_is_in_network(ip, &filter->net_ip,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen filter->net_bits)) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen ret = TRUE;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen break;
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen }
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen }
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen if (!ret)
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen return FALSE;
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen }
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen return TRUE;
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen}
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainenstatic void who_print_user(const struct who_user *user)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct ip_addr *ip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const pid_t *pid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen string_t *str = t_str_new(256);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen doveadm_print(user->username);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen doveadm_print(dec2str(user->connection_count));
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen doveadm_print(user->service);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_append_c(str, '(');
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen array_foreach(&user->pids, pid)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_printfa(str, "%ld ", (long)*pid);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (str_len(str) > 1)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_truncate(str, str_len(str)-1);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_append_c(str, ')');
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen doveadm_print(str_c(str));
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_truncate(str, 0);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_append_c(str, '(');
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen array_foreach(&user->ips, ip)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_printfa(str, "%s ", net_ip2addr(ip));
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (str_len(str) > 1)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_truncate(str, str_len(str)-1);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_append_c(str, ')');
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen doveadm_print(str_c(str));
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen}
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenstatic void who_print(struct who_context *ctx)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen{
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen struct hash_iterate_context *iter;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen struct who_user *user;
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen doveadm_print_header("username", "username", 0);
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen doveadm_print_header("connections", "#",
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY);
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen doveadm_print_header("service", "proto", 0);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen doveadm_print_header("pids", "(pids)", 0);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen doveadm_print_header("ips", "(ips)", 0);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen iter = hash_table_iterate_init(ctx->users);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen while (hash_table_iterate(iter, ctx->users, &user, &user)) {
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen if (who_user_filter_match(user, &ctx->filter)) T_BEGIN {
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen who_print_user(user);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen } T_END;
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen }
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen hash_table_iterate_deinit(&iter);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen}
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenbool who_line_filter_match(const struct who_line *line,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen const struct who_filter *filter)
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen{
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen if (filter->username != NULL) {
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen if (!wildcard_match_icase(line->username, filter->username))
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen return FALSE;
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen }
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen if (filter->net_bits > 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (!net_is_in_network(&line->ip, &filter->net_ip,
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen filter->net_bits))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen}
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainenstatic void who_print_line(struct who_context *ctx,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen const struct who_line *line)
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen{
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen unsigned int i;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (!who_line_filter_match(line, &ctx->filter))
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen return;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen for (i = 0; i < line->refcount; i++) T_BEGIN {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen doveadm_print(line->username);
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen doveadm_print(line->service);
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen doveadm_print(dec2str(line->pid));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen doveadm_print(net_ip2addr(&line->ip));
e52f55c08f6f1b4fbc5765bf6aa9c7daee0785c3Timo Sirainen } T_END;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainenstatic void cmd_who(int argc, char *argv[])
e52f55c08f6f1b4fbc5765bf6aa9c7daee0785c3Timo Sirainen{
e52f55c08f6f1b4fbc5765bf6aa9c7daee0785c3Timo Sirainen struct who_context ctx;
e52f55c08f6f1b4fbc5765bf6aa9c7daee0785c3Timo Sirainen bool separate_connections = FALSE;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen int c;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen memset(&ctx, 0, sizeof(ctx));
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen ctx.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx.pool = pool_alloconly_create("who users", 10240);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_create(&ctx.users, ctx.pool, 0, who_user_hash, who_user_cmp);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen while ((c = getopt(argc, argv, "1a:")) > 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen switch (c) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case '1':
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen separate_connections = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 'a':
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx.anvil_path = optarg;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen help(&doveadm_cmd_who);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen argv += optind - 1;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen who_parse_args(&ctx, argv);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (!separate_connections) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen who_lookup(&ctx, who_aggregate_line);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen who_print(&ctx);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen doveadm_print_header("username", "username",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen DOVEADM_PRINT_HEADER_FLAG_EXPAND);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen doveadm_print_header("service", "proto", 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen doveadm_print_header_simple("pid");
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen doveadm_print_header_simple("ip");
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen who_lookup(&ctx, who_print_line);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen hash_table_destroy(&ctx.users);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen pool_unref(&ctx.pool);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct doveadm_cmd doveadm_cmd_who = {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen cmd_who, "who",
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen "[-a <anvil socket path>] [-1] [<user mask>] [<ip/bits>]"
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen};
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen