Jorge Bastos wrote:
"166319344" bytes RX, well not possible!!
I assumed that the values would start at 0. I have set them to 0 at the
clientbase_t creation so give that a shot.
-Jon
--
Scanned for viruses and dangerous content by MailScanner
>From 8607234bd8687f98918ee86e304c6939a598920a Mon Sep 17 00:00:00 2001
From: Jonathan Feally <vult...@netvulture.com>
Date: Fri, 12 Jun 2009 17:16:32 -0700
Subject: [PATCH] Add dbmail_authlog table and code to record logins and logouts
---
sql/mysql/2_3_5-2_3_6.mysql | 23 ++++++++
sql/mysql/create_tables.mysql | 24 +++++++++
sql/postgresql/2_3_5-2_3_6.pgsql | 24 +++++++++
sql/postgresql/create_tables.pgsql | 21 ++++++++
sql/sqlite/2_3_5-2_3_6.sqlite | 22 ++++++++
sql/sqlite/create_tables.sqlite | 20 +++++++
src/clientbase.c | 6 ++
src/clientsession.c | 31 ++++++------
src/dbmail-imapsession.c | 9 +++
src/dbmailtypes.h | 3 +
src/pop3.c | 98 +++++++++++++++++++++++-------------
11 files changed, 230 insertions(+), 51 deletions(-)
diff --git a/sql/mysql/2_3_5-2_3_6.mysql b/sql/mysql/2_3_5-2_3_6.mysql
index d7bb886..e66e8a2 100644
--- a/sql/mysql/2_3_5-2_3_6.mysql
+++ b/sql/mysql/2_3_5-2_3_6.mysql
@@ -184,4 +184,27 @@ CREATE TABLE dbmail_filters (
FOREIGN KEY (user_id) REFERENCES dbmail_users(user_idnr) ON DELETE
CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Add new authlog table
+DROP TABLE IF EXISTS dbmail_authlog;
+CREATE TABLE `dbmail_authlog` (
+ `id` bigint(20) NOT NULL auto_increment,
+ `userid` varchar(100) default NULL,
+ `service` varchar(32) default NULL,
+ `login_time` datetime default NULL,
+ `logout_time` datetime default NULL,
+ `ip_address` varchar(16) default NULL,
+ `src_port` int(11) default NULL,
+ `session_id` varchar(32) default NULL,
+ `session_status` varchar(32) default 'active',
+ `bytes_rx` bigint(20) NOT NULL default '0',
+ `bytes_tx` bigint(20) NOT NULL default '0',
+ PRIMARY KEY (`id`),
+ KEY `userid` (`userid`),
+ KEY `ip_address` (`ip_address`),
+ KEY `src_port` (`src_port`),
+ KEY `session_id` (`session_id`),
+ KEY `session_status` (`session_status`)
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
+
SET FOREIGN_KEY_CHECKS=1;
diff --git a/sql/mysql/create_tables.mysql b/sql/mysql/create_tables.mysql
index 129b850..f4b0c7c 100644
--- a/sql/mysql/create_tables.mysql
+++ b/sql/mysql/create_tables.mysql
@@ -28,6 +28,30 @@ SET FOREIGN_KEY_CHECKS=0;
-- Table structure for table `dbmail_acl`
--
+CREATE TABLE `dbmail_authlog` (
+ `id` bigint(20) NOT NULL auto_increment,
+ `userid` varchar(100) default NULL,
+ `service` varchar(32) default NULL,
+ `login_time` datetime default NULL,
+ `logout_time` datetime default NULL,
+ `ip_address` varchar(16) default NULL,
+ `src_port` int(11) default NULL,
+ `session_id` varchar(32) default NULL,
+ `session_status` varchar(32) default 'active',
+ `bytes_rx` bigint(20) NOT NULL default '0',
+ `bytes_tx` bigint(20) NOT NULL default '0',
+ PRIMARY KEY (`id`),
+ KEY `userid` (`userid`),
+ KEY `ip_address` (`ip_address`),
+ KEY `src_port` (`src_port`),
+ KEY `session_id` (`session_id`),
+ KEY `session_status` (`session_status`)
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `dbmail_acl`
+--
+
DROP TABLE IF EXISTS `dbmail_acl`;
CREATE TABLE `dbmail_acl` (
`user_id` bigint(20) NOT NULL default '0',
diff --git a/sql/postgresql/2_3_5-2_3_6.pgsql b/sql/postgresql/2_3_5-2_3_6.pgsql
index 1b1b2c8..e517d59 100644
--- a/sql/postgresql/2_3_5-2_3_6.pgsql
+++ b/sql/postgresql/2_3_5-2_3_6.pgsql
@@ -121,3 +121,27 @@ COMMIT;
BEGIN;
CREATE UNIQUE INDEX message_parts ON dbmail_partlists(physmessage_id,
part_key, part_depth, part_order);
COMMIT;
+
+BEGIN;
+DROP TABLE IF EXISTS dbmail_authlog;
+CREATE SEQUENCE dbmail_authlog_id_seq;
+CREATE TABLE dbmail_authlog (
+ id INT8 DEFAULT nextval('dbmail_authlog_id_seq'),
+ userid VARCHAR(100),
+ service VARCHAR(32),
+ login_time TIMESTAMP WITHOUT TIME ZONE,
+ logout_time TIMESTAMP WITHOUT TIME ZONE,
+ ip_address VARCHAR(16),
+ src_port INT8,
+ session_id VARCHAR(32),
+ session_status VARCHAR(32) DEFAULT 'active',
+ bytes_rx INT8 DEFAULT '0' NOT NULL,
+ bytes_tx INT8 DEFAULT '0' NOT NULL,
+);
+
+CREATE INDEX userid_1 ON dbmail_authlog(userid);
+CREATE INDEX ip_address_1 ON dbmail_authlog(ip_address);
+CREATE INDEX src_port_1 ON dbmail_authlog(src_port);
+CREATE INDEX session_id_1 ON dbmail_authlog (session_id);
+CREATE INDEX session_status_1 ON dbmail_authlog(session_status);
+COMMIT;
diff --git a/sql/postgresql/create_tables.pgsql
b/sql/postgresql/create_tables.pgsql
index 36cd377..ad6ebe4 100644
--- a/sql/postgresql/create_tables.pgsql
+++ b/sql/postgresql/create_tables.pgsql
@@ -32,6 +32,27 @@ CREATE TABLE dbmail_aliases (
CREATE INDEX dbmail_aliases_alias_idx ON dbmail_aliases(alias);
CREATE INDEX dbmail_aliases_alias_low_idx ON dbmail_aliases(lower(alias));
+CREATE SEQUENCE dbmail_authlog_id_seq;
+CREATE TABLE dbmail_authlog (
+ id INT8 DEFAULT nextval('dbmail_authlog_id_seq'),
+ userid VARCHAR(100),
+ service VARCHAR(32),
+ login_time TIMESTAMP WITHOUT TIME ZONE,
+ logout_time TIMESTAMP WITHOUT TIME ZONE,
+ ip_address VARCHAR(16),
+ src_port INT8,
+ session_id VARCHAR(32),
+ session_status VARCHAR(32) DEFAULT 'active',
+ bytes_rx INT8 DEFAULT '0' NOT NULL,
+ bytes_tx INT8 DEFAULT '0' NOT NULL,
+);
+
+CREATE INDEX userid_1 ON dbmail_authlog(userid);
+CREATE INDEX ip_address_1 ON dbmail_authlog(ip_address);
+CREATE INDEX src_port_1 ON dbmail_authlog(src_port);
+CREATE INDEX session_id_1 ON dbmail_authlog (session_id);
+CREATE INDEX session_status_1 ON dbmail_authlog(session_status);
+
CREATE SEQUENCE dbmail_user_idnr_seq;
CREATE TABLE dbmail_users (
user_idnr INT8 DEFAULT nextval('dbmail_user_idnr_seq'),
diff --git a/sql/sqlite/2_3_5-2_3_6.sqlite b/sql/sqlite/2_3_5-2_3_6.sqlite
index 594e88d..d874d44 100644
--- a/sql/sqlite/2_3_5-2_3_6.sqlite
+++ b/sql/sqlite/2_3_5-2_3_6.sqlite
@@ -296,3 +296,25 @@ BEGIN TRANSACTION;
CREATE UNIQUE INDEX message_parts ON dbmail_partlists(physmessage_id,
part_key, part_depth, part_order);
COMMIT;
+BEGIN TRANSACTION;
+DROP TABLE IF EXISTS dbmail_authlog;
+CREATE TABLE dbmail_authlog (
+ id INTEGER PRIMARY KEY,
+ userid TEXT,
+ service TEXT,
+ login_time DATETIME,
+ logout_time DATETIME,
+ ip_address TEXT,
+ src_port INTEGER,
+ session_id TEXT,
+ session_status TEXT DEFAULT 'active',
+ bytes_rx INTEGER DEFAULT '0' NOT NULL,
+ bytes_tx INTEGER DEFAULT '0' NOT NULL,
+);
+
+CREATE INDEX userid_1 ON dbmail_authlog(userid);
+CREATE INDEX ip_address_1 ON dbmail_authlog(ip_address);
+CREATE INDEX src_port_1 ON dbmail_authlog(src_port);
+CREATE INDEX session_id_1 ON dbmail_authlog (session_id);
+CREATE INDEX session_status_1 ON dbmail_authlog(session_status);
+COMMIT;
diff --git a/sql/sqlite/create_tables.sqlite b/sql/sqlite/create_tables.sqlite
index e8c9153..cba50be 100644
--- a/sql/sqlite/create_tables.sqlite
+++ b/sql/sqlite/create_tables.sqlite
@@ -30,6 +30,26 @@ CREATE TABLE dbmail_aliases (
CREATE INDEX dbmail_aliases_index_1 ON dbmail_aliases(alias);
CREATE INDEX dbmail_aliases_index_2 ON dbmail_aliases(client_idnr);
+CREATE TABLE dbmail_authlog (
+ id INTEGER PRIMARY KEY,
+ userid TEXT,
+ service TEXT,
+ login_time DATETIME,
+ logout_time DATETIME,
+ ip_address TEXT,
+ src_port INTEGER,
+ session_id TEXT,
+ session_status TEXT DEFAULT 'active',
+ bytes_rx INTEGER DEFAULT '0' NOT NULL,
+ bytes_tx INTEGER DEFAULT '0' NOT NULL,
+);
+
+CREATE INDEX userid_1 ON dbmail_authlog(userid);
+CREATE INDEX ip_address_1 ON dbmail_authlog(ip_address);
+CREATE INDEX src_port_1 ON dbmail_authlog(src_port);
+CREATE INDEX session_id_1 ON dbmail_authlog (session_id);
+CREATE INDEX session_status_1 ON dbmail_authlog(session_status);
+
CREATE TABLE dbmail_users (
user_idnr INTEGER PRIMARY KEY,
userid TEXT NOT NULL,
diff --git a/src/clientbase.c b/src/clientbase.c
index 372d337..1b62556 100644
--- a/src/clientbase.c
+++ b/src/clientbase.c
@@ -139,6 +139,10 @@ clientbase_t * client_init(int socket, struct sockaddr_in
*caddr, SSL *ssl)
client->queue = g_async_queue_new();
client->cb_error = client_error_cb;
+ /* set byte counters to 0 */
+ client->bytes_rx = 0;
+ client->bytes_tx = 0;
+
/* make streams */
if (socket == 0 && caddr == NULL) {
client->rx = STDIN_FILENO;
@@ -270,6 +274,7 @@ int ci_write(clientbase_t *self, char * msg, ...)
if ((e = self->cb_error(self->tx, e, (void *)self)))
return e;
} else {
+ self->bytes_tx += t; // Update our byte counter
if (self->ssl) {
memset(self->tls_wbuf, '\0', TLS_SEGMENT);
self->tls_wbuf_n = 0;
@@ -325,6 +330,7 @@ void ci_read_cb(clientbase_t *self)
break;
} else {
+ self->bytes_rx += t; // Update our byte counter
self->client_state = CLIENT_OK;
g_string_append_len(self->read_buffer, ibuf, t);
TRACE(TRACE_DEBUG,"read [%u:%s]", t, ibuf);
diff --git a/src/clientsession.c b/src/clientsession.c
index 948c53a..839fea7 100644
--- a/src/clientsession.c
+++ b/src/clientsession.c
@@ -107,6 +107,9 @@ void client_session_bailout(ClientSession_t **session)
if (! c) return;
TRACE(TRACE_DEBUG,"[%p]", c);
+ // Run registered cleanup function call
+ if(c->session_cleanup) c->session_cleanup(c);
+
// brute force:
if (server_conf->no_daemonize == 1) _exit(0);
@@ -118,25 +121,23 @@ void client_session_bailout(ClientSession_t **session)
void client_session_read(void *arg)
{
+ int state;
ClientSession_t *session = (ClientSession_t *)arg;
TRACE(TRACE_DEBUG, "[%p] state: [%d]", session, session->state);
ci_read_cb(session->ci);
- switch(session->ci->client_state) {
- case CLIENT_OK:
- case CLIENT_AGAIN:
- session->handle_input(session);
- break;
-
- default:
- case CLIENT_ERR:
+
+ state = session->ci->client_state;
+ if (state & CLIENT_ERR) {
+ TRACE(TRACE_DEBUG,"client_state ERROR");
+ client_session_bailout(&session);
+ } else if (state & CLIENT_EOF) {
+ TRACE(TRACE_NOTICE,"reached EOF");
+ event_del(session->ci->rev);
+ if (session->ci->read_buffer->len < 1)
client_session_bailout(&session);
- break;
- case CLIENT_EOF:
- TRACE(TRACE_NOTICE,"reached EOF");
- event_del(session->ci->rev);
- if (session->ci->read_buffer->len < 1)
- client_session_bailout(&session);
- break;
+ }
+ else if (state & CLIENT_OK || state & CLIENT_AGAIN) {
+ session->handle_input(session);
}
}
diff --git a/src/dbmail-imapsession.c b/src/dbmail-imapsession.c
index e6e0f2f..045e02c 100644
--- a/src/dbmail-imapsession.c
+++ b/src/dbmail-imapsession.c
@@ -163,6 +163,9 @@ void dbmail_imap_session_delete(ImapSession * self)
TRACE(TRACE_DEBUG,"[%p]", self);
Cache_free(&self->cache);
+ db_update("UPDATE %sauthlog SET logout_time=NOW(),
session_status='closed', bytes_rx='%d', bytes_tx='%d' WHERE ip_address='%s' AND
src_port='%d' AND session_status='active' AND session_id='%p'",
+ DBPFX, (int *)self->ci->bytes_rx, (int *)self->ci->bytes_tx,
(char *)self->ci->ip_src, (int *)self->ci->ip_src_port, self);
+
if (self->fi) {
dbmail_imap_session_bodyfetch_free(self);
g_free(self->fi);
@@ -1192,12 +1195,18 @@ int dbmail_imap_session_handle_auth(ImapSession * self,
char * username, char *
case 0:
sleep(2); /* security */
+ db_update("INSERT INTO %sauthlog (userid, service,
login_time, logout_time, ip_address, src_port, session_id, session_status)"
+ " VALUES ('%s', 'imap', NOW(), NOW(), '%s',
'%d', '%p', 'auth_failed')",
+ DBPFX, (char *)username, (char
*)self->ci->ip_src, (int *)self->ci->ip_src_port, self);
dbmail_imap_session_buff_printf(self, "%s NO login
rejected\r\n", self->tag);
TRACE(TRACE_NOTICE, "[%p] login rejected: user [%s]
from [%s:%d]", self, username, self->ci->ip_src, self->ci->ip_src_port);
return 1;
case 1:
self->userid = userid;
+ db_update("INSERT INTO %sauthlog (userid, service,
login_time, ip_address, src_port, session_id)"
+ " VALUES ('%s', 'imap', NOW(), '%s', '%d',
'%p')",
+ DBPFX, (char *)username, (char
*)self->ci->ip_src, (int *)self->ci->ip_src_port, self);
TRACE(TRACE_NOTICE, "[%p] login accepted: user [%s]
from [%s:%d]", self, username, self->ci->ip_src, self->ci->ip_src_port);
break;
diff --git a/src/dbmailtypes.h b/src/dbmailtypes.h
index 670aec9..d487989 100644
--- a/src/dbmailtypes.h
+++ b/src/dbmailtypes.h
@@ -313,6 +313,8 @@ typedef struct {
typedef struct {
int rx, tx; /* read and write filehandles */
+ u64_t bytes_rx; /* read byte counter */
+ u64_t bytes_tx; /* write byte counter */
SSL *ssl; /* SSL/TLS context for this client */
gboolean ssl_state; /* SSL_accept done or not */
int client_state; /* CLIENT_OK, CLIENT_AGAIN, CLIENT_EOF
*/
@@ -350,6 +352,7 @@ typedef struct {
clientbase_t *ci;
clientstate_t state; /**< session state */
void (*handle_input) (void *);
+ void (*session_cleanup) (void *); /* session cleanup */
int error_count; /**< number of errors that have occured
*/
int was_apop; /**< 1 if session was session was apop
(no plaintext password) */
diff --git a/src/pop3.c b/src/pop3.c
index d32799f..3a28013 100644
--- a/src/pop3.c
+++ b/src/pop3.c
@@ -167,49 +167,21 @@ static void db_session_cleanup(ClientSession_t *
session_ptr)
g_list_destroy(session_ptr->messagelst);
}
-
static void pop3_close(ClientSession_t *session)
{
clientbase_t *ci = session->ci;
- TRACE(TRACE_DEBUG,"[%p] sessionResult [%d]", session,
session->SessionResult);
-
- if (session->username != NULL && (session->was_apop ||
session->password != NULL)) {
-
- switch (session->SessionResult) {
- case 0:
- TRACE(TRACE_NOTICE, "user %s logging out
[messages=%llu, octets=%llu]",
- session->username,
- session->virtual_totalmessages,
- session->virtual_totalsize);
-
- /* if everything went well, write down everything and
do a cleanup */
- if (db_update_pop(session) == DM_SUCCESS)
- ci_write(ci, "+OK see ya later\r\n");
- else
- ci_write(ci, "-ERR some deleted messages not
removed\r\n");
- break;
-
+ switch (pop3_session_cleanup(session)) {
case 1:
- ci_write(ci, "-ERR I'm leaving, you're too slow\r\n");
- TRACE(TRACE_ERR, "client timed out, connection closed");
- break;
-
- case 2:
- TRACE(TRACE_ERR, "alert! possible flood attempt,
closing connection");
+ ci_write(ci, "+OK see ya later\r\n");
break;
-
- case 3:
- TRACE(TRACE_ERR, "authorization layer failure");
+ case -1:
+ ci_write(ci, "-ERR I'm leaving, you're too slow\r\n");
break;
- case 4:
- TRACE(TRACE_ERR, "storage layer failure");
+ case 0:
+ default:
+ ci_write(ci, "-ERR some deleted messages not
removed\r\n");
break;
- }
- } else {
- ci_write(ci, "+OK see ya later\r\n");
}
-
- session->state = CLIENTSTATE_QUIT;
}
@@ -220,6 +192,8 @@ static void pop3_handle_input(void *arg)
char buffer[MAX_LINESIZE]; /* connection buffer */
ClientSession_t *session = (ClientSession_t *)arg;
+ TRACE(TRACE_DEBUG,"handling [%p]",arg);
+
if (session->ci->write_buffer->len) {
ci_write(session->ci, NULL);
return;
@@ -256,11 +230,58 @@ void pop3_cb_time(void * arg)
ci_write(session->ci, "-ERR I'm leaving, you're too slow\r\n");
}
+int pop3_session_cleanup(void * arg)
+{
+ ClientSession_t *session = (ClientSession_t *)arg;
+ int r = 0;
+
+ TRACE(TRACE_DEBUG,"[%p] sessionResult [%d]", session,
session->SessionResult);
+
+ if (session->username != NULL && (session->was_apop ||
session->password != NULL)) {
+ TRACE(TRACE_NOTICE, "user %s logging out [messages=%llu,
octets=%llu]",
+ session->username,
+ session->virtual_totalmessages,
+ session->virtual_totalsize);
+
+ db_update("UPDATE %sauthlog SET logout_time=NOW(),
session_status='closed', bytes_rx='%d', bytes_tx='%d' WHERE ip_address='%s' AND
src_port='%d' AND session_status='active' AND session_id='%p'",
+ DBPFX, (int *)session->ci->bytes_rx, (int
*)session->ci->bytes_tx, (char *)session->ci->ip_src, (int
*)session->ci->ip_src_port, session);
+
+ switch (session->SessionResult) {
+ case 0:
+ /* if everything went well, write down everything and
do a cleanup */
+ if (db_update_pop(session) == DM_SUCCESS) r = 1;
+ break;
+
+ case 1:
+ r = -1;
+ TRACE(TRACE_ERR, "client timed out, connection closed");
+ break;
+
+ case 2:
+ TRACE(TRACE_ERR, "alert! possible flood attempt,
closing connection");
+ break;
+
+ case 3:
+ TRACE(TRACE_ERR, "authorization layer failure");
+ break;
+ case 4:
+ TRACE(TRACE_ERR, "storage layer failure");
+ break;
+ }
+ } else {
+ r = 1;
+ }
+
+ session->state = CLIENTSTATE_QUIT;
+ return r;
+}
+
static void reset_callbacks(ClientSession_t *session)
{
session->ci->cb_time = pop3_cb_time;
session->ci->cb_write = pop3_cb_write;
session->handle_input = pop3_handle_input;
+ session->session_cleanup = pop3_session_cleanup;
UNBLOCK(session->ci->rx);
UNBLOCK(session->ci->tx);
@@ -440,6 +461,9 @@ int pop3(ClientSession_t *session, const char *buffer)
session->SessionResult = 3;
return -1;
case 0:
+ db_update("INSERT INTO %sauthlog (userid, service,
login_time, logout_time, ip_address, src_port, session_id, session_status)"
+ " VALUES ('%s', 'pop', NOW(), NOW(), '%s',
'%d', '%p', 'auth_failed')",
+ DBPFX, (char *)session->username, (char
*)ci->ip_src, (int *)ci->ip_src_port, session);
TRACE(TRACE_ERR, "user [%s] coming from [%s] tried to
login with wrong password",
session->username, ci->ip_src);
@@ -454,7 +478,9 @@ int pop3(ClientSession_t *session, const char *buffer)
default:
/* user logged in OK */
session->state = CLIENTSTATE_AUTHENTICATED;
-
+ db_update("INSERT INTO %sauthlog (userid, service,
login_time, ip_address, src_port, session_id)"
+ " VALUES ('%s', 'pop', NOW(), '%s', '%d',
'%p')",
+ DBPFX, (char *)session->username, (char
*)ci->ip_src, (int *)ci->ip_src_port, session);
client_session_set_timeout(session,
server_conf->timeout);
/* now we're going to build up a session for this user
*/
--
1.6.1.3
_______________________________________________
Dbmail-dev mailing list
Dbmail-dev@dbmail.org
http://mailman.fastxs.nl/cgi-bin/mailman/listinfo/dbmail-dev