Extra RADIUS request attributes from SQLite
Add an SQLite table for defining per station MAC address version of radius_auth_req_attr/radius_acct_req_attr information. Create the necessary table and index where this doesn't exist. Select attributes from the table keyed by station MAC address and request type (auth or acct), parse and apply to a RADIUS message. Add radius_req_attr_sqlite hostapd config option for SQLite database file. Open/close RADIUS attribute database for a lifetime of a BSS and invoke functions to add extra attributes during RADIUS auth and accounting request generation. Signed-off-by: Terry Burton <tez@terryburton.co.uk>
This commit is contained in:
parent
74707def8f
commit
f4111ff3d1
9 changed files with 158 additions and 1 deletions
|
@ -2832,6 +2832,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
a = a->next;
|
a = a->next;
|
||||||
a->next = attr;
|
a->next = attr;
|
||||||
}
|
}
|
||||||
|
} else if (os_strcmp(buf, "radius_req_attr_sqlite") == 0) {
|
||||||
|
os_free(bss->radius_req_attr_sqlite);
|
||||||
|
bss->radius_req_attr_sqlite = os_strdup(pos);
|
||||||
} else if (os_strcmp(buf, "radius_das_port") == 0) {
|
} else if (os_strcmp(buf, "radius_das_port") == 0) {
|
||||||
bss->radius_das_port = atoi(pos);
|
bss->radius_das_port = atoi(pos);
|
||||||
} else if (os_strcmp(buf, "radius_das_client") == 0) {
|
} else if (os_strcmp(buf, "radius_das_client") == 0) {
|
||||||
|
|
|
@ -1384,6 +1384,17 @@ own_ip_addr=127.0.0.1
|
||||||
# Operator-Name = "Operator"
|
# Operator-Name = "Operator"
|
||||||
#radius_acct_req_attr=126:s:Operator
|
#radius_acct_req_attr=126:s:Operator
|
||||||
|
|
||||||
|
# If SQLite support is included, path to a database from which additional
|
||||||
|
# RADIUS request attributes are extracted based on the station MAC address.
|
||||||
|
#
|
||||||
|
# The schema for the radius_attributes table is:
|
||||||
|
# id | sta | reqtype | attr : multi-key (sta, reqtype)
|
||||||
|
# id = autonumber
|
||||||
|
# sta = station MAC address in `11:22:33:44:55:66` format.
|
||||||
|
# type = `auth` | `acct` | NULL (match any)
|
||||||
|
# attr = existing config file format, e.g. `126:s:Test Operator`
|
||||||
|
#radius_req_attr_sqlite=radius_attr.sqlite
|
||||||
|
|
||||||
# Dynamic Authorization Extensions (RFC 5176)
|
# Dynamic Authorization Extensions (RFC 5176)
|
||||||
# This mechanism can be used to allow dynamic changes to user session based on
|
# This mechanism can be used to allow dynamic changes to user session based on
|
||||||
# commands from a RADIUS server (or some other disconnect client that has the
|
# commands from a RADIUS server (or some other disconnect client that has the
|
||||||
|
|
|
@ -97,6 +97,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
|
||||||
msg) < 0)
|
msg) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (sta && add_sqlite_radius_attr(hapd, sta, msg, 1) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (sta) {
|
if (sta) {
|
||||||
for (i = 0; ; i++) {
|
for (i = 0; ; i++) {
|
||||||
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
|
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
|
||||||
|
|
|
@ -545,7 +545,7 @@ struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
|
void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
|
||||||
{
|
{
|
||||||
struct hostapd_radius_attr *prev;
|
struct hostapd_radius_attr *prev;
|
||||||
|
|
||||||
|
@ -694,6 +694,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||||
}
|
}
|
||||||
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
|
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
|
||||||
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
|
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
|
||||||
|
os_free(conf->radius_req_attr_sqlite);
|
||||||
os_free(conf->rsn_preauth_interfaces);
|
os_free(conf->rsn_preauth_interfaces);
|
||||||
os_free(conf->ctrl_interface);
|
os_free(conf->ctrl_interface);
|
||||||
os_free(conf->ca_cert);
|
os_free(conf->ca_cert);
|
||||||
|
|
|
@ -301,6 +301,7 @@ struct hostapd_bss_config {
|
||||||
int radius_request_cui;
|
int radius_request_cui;
|
||||||
struct hostapd_radius_attr *radius_auth_req_attr;
|
struct hostapd_radius_attr *radius_auth_req_attr;
|
||||||
struct hostapd_radius_attr *radius_acct_req_attr;
|
struct hostapd_radius_attr *radius_acct_req_attr;
|
||||||
|
char *radius_req_attr_sqlite;
|
||||||
int radius_das_port;
|
int radius_das_port;
|
||||||
unsigned int radius_das_time_window;
|
unsigned int radius_das_time_window;
|
||||||
int radius_das_require_event_timestamp;
|
int radius_das_require_event_timestamp;
|
||||||
|
@ -1074,6 +1075,7 @@ hostapd_set_oper_centr_freq_seg1_idx(struct hostapd_config *conf,
|
||||||
int hostapd_mac_comp(const void *a, const void *b);
|
int hostapd_mac_comp(const void *a, const void *b);
|
||||||
struct hostapd_config * hostapd_config_defaults(void);
|
struct hostapd_config * hostapd_config_defaults(void);
|
||||||
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
|
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
|
||||||
|
void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr);
|
||||||
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
|
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
|
||||||
void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
|
void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
|
||||||
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
|
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "utils/includes.h"
|
#include "utils/includes.h"
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
#include "utils/eloop.h"
|
#include "utils/eloop.h"
|
||||||
|
@ -1025,6 +1028,43 @@ hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
|
||||||
#define hostapd_das_coa NULL
|
#define hostapd_das_coa NULL
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
|
||||||
|
static int db_table_exists(sqlite3 *db, const char *name)
|
||||||
|
{
|
||||||
|
char cmd[128];
|
||||||
|
|
||||||
|
os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
|
||||||
|
return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int db_table_create_radius_attributes(sqlite3 *db)
|
||||||
|
{
|
||||||
|
char *err = NULL;
|
||||||
|
const char *sql =
|
||||||
|
"CREATE TABLE radius_attributes("
|
||||||
|
" id INTEGER PRIMARY KEY,"
|
||||||
|
" sta TEXT,"
|
||||||
|
" reqtype TEXT,"
|
||||||
|
" attr TEXT"
|
||||||
|
");"
|
||||||
|
"CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);";
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Adding database table for RADIUS attribute information");
|
||||||
|
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
|
||||||
|
wpa_printf(MSG_ERROR, "SQLite error: %s", err);
|
||||||
|
sqlite3_free(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
#endif /* CONFIG_NO_RADIUS */
|
#endif /* CONFIG_NO_RADIUS */
|
||||||
|
|
||||||
|
|
||||||
|
@ -1178,6 +1218,24 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||||
if (wpa_debug_level <= MSG_MSGDUMP)
|
if (wpa_debug_level <= MSG_MSGDUMP)
|
||||||
conf->radius->msg_dumps = 1;
|
conf->radius->msg_dumps = 1;
|
||||||
#ifndef CONFIG_NO_RADIUS
|
#ifndef CONFIG_NO_RADIUS
|
||||||
|
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
if (conf->radius_req_attr_sqlite) {
|
||||||
|
if (sqlite3_open(conf->radius_req_attr_sqlite,
|
||||||
|
&hapd->rad_attr_db)) {
|
||||||
|
wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'",
|
||||||
|
conf->radius_req_attr_sqlite);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s",
|
||||||
|
conf->radius_req_attr_sqlite);
|
||||||
|
if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") &&
|
||||||
|
db_table_create_radius_attributes(hapd->rad_attr_db) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
hapd->radius = radius_client_init(hapd, conf->radius);
|
hapd->radius = radius_client_init(hapd, conf->radius);
|
||||||
if (hapd->radius == NULL) {
|
if (hapd->radius == NULL) {
|
||||||
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
|
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
|
||||||
|
@ -2194,6 +2252,12 @@ static void hostapd_bss_deinit(struct hostapd_data *hapd)
|
||||||
hapd->conf ? hapd->conf->iface : "N/A");
|
hapd->conf ? hapd->conf->iface : "N/A");
|
||||||
hostapd_bss_deinit_no_free(hapd);
|
hostapd_bss_deinit_no_free(hapd);
|
||||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
|
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
if (hapd->rad_attr_db) {
|
||||||
|
sqlite3_close(hapd->rad_attr_db);
|
||||||
|
hapd->rad_attr_db = NULL;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
hostapd_cleanup(hapd);
|
hostapd_cleanup(hapd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
#ifndef HOSTAPD_H
|
#ifndef HOSTAPD_H
|
||||||
#define HOSTAPD_H
|
#define HOSTAPD_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
#include "common/defs.h"
|
#include "common/defs.h"
|
||||||
#include "utils/list.h"
|
#include "utils/list.h"
|
||||||
#include "ap_config.h"
|
#include "ap_config.h"
|
||||||
|
@ -390,6 +394,10 @@ struct hostapd_data {
|
||||||
#endif /* CONFIG_AIRTIME_POLICY */
|
#endif /* CONFIG_AIRTIME_POLICY */
|
||||||
|
|
||||||
u8 last_1x_eapol_key_replay_counter[8];
|
u8 last_1x_eapol_key_replay_counter[8];
|
||||||
|
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
sqlite3 *rad_attr_db;
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "utils/includes.h"
|
#include "utils/includes.h"
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
#include "utils/eloop.h"
|
#include "utils/eloop.h"
|
||||||
|
@ -615,6 +618,63 @@ int add_common_radius_attr(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
struct radius_msg *msg, int acct)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
const char *attrtxt;
|
||||||
|
char addrtxt[3 * ETH_ALEN];
|
||||||
|
char *sql;
|
||||||
|
sqlite3_stmt *stmt = NULL;
|
||||||
|
|
||||||
|
if (!hapd->rad_attr_db)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr));
|
||||||
|
|
||||||
|
sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);";
|
||||||
|
if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt,
|
||||||
|
NULL) != SQLITE_OK) {
|
||||||
|
wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s",
|
||||||
|
sqlite3_errmsg(hapd->rad_attr_db));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC);
|
||||||
|
sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC);
|
||||||
|
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
struct hostapd_radius_attr *attr;
|
||||||
|
struct radius_attr_hdr *hdr;
|
||||||
|
|
||||||
|
attrtxt = (const char *) sqlite3_column_text(stmt, 0);
|
||||||
|
attr = hostapd_parse_radius_attr(attrtxt);
|
||||||
|
if (!attr) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"Skipping invalid attribute from SQL: %s",
|
||||||
|
attrtxt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s",
|
||||||
|
attrtxt);
|
||||||
|
hdr = radius_msg_add_attr(msg, attr->type,
|
||||||
|
wpabuf_head(attr->val),
|
||||||
|
wpabuf_len(attr->val));
|
||||||
|
hostapd_config_free_radius_attr(attr);
|
||||||
|
if (!hdr) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"Could not add RADIUS attribute from SQL");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
sqlite3_clear_bindings(stmt);
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||||
struct sta_info *sta,
|
struct sta_info *sta,
|
||||||
const u8 *eap, size_t len)
|
const u8 *eap, size_t len)
|
||||||
|
@ -654,6 +714,9 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||||
msg) < 0)
|
msg) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* TODO: should probably check MTU from driver config; 2304 is max for
|
/* TODO: should probably check MTU from driver config; 2304 is max for
|
||||||
* IEEE 802.11, but use 1400 to avoid problems with too large packets
|
* IEEE 802.11, but use 1400 to avoid problems with too large packets
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -59,6 +59,8 @@ int add_common_radius_attr(struct hostapd_data *hapd,
|
||||||
struct hostapd_radius_attr *req_attr,
|
struct hostapd_radius_attr *req_attr,
|
||||||
struct sta_info *sta,
|
struct sta_info *sta,
|
||||||
struct radius_msg *msg);
|
struct radius_msg *msg);
|
||||||
|
int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
struct radius_msg *msg, int acct);
|
||||||
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||||
struct sta_info *sta,
|
struct sta_info *sta,
|
||||||
const u8 *eap, size_t len);
|
const u8 *eap, size_t len);
|
||||||
|
|
Loading…
Reference in a new issue