]> code.citadel.org Git - citadel.git/blobdiff - citadel/modules/expire/serv_expire.c
Turn off the user 0 message that should not have gotten into the
[citadel.git] / citadel / modules / expire / serv_expire.c
index 80d38c48c6c13849c485649bdf4a4598030ca79d..d15623a33b3bc51af6bec20b6bbb4c5ec6b1cf35 100644 (file)
  *
  * When using Berkeley DB, there's another reason for the two-phase purge: we
  * don't want the entire thing being done as one huge transaction.
+ *
+ * You'll also notice that we build the in-memory list of records to be deleted
+ * sometimes with a linked list and sometimes with a hash table.  There is no
+ * reason for this aside from the fact that the linked list ones were written
+ * before we had the hash table library available.
  */
 
 
@@ -115,6 +120,7 @@ struct ValidUser *ValidUserList = NULL;
 int messages_purged;
 int users_not_purged;
 char *users_corrupt_msg = NULL;
+char *users_zero_msg = NULL;
 
 struct ctdlroomref *rr = NULL;
 
@@ -225,12 +231,12 @@ void DoPurgeMessages(FILE *purgelist) {
 void PurgeMessages(void) {
        FILE *purgelist;
 
-       lprintf(CTDL_DEBUG, "PurgeMessages() called\n");
+       CtdlLogPrintf(CTDL_DEBUG, "PurgeMessages() called\n");
        messages_purged = 0;
 
        purgelist = tmpfile();
        if (purgelist == NULL) {
-               lprintf(CTDL_CRIT, "Can't create purgelist temp file: %s\n",
+               CtdlLogPrintf(CTDL_CRIT, "Can't create purgelist temp file: %s\n",
                        strerror(errno));
                return;
        }
@@ -297,7 +303,7 @@ void DoPurgeRooms(struct ctdlroom *qrbuf, void *data) {
                age = time(NULL) - (qrbuf->QRmtime);
                purge_secs = (time_t)config.c_roompurge * (time_t)86400;
                if (purge_secs <= (time_t)0) return;
-               lprintf(CTDL_DEBUG, "<%s> is <%ld> seconds old\n", qrbuf->QRname, (long)age);
+               CtdlLogPrintf(CTDL_DEBUG, "<%s> is <%ld> seconds old\n", qrbuf->QRname, (long)age);
                if (age > purge_secs) do_purge = 1;
        } /* !QR_MAILBOX */
 
@@ -319,7 +325,7 @@ int PurgeRooms(void) {
        struct ValidUser *vuptr;
        char *transcript = NULL;
 
-       lprintf(CTDL_DEBUG, "PurgeRooms() called\n");
+       CtdlLogPrintf(CTDL_DEBUG, "PurgeRooms() called\n");
 
 
        /* Load up a table full of valid user numbers so we can delete
@@ -356,7 +362,7 @@ int PurgeRooms(void) {
        if (num_rooms_purged > 0) aide_message(transcript, "Room Autopurger Message");
        free(transcript);
 
-       lprintf(CTDL_DEBUG, "Purged %d rooms.\n", num_rooms_purged);
+       CtdlLogPrintf(CTDL_DEBUG, "Purged %d rooms.\n", num_rooms_purged);
        return(num_rooms_purged);
 }
 
@@ -436,33 +442,72 @@ void do_user_purge(struct ctdluser *us, void *data) {
        
        /* 0 calls is impossible.  If there are 0 calls, it must
         * be a corrupted record, so purge it.
+        * Actually it is possible if an Aide created the user so now we check for less than 0 (DRW)
         */
-       if (us->timescalled == 0) purge = 1;
+       if (us->timescalled < 0) purge = 1;
 
        /* User number 0, as well as any negative user number, is
         * also impossible.
         */
-       if (us->usernum < 1L) purge = 1;
+       if (us->usernum < 0L) purge = 1;
+       
+       /** Don't purge user 0. That user is there for the system */
+       if (us->usernum == 0) purge = 0;
        
        /* If the user has no full name entry then we can't purge them
         * since the actual purge can't find them.
         * This shouldn't happen but does somehow.
-        * So we make an Aide message to alert to it but don't add it to the purge list
         */
        if (IsEmptyStr(us->fullname))
        {
-               purge=0;
-               if (users_corrupt_msg == NULL)
+               purge = 0;
+/*
+ ** Keeping this block of code for later referance.
+ * We don't actually want to send the user 0 messages as part of the purger cycle
+ * But we might want to use some of this code to do a user database integrity check
+ * some time in the future.
+               
+               if (us->usernum > 0L)
                {
-                       users_corrupt_msg = malloc(SIZ);
-                       strcpy(users_corrupt_msg, "The auto-purger found the following user numbers with no name.\n"
-                       "Unfortunately the auto-purger is not yet able to fix this problem.\n"
-                       "This problem is not considered serious since a user with no name can\n"
-                       "not log in.\n");
-               }
+                       purge=0;
+                       if (users_corrupt_msg == NULL)
+                       {
+                               users_corrupt_msg = malloc(SIZ);
+                               strcpy(users_corrupt_msg, "The auto-purger found the following user numbers with no name.\n"
+                               "If the user number is 0 you should report this to the Citadel development\n"
+                               "team either by a bugzilla report at http://bugzilla.citadel.org or\n"
+                               "posting a message in the Citadel Support room on Uncensored at\n"
+                               "https://uncensored.citadel.org You should make it clear that you have seen a\n"
+                               "user 0 messages in the Aide room which means a module has not named its\n"
+                               "private context.\n"
+                               "Unfortunately the auto-purger is not yet able to fix this problem.\n"
+                               "This problem is not considered serious since a user with no name can\n"
+                               "not log in.\n");
+                       }
                
-               users_corrupt_msg=realloc(users_corrupt_msg, strlen(users_corrupt_msg)+SIZ);
-               snprintf(&users_corrupt_msg[strlen(users_corrupt_msg)], SIZ, " %ld\n", us->usernum);
+                       users_corrupt_msg=realloc(users_corrupt_msg, strlen(users_corrupt_msg)+SIZ);
+                       snprintf(&users_corrupt_msg[strlen(users_corrupt_msg)], SIZ, " %ld\n", us->usernum);
+               }
+               else if (us->usernum == 0L)
+               {
+                       purge=0;
+                       if (users_zero_msg == NULL)
+                       {
+                               users_zero_msg = malloc(SIZ);
+                               strcpy(users_zero_msg, "The auto-purger found a user with a user number of 0 but no name.\n"
+                               "This is the result of a bug where a private contaxt has been created but\n"
+                               "not named.\n\n"
+                               "Please report this to the Citadel development team either by a bugzilla\n"
+                               "report at http://bugzilla.citadel.org or by posting a message in the\n"
+                               "Citadel Support room on Uncensored at https://uncensored.citadel.org\n"
+                               "You should make it clear that you have seen a user 0 messages in the\n"
+                               "Aide room which means a module has not named its private context.\n\n"
+                               "This problem is not considered serious since it does not constitute a\n"
+                               "security risk and should not impare system operation.\n"
+                               );
+                       }
+               }
+*/
        }
 
 
@@ -485,7 +530,7 @@ int PurgeUsers(void) {
        int num_users_purged = 0;
        char *transcript = NULL;
 
-       lprintf(CTDL_DEBUG, "PurgeUsers() called\n");
+       CtdlLogPrintf(CTDL_DEBUG, "PurgeUsers() called\n");
        users_not_purged = 0;
 
        switch(config.c_auth_mode) {
@@ -496,7 +541,7 @@ int PurgeUsers(void) {
                        ForEachUser(do_uid_user_purge, NULL);
                        break;
                default:
-                       lprintf(CTDL_DEBUG, "Unknown authentication mode!\n");
+                       CtdlLogPrintf(CTDL_DEBUG, "Unknown authentication mode!\n");
                        break;
        }
 
@@ -539,8 +584,14 @@ int PurgeUsers(void) {
                users_corrupt_msg = NULL;
        }
        
+       if(users_zero_msg)
+       {
+               aide_message(users_zero_msg, "User Zero Message");
+               free (users_zero_msg);
+               users_zero_msg = NULL;
+       }
                
-       lprintf(CTDL_DEBUG, "Purged %d users.\n", num_users_purged);
+       CtdlLogPrintf(CTDL_DEBUG, "Purged %d users.\n", num_users_purged);
        return(num_users_purged);
 }
 
@@ -655,7 +706,7 @@ int PurgeUseTable(void) {
        struct UPurgeList *uptr; 
 
        /* Phase 1: traverse through the table, discovering old records... */
-       lprintf(CTDL_DEBUG, "Purge use table: phase 1\n");
+       CtdlLogPrintf(CTDL_DEBUG, "Purge use table: phase 1\n");
        cdb_rewind(CDB_USETABLE);
        while(cdbut = cdb_next_item(CDB_USETABLE), cdbut != NULL) {
 
@@ -682,7 +733,7 @@ int PurgeUseTable(void) {
        }
 
        /* Phase 2: delete the records */
-       lprintf(CTDL_DEBUG, "Purge use table: phase 2\n");
+       CtdlLogPrintf(CTDL_DEBUG, "Purge use table: phase 2\n");
        while (ul != NULL) {
                cdb_delete(CDB_USETABLE, ul->up_key, strlen(ul->up_key));
                uptr = ul->next;
@@ -690,7 +741,7 @@ int PurgeUseTable(void) {
                ul = uptr;
        }
 
-       lprintf(CTDL_DEBUG, "Purge use table: finished (purged %d records)\n", purged);
+       CtdlLogPrintf(CTDL_DEBUG, "Purge use table: finished (purged %d records)\n", purged);
        return(purged);
 }
 
@@ -709,7 +760,7 @@ int PurgeEuidIndexTable(void) {
        struct CtdlMessage *msg = NULL;
 
        /* Phase 1: traverse through the table, discovering old records... */
-       lprintf(CTDL_DEBUG, "Purge EUID index: phase 1\n");
+       CtdlLogPrintf(CTDL_DEBUG, "Purge EUID index: phase 1\n");
        cdb_rewind(CDB_EUIDINDEX);
        while(cdbei = cdb_next_item(CDB_EUIDINDEX), cdbei != NULL) {
 
@@ -736,7 +787,7 @@ int PurgeEuidIndexTable(void) {
        }
 
        /* Phase 2: delete the records */
-       lprintf(CTDL_DEBUG, "Purge euid index: phase 2\n");
+       CtdlLogPrintf(CTDL_DEBUG, "Purge euid index: phase 2\n");
        while (el != NULL) {
                cdb_delete(CDB_EUIDINDEX, el->ep_key, el->ep_keylen);
                free(el->ep_key);
@@ -745,17 +796,74 @@ int PurgeEuidIndexTable(void) {
                el = eptr;
        }
 
-       lprintf(CTDL_DEBUG, "Purge euid index: finished (purged %d records)\n", purged);
+       CtdlLogPrintf(CTDL_DEBUG, "Purge euid index: finished (purged %d records)\n", purged);
        return(purged);
 }
 
 
+
+/*
+ * Purge OpenID assocations for missing users (theoretically this will never delete anything)
+ */
+int PurgeStaleOpenIDassociations(void) {
+       struct cdbdata *cdboi;
+       struct ctdluser usbuf;
+       HashList *keys = NULL;
+       HashPos *HashPos;
+       char *deleteme = NULL;
+       long len;
+       void *Value;
+       char *Key;
+       int num_deleted = 0;
+
+       keys = NewHash(1, NULL);
+       if (!keys) return(0);
+
+
+       cdb_rewind(CDB_OPENID);
+       while (cdboi = cdb_next_item(CDB_OPENID), cdboi != NULL) {
+               if (cdboi->len > sizeof(long)) {
+                       long usernum;
+                       usernum = ((long)*(cdboi->ptr));
+                       if (getuserbynumber(&usbuf, usernum) != 0) {
+                               deleteme = strdup(cdboi->ptr + sizeof(long)),
+                               Put(keys, deleteme, strlen(deleteme), deleteme, generic_free_handler);
+                       }
+               }
+               cdb_free(cdboi);
+       }
+
+       /* Go through the hash list, deleting keys we stored in it */
+
+       HashPos = GetNewHashPos();
+       while (GetNextHashPos(keys, HashPos, &len, &Key, &Value)!=0)
+       {
+               CtdlLogPrintf(CTDL_DEBUG, "Deleting associated OpenID <%s>\n", Value);
+               cdb_delete(CDB_OPENID, Value, strlen(Value));
+               /* note: don't free(Value) -- deleting the hash list will handle this for us */
+               ++num_deleted;
+       }
+       DeleteHashPos(&HashPos);
+       DeleteHash(&keys);
+       return num_deleted;
+}
+
+
+
+
+
 void *purge_databases(void *args)
 {
         int retval;
         static time_t last_purge = 0;
         time_t now;
         struct tm tm;
+       struct CitContext purgerCC;
+
+       CtdlLogPrintf(CTDL_DEBUG, "Auto-purger_thread() initializing\n");
+
+       CtdlFillPrivateContext(&purgerCC, "purger");
+       citthread_setspecific(MyConKey, (void *)&purgerCC );
 
         while (!CtdlThreadCheckStop()) {
                 /* Do the auto-purge if the current hour equals the purge hour,
@@ -770,57 +878,63 @@ void *purge_databases(void *args)
                 }
 
 
-                lprintf(CTDL_INFO, "Auto-purger: starting.\n");
+                CtdlLogPrintf(CTDL_INFO, "Auto-purger: starting.\n");
 
                if (!CtdlThreadCheckStop())
                {
                        retval = PurgeUsers();
-                       lprintf(CTDL_NOTICE, "Purged %d users.\n", retval);
+                       CtdlLogPrintf(CTDL_NOTICE, "Purged %d users.\n", retval);
                }
                
                if (!CtdlThreadCheckStop())
                {
                        PurgeMessages();
-                       lprintf(CTDL_NOTICE, "Expired %d messages.\n", messages_purged);
+                       CtdlLogPrintf(CTDL_NOTICE, "Expired %d messages.\n", messages_purged);
                }
 
                if (!CtdlThreadCheckStop())
                {
                        retval = PurgeRooms();
-                       lprintf(CTDL_NOTICE, "Expired %d rooms.\n", retval);
+                       CtdlLogPrintf(CTDL_NOTICE, "Expired %d rooms.\n", retval);
                }
 
                if (!CtdlThreadCheckStop())
                {
                        retval = PurgeVisits();
-                       lprintf(CTDL_NOTICE, "Purged %d visits.\n", retval);
+                       CtdlLogPrintf(CTDL_NOTICE, "Purged %d visits.\n", retval);
                }
 
                if (!CtdlThreadCheckStop())
                {
                        retval = PurgeUseTable();
-                       lprintf(CTDL_NOTICE, "Purged %d entries from the use table.\n", retval);
+                       CtdlLogPrintf(CTDL_NOTICE, "Purged %d entries from the use table.\n", retval);
                }
 
                if (!CtdlThreadCheckStop())
                {
                        retval = PurgeEuidIndexTable();
-                       lprintf(CTDL_NOTICE, "Purged %d entries from the EUID index.\n", retval);
+                       CtdlLogPrintf(CTDL_NOTICE, "Purged %d entries from the EUID index.\n", retval);
+               }
+
+               if (!CtdlThreadCheckStop())
+               {
+                       retval = PurgeStaleOpenIDassociations();
+                       CtdlLogPrintf(CTDL_NOTICE, "Purged %d stale OpenID associations.\n", retval);
                }
 
                if (!CtdlThreadCheckStop())
                {
                        retval = TDAP_ProcessAdjRefCountQueue();
-                       lprintf(CTDL_NOTICE, "Processed %d message reference count adjustments.\n", retval);
+                       CtdlLogPrintf(CTDL_NOTICE, "Processed %d message reference count adjustments.\n", retval);
                }
 
                if (!CtdlThreadCheckStop())
                {
-                       lprintf(CTDL_INFO, "Auto-purger: finished.\n");
+                       CtdlLogPrintf(CTDL_INFO, "Auto-purger: finished.\n");
                        last_purge = now;       /* So we don't do it again soon */
                }
                else
-                       lprintf(CTDL_INFO, "Auto-purger: STOPPED.\n");
+                       CtdlLogPrintf(CTDL_INFO, "Auto-purger: STOPPED.\n");
 
         }
         return NULL;