]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Extra RADIUS request attributes from SQLite
authorTerry Burton <tez@terryburton.co.uk>
Sun, 21 Jul 2019 12:05:56 +0000 (13:05 +0100)
committerJouni Malinen <j@w1.fi>
Tue, 30 Jul 2019 16:58:09 +0000 (19:58 +0300)
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>
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/accounting.c
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/ieee802_1x.c
src/ap/ieee802_1x.h

index 29ea92e0d35e721c47e06d982360c28f19ca71b3..1f2c565832601b84f30aeed9741441d968511cf8 100644 (file)
@@ -2832,6 +2832,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                a = a->next;
                        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) {
                bss->radius_das_port = atoi(pos);
        } else if (os_strcmp(buf, "radius_das_client") == 0) {
index f2d5873885b05eb38ab0e7df5fa27f1df2a8e31b..5138aeebc4c586912d4be27d351cad86c77627e6 100644 (file)
@@ -1384,6 +1384,17 @@ own_ip_addr=127.0.0.1
 # Operator-Name = "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)
 # 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
index 0aacc3c95b084cb976e1f43d2ddd9354916b7b01..9fc1886a2cffe5795b580957fedaed5f80ec14e0 100644 (file)
@@ -97,6 +97,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                                   msg) < 0)
                goto fail;
 
+       if (sta && add_sqlite_radius_attr(hapd, sta, msg, 1) < 0)
+               goto fail;
+
        if (sta) {
                for (i = 0; ; i++) {
                        val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
index 258a20572650a5abb5b99160c62a406ab2cb71bb..968eb65a622d170c903fc12a265f59424dbfedc4 100644 (file)
@@ -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;
 
@@ -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_acct_req_attr);
+       os_free(conf->radius_req_attr_sqlite);
        os_free(conf->rsn_preauth_interfaces);
        os_free(conf->ctrl_interface);
        os_free(conf->ca_cert);
index f42505e447d5fb3ff3c027b39d60f3f4aad7502d..0a1d49b717157e5397ba72b510ebfb988f0094bb 100644 (file)
@@ -301,6 +301,7 @@ struct hostapd_bss_config {
        int radius_request_cui;
        struct hostapd_radius_attr *radius_auth_req_attr;
        struct hostapd_radius_attr *radius_acct_req_attr;
+       char *radius_req_attr_sqlite;
        int radius_das_port;
        unsigned int radius_das_time_window;
        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);
 struct hostapd_config * hostapd_config_defaults(void);
 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_users(struct hostapd_eap_user *user);
 void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
index cc75a7765a80f01e35dad7dd00ea34ad47d7bdad..bf1975fbd283308e3eddd316ef36725f920ad806 100644 (file)
@@ -7,6 +7,9 @@
  */
 
 #include "utils/includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
 
 #include "utils/common.h"
 #include "utils/eloop.h"
@@ -1025,6 +1028,43 @@ hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
 #define hostapd_das_coa NULL
 #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 */
 
 
@@ -1178,6 +1218,24 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
        if (wpa_debug_level <= MSG_MSGDUMP)
                conf->radius->msg_dumps = 1;
 #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);
        if (hapd->radius == NULL) {
                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");
        hostapd_bss_deinit_no_free(hapd);
        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);
 }
 
index d90bae4e61e9902849c32fd8d5cd00dafa8173fd..518c7f10bc37532ba5a69c58914d60cfe1d047f1 100644 (file)
@@ -9,6 +9,10 @@
 #ifndef HOSTAPD_H
 #define HOSTAPD_H
 
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
 #include "common/defs.h"
 #include "utils/list.h"
 #include "ap_config.h"
@@ -390,6 +394,10 @@ struct hostapd_data {
 #endif /* CONFIG_AIRTIME_POLICY */
 
        u8 last_1x_eapol_key_replay_counter[8];
+
+#ifdef CONFIG_SQLITE
+       sqlite3 *rad_attr_db;
+#endif /* CONFIG_SQLITE */
 };
 
 
index d62864136581721097e38f59d82b4471d28522fd..ab6989b0dd0fbfcf225334272517ca7ef131b51b 100644 (file)
@@ -7,6 +7,9 @@
  */
 
 #include "utils/includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
 
 #include "utils/common.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,
                                   struct sta_info *sta,
                                   const u8 *eap, size_t len)
@@ -654,6 +714,9 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                                   msg) < 0)
                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
         * IEEE 802.11, but use 1400 to avoid problems with too large packets
         */
index d771ba526c1346d50d091d7f787a1a56d84b9972..bb85b93d69a50ec807eb3d838ac77118eefc8ca6 100644 (file)
@@ -59,6 +59,8 @@ int add_common_radius_attr(struct hostapd_data *hapd,
                           struct hostapd_radius_attr *req_attr,
                           struct sta_info *sta,
                           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,
                                   struct sta_info *sta,
                                   const u8 *eap, size_t len);