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

Reply via email to