added new auth-check security feature
authorpk910 <philipp@zoelle1.de>
Tue, 17 Jan 2012 16:19:20 +0000 (17:19 +0100)
committerpk910 <philipp@zoelle1.de>
Tue, 17 Jan 2012 18:32:56 +0000 (19:32 +0100)
14 files changed:
database.sql
database.upgrade.sql
neonserv.example.conf
src/ClientSocket.c
src/ClientSocket.h
src/DBHelper.c
src/DBHelper.h
src/HandleInfoHandler.c
src/HandleInfoHandler.h
src/WHOHandler.c
src/WHOHandler.h
src/cmd_global_unregister.c
src/main.c
src/mysqlConn.c

index 2047290e00d50e71b17c93a5d5722052ac532916..fbc3b4048e04d1fab31e215290b7368216303be2 100644 (file)
@@ -317,6 +317,8 @@ CREATE TABLE IF NOT EXISTS `users` (
   `user_god` tinyint(1) NOT NULL,
   `user_lang` varchar(6) NOT NULL,
   `user_reply_privmsg` tinyint(1) NOT NULL,
+  `user_registered` INT(20) NOT NULL,
+  `user_lastcheck` INT(20) NOT NULL,
   PRIMARY KEY (`user_id`),
   UNIQUE KEY `user_user` (`user_user`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=latin1;
index 4f4697dccf9da46b841813e021034bb701aa7eda..cad2b7310784cf5c478b4dc8c9753335534606ef 100644 (file)
@@ -134,3 +134,9 @@ UPDATE `channels` SET `channel_canhalfop` = '150',
 `channel_gethalfop` = '150' WHERE `channel_name` = 'defaults';
 
 -- version: 14
+
+ALTER TABLE `users` ADD `user_registered` INT( 20 ) NOT NULL ,
+ADD `user_lastcheck` INT( 20 ) NOT NULL;
+
+-- version: 15
+
index b0321641012c8b992ecf5a1f001d5caf921c4e0b..a6b3a6101ee841907f54ee84a07d04323ed1754f 100644 (file)
@@ -3,7 +3,7 @@
 */
 
 "MySQL" {
-    "host" = "127.0.0.1 ";
+    "host" = "127.0.0.1";
     "port" = 3306;
     "user" = "neonserv";
     "pass" = "password";
 "General" {
     "alertchan" = "";
     "have_halfop" = 0;
+    "CheckAuths" {
+        "enabled" = 1;
+        "start_time" = 3; //24h format
+        "duration" = 180; //minutes
+        "interval" = 2; //seconds
+        "min_unckecked" = 172800; //check auth only if unchecked for x seconds
+        //180 miutes, every 2 seconds: 5400 auth checks
+        "alertchan" = "#krypton.intern";
+    };
 };
 "QServer" {
     "enabled" = 1;
index 80f4c37d2cae7f73fa4cdd4b996858bfa528d551..c49577724393e3de6b1443841072ff8e1ed46105 100644 (file)
@@ -33,6 +33,12 @@ struct socket_list {
 #ifdef HAVE_THREADS
 static pthread_mutex_t synchronized;
 static pthread_mutex_t synchronized_recv;
+
+struct ParseOrder {
+    unsigned long tid;
+    struct ParseOrder *next;
+};
+struct ParseOrder *parse_order = NULL;
 #endif
 
 //the magic list :P
@@ -369,6 +375,49 @@ int write_socket(struct ClientSocket *client, char* msg, int len) {
         return write_socket_force(client, msg, len);
 }
 
+#if HAVE_THREADS
+static void clientsocket_start_of_recv(unsigned long tid) {
+    SYNCHRONIZE(whohandler_sync);
+    struct ParseOrder *entry, *last;
+    for(last = parse_order; last; last = last->next) {
+        if(last->next == NULL)
+            break;
+    }
+    entry = malloc(sizeof(*entry));
+    entry->tid = tid;
+    entry->next = NULL;
+    if(last)
+        last->next = entry;
+    else
+        parse_order = entry;
+    DESYNCHRONIZE(whohandler_sync);
+}
+
+static void clientsocket_end_of_recv(unsigned long tid) {
+    SYNCHRONIZE(whohandler_sync);
+    struct ParseOrder *entry, *last = NULL;
+    for(entry = parse_order; entry; entry = entry->next) {
+        if(entry->tid == tid) {
+            if(last)
+                last->next = entry->next;
+            else
+                parse_order = entry->next;
+            free(entry);
+            break;
+        } else
+            last = entry;
+    }
+    DESYNCHRONIZE(whohandler_sync);
+}
+
+int clientsocket_parseorder_top(unsigned long tid) {
+    if(parse_order && parse_order->tid == tid)
+        return 1;
+    else
+        return 0;
+}
+#endif
+
 void socket_loop(int timeout_seconds) {
     if(sockets == NULL) return;
     int is_synchronized = 1;
@@ -446,10 +495,10 @@ void socket_loop(int timeout_seconds) {
                 }
                 is_synchronized = 0;
                 unsigned long tid = syscall(SYS_gettid);
-                whohandler_start_of_recv(sock, tid);
+                clientsocket_start_of_recv(tid);
                 DESYNCHRONIZE(synchronized_recv);
                 parse_lines(sock, linesbuf, used);
-                whohandler_end_of_recv(sock, tid); //WHOHandler hack (unlock WHOQueue mutexes)
+                clientsocket_end_of_recv(tid);
                 #else
                 int used = parse_lines(sock, sock->buffer, sock->bufferpos);
                 if(used == sock->bufferpos + 1) {
index 4073a23b38570778980337c5c1e575d0b6466bc9..1ab71397d2ec182564a619c63004cdb1f59fc578 100644 (file)
@@ -83,6 +83,9 @@ int close_socket(struct ClientSocket *client);
 int disconnect_socket(struct ClientSocket *client);
 int write_socket_force(struct ClientSocket *client, char* msg, int len);
 int write_socket(struct ClientSocket *client, char* msg, int len);
+#ifdef HAVE_THREADS
+int clientsocket_parseorder_top(unsigned long tid);
+#endif
 void socket_loop(int timeout_seconds);
 void putsock(struct ClientSocket *client, const char *text, ...) PRINTF_LIKE(2, 3);
 struct ClientSocket* getBots(int flags, struct ClientSocket* last_bot);
index 4f3dd757262d0150e93a3966731b163d6712ee92..980ee7ae80c651b4484026f2136e6f3a05eef093 100644 (file)
@@ -24,6 +24,7 @@
 #include "tools.h"
 #include "IRCEvents.h"
 #include "HandleInfoHandler.h"
+#include "ClientSocket.h"
 
 void _loadUserSettings(struct UserNode *user) {
     SYNCHRONIZE(cache_sync);
@@ -301,6 +302,45 @@ static AUTHLOOKUP_CALLBACK(event_user_registered_auth_lookup) {
     free(cache->oldauth);
 }
 
+void deleteUser(int userid) {
+    //simply delete the user
+    MYSQL_RES *res, *res2;
+    MYSQL_ROW row, row2;
+    printf_mysql_query("SELECT a.`chanuser_access`, a.`chanuser_cid`, (SELECT COUNT(*) FROM `chanusers` AS b WHERE b.`chanuser_cid` = a.`chanuser_cid` AND b.`chanuser_access` = 500) FROM `chanusers` AS a WHERE a.`chanuser_uid` = '%d'", userid);
+    res = mysql_use();
+    while((row = mysql_fetch_row(res))) {
+        if(!strcmp(row[0], "500") && !strcmp(row[2], "1")) {
+            //unregister channel
+            printf_mysql_query("SELECT `botid`, `channel_name` FROM `bot_channels` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `chanid` = '%s' AND `suspended` = '0'", row[1]);
+            res2 = mysql_use();
+            while((row2 = mysql_fetch_row(res))) {
+                struct ClientSocket *bot;
+                int clientid = atoi(row2[0]);
+                for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+                    if(bot->clientid == clientid)
+                        putsock(bot, "PART %s :Channel unregistered.", row2[1]);
+                }
+            }
+            printf_mysql_query("DELETE FROM `bot_channels` WHERE `chanid` = '%s'", row[1]);
+        }
+    }
+    printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_uid` = '%d'", userid);
+    printf_mysql_query("UPDATE `bans` SET `ban_owner` = 0 WHERE `ban_owner` = '%d'", userid);
+    printf_mysql_query("UPDATE `donotregister` SET `dnr_user` = 0 WHERE `dnr_user` = '%d'", userid);
+    printf_mysql_query("UPDATE `bans` SET `ban_owner` = 0 WHERE `ban_owner` = '%d'", userid);
+    printf_mysql_query("UPDATE `godlog` SET `godlog_uid` = 0 WHERE `godlog_uid` = '%d'", userid);
+    printf_mysql_query("DELETE FROM `noinvite` WHERE `uid` = '%d'", userid);
+    printf_mysql_query("UPDATE `owner_history` SET `owner_history_to_uid` = 0 WHERE `owner_history_to_uid` = '%d'", userid);
+    printf_mysql_query("UPDATE `owner_history` SET `owner_history_from_uid` = 0 WHERE `owner_history_from_uid` = '%d'", userid);
+    printf_mysql_query("UPDATE `channels` SET `channel_registrator` = 0 WHERE `channel_registrator` = '%d'", userid);
+    printf_mysql_query("DELETE FROM `users` WHERE `user_id` = '%d'", userid);
+    struct UserNode *user;
+    for(user = getAllUsers(NULL); user; user = getAllUsers(user)) {
+        if(user->flags & USERFLAG_HAS_USERID)
+            user->flags &= ~USERFLAG_HAS_USERID;
+    }
+}
+
 void init_DBHelper() {
     bind_registered(event_user_registered);
 }
index caa45bb1b16cea401a5b94de7e997a5aac8fdcd2..01658f4cf5f1b70fa9359d598e2478bdf634cf63 100644 (file)
@@ -39,5 +39,7 @@ char *getBanAffectingMask(struct ChanNode *chan, char *mask); //returns bans tha
 
 int renameAccount(char *oldauth, char *newauth);
 
+void deleteUser(int userid);
+
 void init_DBHelper();
 #endif
\ No newline at end of file
index 99d19658b73c33d6b24abb729988eecbc44cc746..0508e07413448c82c7dc22f2661b364d333db646 100644 (file)
@@ -121,6 +121,8 @@ static void recv_notice(struct UserNode *user, struct UserNode *target, char *me
     char *auth = NULL;
     int do_match = 0, exists = 0;
     char *tmp;
+    time_t registered = time(0);
+    struct tm *timeinfo;
     //messages to parse:
     //  Account * has not been registered.
     //  Account information for Skynet:
@@ -130,24 +132,99 @@ static void recv_notice(struct UserNode *user, struct UserNode *target, char *me
         auth = tmp+1;
         tmp = strstr(auth, "\002");
         *tmp = '\0';
-    }
-    if(!match("Account information for *", message)) {
-        do_match = 1;
+    } else if(!match("Account information for *", message)) {
+        do_match = 2;
         exists = 1;
         tmp = strstr(message, "\002");
         auth = tmp+1;
         tmp = strstr(auth, "\002");
         *tmp = '\0';
+    } else if(!match("  Registered on: *", message)) {
+        do_match = 1;
+        exists = 1;
+        tmp = strstr(message, ": ");
+        tmp += 2;
+        timeinfo = localtime(&registered);
+        timeinfo->tm_year = 0;
+        //parse time
+        //Sat Nov 19 14:52:57 2011
+        tmp = strchr(tmp, ' ');
+        if(!tmp) goto errparse;
+        tmp++;
+        char *tmp2 = strchr(tmp, ' ');
+        if(!tmp2) goto errparse;
+        *tmp2 = '\0';
+        if(!stricmp(tmp, "Jan"))
+            timeinfo->tm_mon = 0;
+        else if(!stricmp(tmp, "Feb"))
+            timeinfo->tm_mon = 1;
+        else if(!stricmp(tmp, "Mar"))
+            timeinfo->tm_mon = 2;
+        else if(!stricmp(tmp, "Apr"))
+            timeinfo->tm_mon = 3;
+        else if(!stricmp(tmp, "May"))
+            timeinfo->tm_mon = 4;
+        else if(!stricmp(tmp, "Jun"))
+            timeinfo->tm_mon = 5;
+        else if(!stricmp(tmp, "Jul"))
+            timeinfo->tm_mon = 6;
+        else if(!stricmp(tmp, "Aug"))
+            timeinfo->tm_mon = 7;
+        else if(!stricmp(tmp, "Sep"))
+            timeinfo->tm_mon = 8;
+        else if(!stricmp(tmp, "Oct"))
+            timeinfo->tm_mon = 9;
+        else if(!stricmp(tmp, "Nov"))
+            timeinfo->tm_mon = 10;
+        else if(!stricmp(tmp, "Dec"))
+            timeinfo->tm_mon = 11;
+        tmp = tmp2 + 1;
+        tmp2 = strchr(tmp, ' ');
+        if(!tmp2) goto errparse;
+        *tmp2 = '\0';
+        timeinfo->tm_mday = atoi(tmp);
+        tmp = tmp2 + 1;
+        if(*tmp == ' ') tmp++;
+        tmp2 = strchr(tmp, ':');
+        if(!tmp2) goto errparse;
+        *tmp2 = '\0';
+        timeinfo->tm_hour = atoi(tmp);
+        tmp = tmp2 + 1;
+        tmp2 = strchr(tmp, ':');
+        if(!tmp2) goto errparse;
+        *tmp2 = '\0';
+        timeinfo->tm_min = atoi(tmp);
+        tmp = tmp2 + 1;
+        tmp2 = strchr(tmp, ' ');
+        if(!tmp2) goto errparse;
+        *tmp2 = '\0';
+        timeinfo->tm_sec = atoi(tmp);
+        tmp = tmp2 + 1;
+        timeinfo->tm_year = atoi(tmp) - 1900;
+        registered = mktime(timeinfo);
     }
+    errparse:
+    
     if(do_match) {
-        struct HandleInfoQueueEntry* entry = getNextHandleInfoQueueEntry(bot, 1);
+        #ifdef HAVE_THREADS
+        unsigned long tid = syscall(SYS_gettid);
+        while(!clientsocket_parseorder_top(tid)) {
+            usleep(1000); //1ms
+        }
+        #endif
+        struct HandleInfoQueueEntry* entry = getNextHandleInfoQueueEntry(bot, ((do_match != 2) ? 1 : 0));
         if(entry) {
+            if(do_match == 2) {
+                free(entry->auth);
+                entry->auth = strdup(auth);
+                return;
+            }
             authlookup_callback_t *callback;
             int i;
             for(i = 0; i < MAXCALLBACKS; i++) {
                 callback = entry->callback[i];
                 if(!callback) break;
-                callback(auth, exists, entry->data[i]);
+                callback(entry->auth, exists, registered, entry->data[i]);
             }
             free(entry->auth);
             free(entry);
index c49cfacaa6083b21d718f595678558e270c890d3..d5bb9bdf2d806188d134bbfe4913d71583a78a53 100644 (file)
@@ -22,7 +22,7 @@
 struct ClientSocket;
 struct UserNode;
 
-#define AUTHLOOKUP_CALLBACK(NAME) void NAME(UNUSED_ARG(char *auth), UNUSED_ARG(int exists), UNUSED_ARG(void *data))
+#define AUTHLOOKUP_CALLBACK(NAME) void NAME(UNUSED_ARG(char *auth), UNUSED_ARG(int exists), UNUSED_ARG(time_t registered), UNUSED_ARG(void *data))
 typedef AUTHLOOKUP_CALLBACK(authlookup_callback_t);
 
 void clear_handleinfoqueue(struct ClientSocket *client);
index 076afd3c0ed1655a9fb2870ad95c7e5c9a776e5d..f8769decabbce38aa79444156a7b1006b3450e83 100644 (file)
@@ -41,14 +41,6 @@ struct WHOQueueEntry {
     void *data[MAXCALLBACKS];
 };
 
-#ifdef HAVE_THREADS
-struct ParseOrder {
-    unsigned long tid;
-    struct ParseOrder *next;
-};
-struct ParseOrder *parse_order = NULL;
-#endif
-
 static int checkWHOID(struct ClientSocket *client, int whoid) {
     struct WHOQueueEntry *entry;
     for(entry = client->whoqueue_first; entry; entry = entry->next) {
@@ -122,42 +114,6 @@ void clear_whoqueue(struct ClientSocket *client) {
     DESYNCHRONIZE(whohandler_sync);
 }
 
-#if HAVE_THREADS
-void whohandler_start_of_recv(struct ClientSocket *client, unsigned long tid) {
-    SYNCHRONIZE(whohandler_sync);
-    struct ParseOrder *entry, *last;
-    for(last = parse_order; last; last = last->next) {
-        if(last->next == NULL)
-            break;
-    }
-    entry = malloc(sizeof(*entry));
-    entry->tid = tid;
-    entry->next = NULL;
-    if(last)
-        last->next = entry;
-    else
-        parse_order = entry;
-    DESYNCHRONIZE(whohandler_sync);
-}
-
-void whohandler_end_of_recv(struct ClientSocket *client, unsigned long tid) {
-    SYNCHRONIZE(whohandler_sync);
-    struct ParseOrder *entry, *last = NULL;
-    for(entry = parse_order; entry; entry = entry->next) {
-        if(entry->tid == tid) {
-            if(last)
-                last->next = entry->next;
-            else
-                parse_order = entry->next;
-            free(entry);
-            break;
-        } else
-            last = entry;
-    }
-    DESYNCHRONIZE(whohandler_sync);
-}
-#endif
-
 void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data) {
     struct ClientSocket *bot;
     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
@@ -287,8 +243,8 @@ static void _recv_whohandler_354(struct ClientSocket *client, char **argv, unsig
     if(entry == NULL) return;
     #ifdef HAVE_THREADS
     unsigned long tid = syscall(SYS_gettid);
-    while(parse_order->tid != tid) {
-        usleep(5000); //5ms
+    while(!clientsocket_parseorder_top(tid)) {
+        usleep(1000); //1ms
     }
     #endif
     if(entry->type & WHOQUEUETYPE_USERLIST) {
@@ -383,8 +339,8 @@ static void _recv_whohandler_315(struct ClientSocket *client, char **argv, unsig
     if(entry == NULL) return;
     #ifdef HAVE_THREADS
     unsigned long tid = syscall(SYS_gettid);
-    while(parse_order->tid != tid) {
-        usleep(5000); //5ms
+    while(!clientsocket_parseorder_top(tid)) {
+        usleep(1000); //1ms
     }
     #endif
     getNextWHOQueueEntry(client, type, 1);
index d4028787991cc0a83a4789a010ce2845ee3116de..68ad205646b940f0bcc6063c58211129e0c7abc6 100644 (file)
@@ -30,10 +30,6 @@ typedef USERLIST_CALLBACK(userlist_callback_t);
 typedef USERAUTH_CALLBACK(userauth_callback_t);
 
 void clear_whoqueue(struct ClientSocket *client);
-#if HAVE_THREADS
-void whohandler_start_of_recv(struct ClientSocket *client, unsigned long tid);
-void whohandler_end_of_recv(struct ClientSocket *client, unsigned long tid);
-#endif
 void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc);
 void recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc);
 void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data);
index 058f38b142f224527ad31a2976e06d0362fe74b3..43dab20796f171615c61b67c487001eb0d539b22 100644 (file)
@@ -42,19 +42,18 @@ CMD_BIND(global_cmd_unregister) {
         return;
     }
     if(client->botid == 0)
-        printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended`, `bots`.`id` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '0' AND `botid` = '%d'", chanid, client->clientid);
+        printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '0' AND `botid` = '%d'", chanid, client->clientid);
     else
-        printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended`, `bots`.`id` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
+        printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
     res = mysql_use();
     if ((row = mysql_fetch_row(res)) == NULL) {
         reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
         return;
     }
     int botid = atoi(row[0]);
-    int clientid = atoi(row[3]);
     struct ClientSocket *bot;
     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->clientid == botid && (!botid || bot->clientid == clientid))
+        if(bot->clientid == botid)
             break;
     }
     if(bot && strcmp(row[2], "1")) {
index e8d366aa0d7141696c51b302cc900f2b961fa3c2..17980b445762e5b2b9634d94bc2c4f2d93e98c98 100644 (file)
@@ -43,6 +43,7 @@ static int running, hard_restart;
 static int statistics_requested_lusers = 0;
 int statistics_enabled;
 TIMEQ_CALLBACK(main_statistics);
+TIMEQ_CALLBACK(main_checkauths);
 #ifdef HAVE_THREADS
 int running_threads;
 pthread_mutex_t cache_sync;
@@ -165,6 +166,8 @@ main:
     if(!update_minutes) update_minutes = 2;
     timeq_add(update_minutes * 60 + 10, main_statistics, NULL);
     
+    timeq_add(90, main_checkauths, NULL);
+    
     int worker_threads = get_int_field("General.worker_threads");
     if(!worker_threads) worker_threads = 1;
     
@@ -262,6 +265,82 @@ void reload_config() {
     loadConfig("neonserv.conf");
 }
 
+static int getCurrentSecondsOfDay() {
+    time_t now = time(0);
+    struct tm *timeofday = localtime(&now);
+    int seconds = 0;
+    seconds += timeofday->tm_hour * 3600;
+    seconds += timeofday->tm_min * 60;
+    seconds += timeofday->tm_sec;
+    return seconds;
+}
+
+static AUTHLOOKUP_CALLBACK(main_checkauths_callback) {
+    //check if registered is still valid
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `user_id`, `user_registered` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        if(!exists || (strcmp(row[1], "0") && registered != atoi(row[1]))) {
+            //User is no longer valid! Delete it...
+            deleteUser(atoi(row[0]));
+            char *alertchan = get_string_field("General.CheckAuths.alertchan");
+            if(alertchan) {
+                struct ChanNode *alertchan_chan = getChanByName(alertchan);
+                struct ClientSocket *alertclient;
+                if(alertchan_chan && (alertclient = getChannelBot(alertchan_chan, 0)) != NULL) {
+                    putsock(alertclient, "PRIVMSG %s :Deleted User %s", alertchan_chan->name, auth);
+                }
+            }
+        } else if(exists && !strcmp(row[1], "0")) {
+            printf_mysql_query("UPDATE `users` SET `user_registered` = '%lu', `user_lastcheck` = UNIX_TIMESTAMP() WHERE `user_id` = '%s'", (unsigned long) registered, row[0]);
+        } else {
+            printf_mysql_query("UPDATE `users` SET `user_lastcheck` = UNIX_TIMESTAMP() WHERE `user_id` = '%s'", row[0]);
+        }
+    }
+}
+
+TIMEQ_CALLBACK(main_checkauths) {
+    int next_call = 600;
+    if(get_int_field("General.CheckAuths.enabled")) {
+        int check_start_time = get_int_field("General.CheckAuths.start_time") * 3600;
+        int duration = get_int_field("General.CheckAuths.duration") * 60;
+        int now = getCurrentSecondsOfDay();
+        if(now < check_start_time && check_start_time+duration >= 86400) {
+            check_start_time -= 86400;
+        }
+        if(now >= check_start_time && now < (check_start_time + duration)) {
+            next_call = get_int_field("General.CheckAuths.interval");
+            //get the "longest-unchecked-user"
+            MYSQL_RES *res;
+            MYSQL_ROW row;
+            int lastcheck;
+            time_t unixtime = time(0);
+            int min_unckecked = get_int_field("General.CheckAuths.min_unckecked");
+            printf_mysql_query("SELECT `user_user`, `user_lastcheck` FROM `users` ORDER BY `user_lastcheck` ASC LIMIT 1");
+            res = mysql_use();
+            if ((row = mysql_fetch_row(res)) != NULL) {
+                lastcheck = atoi(row[1]);
+                if(!lastcheck || unixtime - lastcheck >= min_unckecked) {
+                    lookup_authname(row[0], main_checkauths_callback, NULL);
+                } else 
+                    next_call = 300;
+            }
+        } else {
+            int pending;
+            if(now > check_start_time)
+                pending = 86400 - now + check_start_time;
+            else
+                pending = check_start_time - now;
+            if(pending < 600)
+                next_call = pending;
+        }
+        
+    }
+    timeq_add(next_call, main_checkauths, NULL);
+}
+
 TIMEQ_CALLBACK(main_statistics) {
     int update_minutes = get_int_field("statistics.frequency");
     if(!update_minutes) update_minutes = 2;
index 5fc14e935828d300b3d906fc559efc1b6bdb11a6..12ab76d6ff709ab7bf986e08384a62beaaef80bd 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include "mysqlConn.h"
-#define DATABASE_VERSION "14"
+#define DATABASE_VERSION "15"
 
 struct mysql_conn_struct {
     unsigned long tid;