int swd::database::save_parameter(const int& request_id, const std::string& path, const std::string& value, const int& total_whitelist_rules, const int& critical_impact, const int& threat) { ensure_connection(); boost::unique_lock<boost::mutex> scoped_lock(dbi_mutex_); char *path_esc = strdup(path.c_str()); dbi_conn_quote_string(conn_, &path_esc); char *value_esc = strdup(value.c_str()); dbi_conn_quote_string(conn_, &value_esc); dbi_result res = dbi_conn_queryf(conn_, "INSERT INTO parameters " "(request_id, path, value, total_whitelist_rules, critical_impact, threat) " "VALUES (%i, %s, %s, %i, %i, %i)", request_id, path_esc, value_esc, total_whitelist_rules, critical_impact, threat); free(path_esc); free(value_esc); if (!res) { throw swd::exceptions::database_exception("Can't execute parameter query"); } int id = dbi_conn_sequence_last(conn_, "parameters_id_seq"); dbi_result_free(res); return id; }
int swd::database::save_hash(const int& request_id, const std::string& algorithm, const std::string& digest) { ensure_connection(); boost::unique_lock<boost::mutex> scoped_lock(dbi_mutex_); char *algorithm_esc = strdup(algorithm.c_str()); dbi_conn_quote_string(conn_, &algorithm_esc); char *digest_esc = strdup(digest.c_str()); dbi_conn_quote_string(conn_, &digest_esc); dbi_result res = dbi_conn_queryf(conn_, "INSERT INTO hashes (request_id, " "algorithm, digest) VALUES (%i, %s, %s)", request_id, algorithm_esc, digest_esc); free(algorithm_esc); free(digest_esc); if (!res) { throw swd::exceptions::database_exception("Can't execute hash query"); } int id = dbi_conn_sequence_last(conn_, "hashes_id_seq"); dbi_result_free(res); return id; }
swd::whitelist_rules swd::database::get_whitelist_rules(const int& profile_id, const std::string& caller, const std::string& path) { swd::log::i()->send(swd::notice, "Get whitelist rules from db"); ensure_connection(); boost::unique_lock<boost::mutex> scoped_lock(dbi_mutex_); char *caller_esc = strdup(caller.c_str()); dbi_conn_quote_string(conn_, &caller_esc); char *path_esc = strdup(path.c_str()); dbi_conn_quote_string(conn_, &path_esc); /** * Remove LIKE single character wildcard, because it could result easily in security * problems if a user forgets to escape an underscore. And instead of a percentage sign * it is nicer to use an asterisk, because it is more common. */ dbi_result res = dbi_conn_queryf(conn_, "SELECT r.id, r.path, f.id as filter_id, " "f.rule, f.impact, r.min_length, r.max_length FROM whitelist_rules AS r, " "whitelist_filters AS f WHERE r.filter_id = f.id AND r.profile_id = %i AND %s LIKE " "prepare_wildcard(r.caller) AND %s LIKE prepare_wildcard(r.path) AND r.status = %i", profile_id, caller_esc, path_esc, STATUS_ACTIVATED); free(caller_esc); free(path_esc); if (!res) { throw swd::exceptions::database_exception("Can't execute whitelist_rules query"); } swd::whitelist_rules rules; while (dbi_result_next_row(res)) { swd::whitelist_filter_ptr filter(new swd::whitelist_filter()); filter->set_id(dbi_result_get_uint(res, "filter_id")); filter->set_regex(dbi_result_get_string(res, "rule")); swd::whitelist_rule_ptr rule(new swd::whitelist_rule()); rule->set_id(dbi_result_get_uint(res, "id")); rule->set_filter(filter); rule->set_min_length(dbi_result_get_uint(res, "min_length")); rule->set_max_length(dbi_result_get_uint(res, "max_length")); rules.push_back(rule); } dbi_result_free(res); return rules; }
bool swd::database::is_flooding(const std::string& client_ip, const int& profile_id) { ensure_connection(); boost::unique_lock<boost::mutex> scoped_lock(dbi_mutex_); char *client_ip_esc = strdup(client_ip.c_str()); dbi_conn_quote_string(conn_, &client_ip_esc); dbi_result res = dbi_conn_queryf(conn_, "SELECT is_flooding(%i, %s) AS result", profile_id, client_ip_esc); free(client_ip_esc); if (!res) { throw swd::exceptions::database_exception("Can't execute request count query"); } bool flooding = false; if (dbi_result_get_numrows(res) == 1) { if (!dbi_result_next_row(res)) { throw swd::exceptions::database_exception("No flooding?"); } flooding = (dbi_result_get_uint(res, "result") == 1); } dbi_result_free(res); return flooding; }
swd::profile_ptr swd::database::get_profile(const std::string& server_ip, const int& profile_id) { std::stringstream log_message; log_message << "Get profile from db -> server_ip: " << server_ip << "; profile_id: " << profile_id; swd::log::i()->send(swd::notice, log_message.str()); /* Test the database connection status. Tries to reconnect if disconnected. */ ensure_connection(); /* Mutex to avoid race conditions. */ boost::unique_lock<boost::mutex> scoped_lock(dbi_mutex_); /** * First we escape server_ip. It comes from a trusted source, but better safe * than sorry. This does not work with std::string though. */ char *server_ip_esc = strdup(server_ip.c_str()); dbi_conn_quote_string(conn_, &server_ip_esc); /* Insert the ip and execute the query. */ dbi_result res = dbi_conn_queryf(conn_, "SELECT id, hmac_key, mode, " "whitelist_enabled, blacklist_enabled, integrity_enabled, flooding_enabled, " "blacklist_threshold, cache_outdated FROM profiles WHERE %s LIKE " "prepare_wildcard(server_ip) AND id = %i", server_ip_esc, profile_id); /* Don't forget to free server_ip_esc to avoid a memory leak. */ free(server_ip_esc); if (!res) { throw swd::exceptions::database_exception("Can't execute profile query"); } if (dbi_result_get_numrows(res) != 1) { throw swd::exceptions::database_exception("Can't get profile"); } if (!dbi_result_next_row(res)) { throw swd::exceptions::database_exception("No profile?"); } swd::profile_ptr profile(new swd::profile()); profile->set_server_ip(server_ip), profile->set_id(dbi_result_get_uint(res, "id")); profile->set_mode(dbi_result_get_uint(res, "mode")); profile->set_whitelist_enabled(dbi_result_get_uint(res, "whitelist_enabled") == 1); profile->set_blacklist_enabled(dbi_result_get_uint(res, "blacklist_enabled") == 1); profile->set_integrity_enabled(dbi_result_get_uint(res, "integrity_enabled") == 1); profile->set_flooding_enabled(dbi_result_get_uint(res, "flooding_enabled") == 1); profile->set_key(dbi_result_get_string(res, "hmac_key")); profile->set_blacklist_threshold(dbi_result_get_uint(res, "blacklist_threshold")); profile->set_cache_outdated(dbi_result_get_uint(res, "cache_outdated") == 1); dbi_result_free(res); return profile; }
int swd::database::save_request(const int& profile_id, const std::string& caller, const std::string& resource, const int& mode, const std::string& client_ip, const int& total_integrity_rules) { std::stringstream log_message; log_message << "Save request -> profile: " << profile_id << "; caller: " << caller << "; resource: " << resource << "; mode: " << mode << "; client_ip: " << client_ip; swd::log::i()->send(swd::notice, log_message.str()); ensure_connection(); boost::unique_lock<boost::mutex> scoped_lock(dbi_mutex_); char *caller_esc = strdup(caller.c_str()); dbi_conn_quote_string(conn_, &caller_esc); char *resource_esc = strdup(resource.c_str()); dbi_conn_quote_string(conn_, &resource_esc); char *client_ip_esc = strdup(client_ip.c_str()); dbi_conn_quote_string(conn_, &client_ip_esc); dbi_result res = dbi_conn_queryf(conn_, "INSERT INTO requests (profile_id, " "caller, resource, mode, client_ip, total_integrity_rules) VALUES (%i, %s, " "%s, %i, %s, %i)", profile_id, caller_esc, resource_esc, mode, client_ip_esc, total_integrity_rules); free(caller_esc); free(resource_esc); free(client_ip_esc); if (!res) { throw swd::exceptions::database_exception("Can't execute request query"); } int id = dbi_conn_sequence_last(conn_, "requests_id_seq"); dbi_result_free(res); return id; }
size_t dbi_conn_escape_string(dbi_conn Conn, char **orig) { size_t newlen; newlen = dbi_conn_quote_string(Conn, orig); if (newlen) { (*orig)[newlen-1] = '\0'; memmove(*orig, (*orig)+1, newlen-1); } return newlen-2; }
swd::blacklist_rules swd::database::get_blacklist_rules(const int& profile_id, const std::string& caller, const std::string& path) { swd::log::i()->send(swd::notice, "Get blacklist rules from db"); ensure_connection(); boost::unique_lock<boost::mutex> scoped_lock(dbi_mutex_); char *caller_esc = strdup(caller.c_str()); dbi_conn_quote_string(conn_, &caller_esc); char *path_esc = strdup(path.c_str()); dbi_conn_quote_string(conn_, &path_esc); dbi_result res = dbi_conn_queryf(conn_, "SELECT r.id, r.path, r.threshold " "FROM blacklist_rules AS r WHERE r.profile_id = %i AND %s LIKE " "prepare_wildcard(r.caller) AND %s LIKE prepare_wildcard(r.path) AND " "r.status = %i", profile_id, caller_esc, path_esc, STATUS_ACTIVATED); free(caller_esc); free(path_esc); if (!res) { throw swd::exceptions::database_exception("Can't execute blacklist_rules query"); } swd::blacklist_rules rules; while (dbi_result_next_row(res)) { swd::blacklist_rule_ptr rule(new swd::blacklist_rule()); rule->set_id(dbi_result_get_uint(res, "id")); rule->set_threshold(dbi_result_get_uint(res, "threshold")); rules.push_back(rule); } dbi_result_free(res); return rules; }
//******************************************************************* // UPDATE PR_STATUS //******************************************************************* static dbi_result update_pr_status(trx *t, struct probe_result *prv) { dbi_result result; char *qry; qry = g_malloc(512 + (t->res->message ? strlen(t->res->message)*2 : 0)); sprintf(qry, "update pr_status " "set stattime = '%u', expires = '%u', hide = '%s', " " contact = '%u', server = '%u'", t->res->stattime, t->res->expires, t->def->hide, t->def->contact, t->def->server); if (t->probe->fuse) { if (t->res->color > prv->color || prv->color == STAT_PURPLE) { // if this probe acts like a fuse, only update color if new color is higher then old color // because colors must be set to green (= fuse replaced) by a human sprintf(&qry[strlen(qry)], ", color = '%u'", t->res->color); } } else { sprintf(&qry[strlen(qry)], ", color = '%u'", t->res->color); } if (t->res->message) { char *escmsg; escmsg = strdup(t->res->message); dbi_conn_quote_string(t->probe->db, &escmsg); if (t->res->color != prv->color) { sprintf(&qry[strlen(qry)], ", message = %s", escmsg); } else if (t->probe->fuse) { sprintf(&qry[strlen(qry)], ", message = concat(message,%s)", escmsg); } free(escmsg); } else { sprintf(&qry[strlen(qry)],", message = ''"); } sprintf(&qry[strlen(qry)], " where probe = '%u' and class = '%u'", t->def->probeid, t->probe->class); result = db_rawquery(t->probe->db, 0, qry); g_free(qry); return(result); }
//******************************************************************* // CREATE PR_STATUS RECORD //******************************************************************* static void insert_pr_status(trx *t) { dbi_result result; char *escmsg; if (t->res->message) { escmsg = strdup(t->res->message); dbi_conn_quote_string(t->probe->db, &escmsg); } else { escmsg = strdup("''"); } result = db_query(t->probe->db, 0, "insert into pr_status " "set class = '%u', probe = '%u', stattime = '%u', expires = '%u', " " color = '%u', server = '%u', message = %s, " " contact = '%u', hide = '%s'", t->probe->class, t->def->probeid, t->res->stattime, t->res->expires, t->def->color, t->def->server, escmsg, t->def->contact, t->def->hide); dbi_result_free(result); g_free(escmsg); }
//******************************************************************* // CREATE PR_HIST //******************************************************************* static void create_pr_hist(trx *t, struct probe_result *prv) { dbi_result result; char *escmsg; if (t->res->message) { escmsg = strdup(t->res->message); dbi_conn_quote_string(t->probe->db, &escmsg); } else { escmsg = strdup("''"); } result = db_query(t->probe->db, 0, "insert into pr_hist " "set server = '%u', class = '%u', probe = '%u', stattime = '%u', " " prv_color = '%d', color = '%d', message = %s, contact = '%u', " " hide = '%s', pgroup = '%u'", t->def->server, t->probe->class, t->def->probeid, t->res->stattime, /* (t->res->received > t->res->expires) ? STAT_PURPLE : */ prv->color, t->res->color, escmsg, t->def->contact, t->def->hide, t->def->pgroup); dbi_result_free(result); g_free(escmsg); }
swd::integrity_rules swd::database::get_integrity_rules(const int& profile_id, const std::string& caller) { swd::log::i()->send(swd::notice, "Get integrity rules from db"); ensure_connection(); boost::unique_lock<boost::mutex> scoped_lock(dbi_mutex_); char *caller_esc = strdup(caller.c_str()); dbi_conn_quote_string(conn_, &caller_esc); dbi_result res = dbi_conn_queryf(conn_, "SELECT r.id, r.algorithm, r.digest FROM " "integrity_rules AS r WHERE r.profile_id = %i AND %s LIKE prepare_wildcard(r.caller) " "AND r.status = %i", profile_id, caller_esc, STATUS_ACTIVATED); free(caller_esc); if (!res) { throw swd::exceptions::database_exception("Can't execute whitelist_rules query"); } swd::integrity_rules rules; while (dbi_result_next_row(res)) { swd::integrity_rule_ptr rule(new swd::integrity_rule()); rule->set_id(dbi_result_get_uint(res, "id")); rule->set_algorithm(dbi_result_get_string(res, "algorithm")); rule->set_digest(dbi_result_get_string(res, "digest")); rules.push_back(rule); } dbi_result_free(res); return rules; }