int collections_remove_stale(modsec_rec *msr, const char *col_name) { char *dbm_filename = NULL; apr_sdbm_datum_t key, value; apr_sdbm_t *dbm = NULL; apr_status_t rc; apr_array_header_t *keys_arr; char **keys; apr_time_t now = apr_time_sec(msr->request_time); int i; if (msr->txcfg->data_dir == NULL) { /* The user has been warned about this problem enough times already by now. * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " * "define data directory first.", log_escape(msr->mp, col_name)); */ goto error; } if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", msr->txcfg->webappid, "_", col_name, NULL); else dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), log_escape(msr->mp, dbm_filename)); } rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); dbm = NULL; goto error; } /* First get a list of all keys. */ keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); goto error; } /* No one can write to the file while doing this so * do it as fast as possible. */ rc = apr_sdbm_firstkey(dbm, &key); while(rc == APR_SUCCESS) { char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); *(char **)apr_array_push(keys_arr) = s; rc = apr_sdbm_nextkey(dbm, &key); } apr_sdbm_unlock(dbm); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Found %d record(s) in file \"%s\".", keys_arr->nelts, log_escape(msr->mp, dbm_filename)); } /* Now retrieve the entires one by one. */ keys = (char **)keys_arr->elts; for (i = 0; i < keys_arr->nelts; i++) { key.dptr = keys[i]; key.dsize = strlen(key.dptr) + 1; rc = apr_sdbm_fetch(dbm, &value, key); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Failed reading DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); goto error; } if (value.dptr != NULL) { apr_table_t *col = NULL; msc_string *var = NULL; col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); if (col == NULL) { goto error; } var = (msc_string *)apr_table_get(col, "__expire_KEY"); if (var == NULL) { msr_log(msr, 1, "Collection cleanup discovered entry with no " "__expire_KEY (name \"%s\", key \"%s\").", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); } else { unsigned int expiry_time = atoi(var->value); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), expiry_time - now); } if (expiry_time <= now) { rc = apr_sdbm_delete(dbm, key); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Failed deleting collection (name \"%s\", " "key \"%s\"): %s", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); goto error; } if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Removed stale collection (name \"%s\", " "key \"%s\").", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); } } } } else { /* Ignore entry not found - it may have been removed in the meantime. */ } } apr_sdbm_close(dbm); return 1; error: if (dbm) { apr_sdbm_close(dbm); } return -1; }
static int dump_database(apr_pool_t *pool, apr_sdbm_t *db, int action) { apr_status_t ret; apr_sdbm_datum_t key; apr_sdbm_datum_t val; apr_sdbm_t *db_dest; double elements = 0; int bad_datum = 0; int expired_datum = 0; int removed = 0; int progress = 0; int fret = 0; if (action & PRINT) v("Dumping database...\n"); if (action & SHRINK) v("Starting the shrink process...\n"); if (action & STATUS) v("Showing some status about the databases...\n"); if (action & EXTRACT) { v("Exporting valid items to: /tmp/new_db.[pag,dir]...\n"); ret = apr_sdbm_open(&db_dest, "/tmp/new_db", APR_CREATE | APR_WRITE | APR_SHARELOCK, 0x0777, pool); if (ret != APR_SUCCESS) { v("Failed to retrieve the first key of the database.\n"); fret = -1; goto end; } } ret = apr_sdbm_firstkey(db, &key); if (ret != APR_SUCCESS) { v("Failed to retrieve the first key of the database.\n"); fret = -1; goto end; } do { ret = apr_sdbm_fetch(db, &val, key); if (ret != APR_SUCCESS) { v("Failed to fetch the value of the key: %s.\n", key.dptr); fret = -1; goto end; } elements++; if (action & PRINT) { if ((!(action & PRINT_ONLY_EXPIRED)) || ((action & PRINT_ONLY_EXPIRED) && is_expired(pool, (const unsigned char *)val.dptr, val.dsize))) { printf("Key: \"%s\", Value len: %d\n", key.dptr, val.dsize); if (action & PRINT_MODSEC_VARS) { print_modsec_variables(pool, (const unsigned char *)val.dptr, val.dsize); } } } if (action & SHRINK || action & STATUS || action & EXTRACT) { int selected = 0; if (val.dsize == 0) { bad_datum++; selected = 1; } if (is_expired(pool, (const unsigned char *)val.dptr, val.dsize)) { expired_datum++; selected = 1; } if ((int)elements % 10 == 0) { int p2s = (int) progress++ % 4; p(" [%c] %.0f records so far.\r", progress_feedback[p2s], elements); fflush(stdout); } if (selected && action & SHRINK) { ret = remote_datum_t(pool, db, &key); if (ret != APR_SUCCESS) { p("Failed to delete key: \"%s\"\n", (const unsigned char *)key.dptr); } else { removed++; } //Remove key. } if (selected == 0 && action & EXTRACT) { ret = apr_sdbm_store(db_dest, key, val, APR_SDBM_INSERT); if (ret != APR_SUCCESS) { p("Failed to insert key: \"%s\"\n", (const unsigned char *)key.dptr); } } } ret = apr_sdbm_nextkey(db, &key); if (ret != APR_SUCCESS) { v("Failed to retrieve the next key.\n"); fret = -1; goto end; } } while (key.dptr); end: if (action & EXTRACT) { p("New database generated with valied keys at: /tmp/new_db\n"); apr_sdbm_close(db_dest); } if (action & SHRINK || action & STATUS) { printf("\n"); printf("Total of %.0f elements processed.\n", elements); printf("%d elements removed.\n", removed); printf("Expired elements: %d, inconsistent items: %d\n", expired_datum, bad_datum); if (expired_datum+bad_datum != 0 && elements !=0) printf("Fragmentation rate: %2.2f%% of the database is/was dirty " \ "data.\n", 100*(expired_datum+bad_datum)/elements); } return fret; }