int remote_datum_t(apr_pool_t *pool, apr_sdbm_t *db, apr_sdbm_datum_t *key) { int ret = 0; ret = apr_sdbm_delete(db, *key); if (ret == APR_SUCCESS) { v("Deleted successfully.\n"); return 0; } v("apr_sdbm_rdonly? %d\n", apr_sdbm_rdonly(db)); v("APR_EINVAL? %d\n", APR_EINVAL); v("ret == %d\n", ret); v("Failed to delete.\n"); return -1; }
static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, const char *col_key, int col_key_len) { char *dbm_filename = NULL; apr_status_t rc; apr_sdbm_datum_t key; apr_sdbm_datum_t *value = NULL; apr_sdbm_t *dbm = NULL; apr_table_t *col = NULL; const apr_array_header_t *arr; apr_table_entry_t *te; int expired = 0; int i; if (msr->txcfg->data_dir == NULL) { msr_log(msr, 1, "Unable to retrieve collection (name \"%s\", key \"%s\"). Use " "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); goto cleanup; } dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), log_escape(msr->mp, dbm_filename)); } key.dptr = (char *)col_key; key.dsize = col_key_len + 1; if (existing_dbm == NULL) { rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { dbm = NULL; goto cleanup; } } else { dbm = existing_dbm; } value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); rc = apr_sdbm_fetch(dbm, value, key); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); goto cleanup; } if (value->dptr == NULL) { /* Key not found in DBM file. */ goto cleanup; } /* ENH Need expiration (and perhaps other metadata) accessible in blob * form to determine if converting to a table is needed. This will * save some cycles. */ /* Transform raw data into a table. */ col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); if (col == NULL) { goto cleanup; } /* Close after "value" used from fetch or memory may be overwritten. */ if (existing_dbm == NULL) { apr_sdbm_close(dbm); dbm = NULL; } /* Remove expired variables. */ do { arr = apr_table_elts(col); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { if (strncmp(te[i].key, "__expire_", 9) == 0) { msc_string *var = (msc_string *)te[i].val; int expiry_time = atoi(var->value); if (expiry_time <= apr_time_sec(msr->request_time)) { char *key_to_expire = te[i].key; /* Done early if the col expired */ if (strcmp(key_to_expire, "__expire_KEY") == 0) { expired = 1; } if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire + 9); msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire); } apr_table_unset(col, key_to_expire + 9); apr_table_unset(col, key_to_expire); if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Removed expired variable \"%s\".", key_to_expire + 9); } break; } } } } while(!expired && (i != arr->nelts)); /* Delete the collection if the variable "KEY" does not exist. * * ENH It would probably be more efficient to hold the DBM * open until determined if it needs deleted than to open a second * time. */ if (apr_table_get(col, "KEY") == NULL) { if (existing_dbm == NULL) { 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 cleanup; } } else { dbm = existing_dbm; } 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, col_key, col_key_len), get_apr_error(msr->mp, rc)); goto cleanup; } if (existing_dbm == NULL) { apr_sdbm_close(dbm); dbm = NULL; } if (expired && (msr->txcfg->debuglog_level >= 9)) { msr_log(msr, 9, "Collection expired (name \"%s\", key \"%s\").", col_name, log_escape_ex(msr->mp, col_key, col_key_len)); } if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Deleted collection (name \"%s\", key \"%s\").", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); } goto cleanup; } /* Update UPDATE_RATE */ { msc_string *var; int create_time, counter; var = (msc_string *)apr_table_get(col, "CREATE_TIME"); if (var == NULL) { /* Error. */ } else { create_time = atoi(var->value); var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); if (var == NULL) { /* Error. */ } else { apr_time_t td; counter = atoi(var->value); /* UPDATE_RATE is removed on store, so add it back here */ var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); var->name = "UPDATE_RATE"; var->name_len = strlen(var->name); apr_table_setn(col, var->name, (void *)var); /* NOTE: No rate if there has been no time elapsed */ td = (apr_time_sec(apr_time_now()) - create_time); if (td == 0) { var->value = apr_psprintf(msr->mp, "%d", 0); } else { var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)((60 * counter)/td)); } var->value_len = strlen(var->value); } } } if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Retrieved collection (name \"%s\", key \"%s\").", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); } if ((existing_dbm == NULL) && dbm) { /* Should not ever get here */ msr_log(msr, 1, "Internal Error: Collection remained open (name \"%s\", key \"%s\").", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); apr_sdbm_close(dbm); } return col; cleanup: if ((existing_dbm == NULL) && dbm) { apr_sdbm_close(dbm); } return NULL; }
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; }