RADIUS server: Add option for storing log information to SQLite DB
If eap_user_file is configured to point to an SQLite database, RADIUS server code can use that database for log information. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
f3ef7a2640
commit
8a57da7e28
4 changed files with 123 additions and 20 deletions
|
@ -16,3 +16,11 @@ INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 use
|
||||||
|
|
||||||
INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
|
INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
|
||||||
INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
|
INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
|
||||||
|
|
||||||
|
CREATE TABLE authlog(
|
||||||
|
timestamp TEXT,
|
||||||
|
session TEXT,
|
||||||
|
nas_ip TEXT,
|
||||||
|
username TEXT,
|
||||||
|
note TEXT
|
||||||
|
);
|
||||||
|
|
|
@ -115,6 +115,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||||
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
|
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
|
||||||
srv.pwd_group = conf->pwd_group;
|
srv.pwd_group = conf->pwd_group;
|
||||||
srv.server_id = conf->server_id ? conf->server_id : "hostapd";
|
srv.server_id = conf->server_id ? conf->server_id : "hostapd";
|
||||||
|
srv.sqlite_file = conf->eap_user_sqlite;
|
||||||
#ifdef CONFIG_RADIUS_TEST
|
#ifdef CONFIG_RADIUS_TEST
|
||||||
srv.dump_msk_file = conf->dump_msk_file;
|
srv.dump_msk_file = conf->dump_msk_file;
|
||||||
#endif /* CONFIG_RADIUS_TEST */
|
#endif /* CONFIG_RADIUS_TEST */
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "radius.h"
|
#include "radius.h"
|
||||||
|
@ -69,6 +72,8 @@ struct radius_session {
|
||||||
unsigned int sess_id;
|
unsigned int sess_id;
|
||||||
struct eap_sm *eap;
|
struct eap_sm *eap;
|
||||||
struct eap_eapol_interface *eap_if;
|
struct eap_eapol_interface *eap_if;
|
||||||
|
char *username; /* from User-Name attribute */
|
||||||
|
char *nas_ip;
|
||||||
|
|
||||||
struct radius_msg *last_msg;
|
struct radius_msg *last_msg;
|
||||||
char *last_from_addr;
|
char *last_from_addr;
|
||||||
|
@ -315,6 +320,10 @@ struct radius_server_data {
|
||||||
|
|
||||||
char *subscr_remediation_url;
|
char *subscr_remediation_url;
|
||||||
u8 subscr_remediation_method;
|
u8 subscr_remediation_method;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
sqlite3 *db;
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -332,6 +341,52 @@ static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||||
static void radius_server_session_remove_timeout(void *eloop_ctx,
|
static void radius_server_session_remove_timeout(void *eloop_ctx,
|
||||||
void *timeout_ctx);
|
void *timeout_ctx);
|
||||||
|
|
||||||
|
void srv_log(struct radius_session *sess, const char *fmt, ...)
|
||||||
|
PRINTF_FORMAT(2, 3);
|
||||||
|
|
||||||
|
void srv_log(struct radius_session *sess, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char *buf;
|
||||||
|
int buflen;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
buf = os_malloc(buflen);
|
||||||
|
if (buf == NULL)
|
||||||
|
return;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(buf, buflen, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
RADIUS_DEBUG("[0x%x %s] %s", sess->sess_id, sess->nas_ip, buf);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
if (sess->server->db) {
|
||||||
|
char *sql;
|
||||||
|
sql = sqlite3_mprintf("INSERT INTO authlog"
|
||||||
|
"(timestamp,session,nas_ip,username,note)"
|
||||||
|
" VALUES ("
|
||||||
|
"strftime('%%Y-%%m-%%d %%H:%%M:%%f',"
|
||||||
|
"'now'),%u,%Q,%Q,%Q)",
|
||||||
|
sess->sess_id, sess->nas_ip,
|
||||||
|
sess->username, buf);
|
||||||
|
if (sql) {
|
||||||
|
if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
|
||||||
|
NULL) != SQLITE_OK) {
|
||||||
|
RADIUS_ERROR("Failed to add authlog entry into sqlite database: %s",
|
||||||
|
sqlite3_errmsg(sess->server->db));
|
||||||
|
}
|
||||||
|
sqlite3_free(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
|
os_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct radius_client *
|
static struct radius_client *
|
||||||
radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
|
radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
|
||||||
|
@ -397,6 +452,8 @@ static void radius_server_session_free(struct radius_server_data *data,
|
||||||
radius_msg_free(sess->last_msg);
|
radius_msg_free(sess->last_msg);
|
||||||
os_free(sess->last_from_addr);
|
os_free(sess->last_from_addr);
|
||||||
radius_msg_free(sess->last_reply);
|
radius_msg_free(sess->last_reply);
|
||||||
|
os_free(sess->username);
|
||||||
|
os_free(sess->nas_ip);
|
||||||
os_free(sess);
|
os_free(sess);
|
||||||
data->num_sess--;
|
data->num_sess--;
|
||||||
}
|
}
|
||||||
|
@ -479,7 +536,7 @@ radius_server_new_session(struct radius_server_data *data,
|
||||||
static struct radius_session *
|
static struct radius_session *
|
||||||
radius_server_get_new_session(struct radius_server_data *data,
|
radius_server_get_new_session(struct radius_server_data *data,
|
||||||
struct radius_client *client,
|
struct radius_client *client,
|
||||||
struct radius_msg *msg)
|
struct radius_msg *msg, const char *from_addr)
|
||||||
{
|
{
|
||||||
u8 *user;
|
u8 *user;
|
||||||
size_t user_len;
|
size_t user_len;
|
||||||
|
@ -490,37 +547,45 @@ radius_server_get_new_session(struct radius_server_data *data,
|
||||||
|
|
||||||
RADIUS_DEBUG("Creating a new session");
|
RADIUS_DEBUG("Creating a new session");
|
||||||
|
|
||||||
user = os_malloc(256);
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &user,
|
||||||
if (user == NULL) {
|
&user_len, NULL) < 0) {
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
|
|
||||||
if (res < 0 || res > 256) {
|
|
||||||
RADIUS_DEBUG("Could not get User-Name");
|
RADIUS_DEBUG("Could not get User-Name");
|
||||||
os_free(user);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
user_len = res;
|
|
||||||
RADIUS_DUMP_ASCII("User-Name", user, user_len);
|
RADIUS_DUMP_ASCII("User-Name", user, user_len);
|
||||||
|
|
||||||
os_memset(&tmp, 0, sizeof(tmp));
|
os_memset(&tmp, 0, sizeof(tmp));
|
||||||
res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp);
|
res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp);
|
||||||
os_free(tmp.password);
|
os_free(tmp.password);
|
||||||
os_free(user);
|
|
||||||
|
|
||||||
if (res == 0) {
|
if (res != 0) {
|
||||||
RADIUS_DEBUG("Matching user entry found");
|
|
||||||
sess = radius_server_new_session(data, client);
|
|
||||||
if (sess == NULL) {
|
|
||||||
RADIUS_DEBUG("Failed to create a new session");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
sess->accept_attr = tmp.accept_attr;
|
|
||||||
} else {
|
|
||||||
RADIUS_DEBUG("User-Name not found from user database");
|
RADIUS_DEBUG("User-Name not found from user database");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RADIUS_DEBUG("Matching user entry found");
|
||||||
|
sess = radius_server_new_session(data, client);
|
||||||
|
if (sess == NULL) {
|
||||||
|
RADIUS_DEBUG("Failed to create a new session");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sess->accept_attr = tmp.accept_attr;
|
||||||
|
|
||||||
|
sess->username = os_malloc(user_len * 2 + 1);
|
||||||
|
if (sess->username == NULL) {
|
||||||
|
radius_server_session_free(data, sess);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
printf_encode(sess->username, user_len * 2 + 1, user, user_len);
|
||||||
|
|
||||||
|
sess->nas_ip = os_strdup(from_addr);
|
||||||
|
if (sess->nas_ip == NULL) {
|
||||||
|
radius_server_session_free(data, sess);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
srv_log(sess, "New session created");
|
||||||
|
|
||||||
os_memset(&eap_conf, 0, sizeof(eap_conf));
|
os_memset(&eap_conf, 0, sizeof(eap_conf));
|
||||||
eap_conf.ssl_ctx = data->ssl_ctx;
|
eap_conf.ssl_ctx = data->ssl_ctx;
|
||||||
eap_conf.msg_ctx = data->msg_ctx;
|
eap_conf.msg_ctx = data->msg_ctx;
|
||||||
|
@ -789,7 +854,8 @@ static int radius_server_request(struct radius_server_data *data,
|
||||||
from_addr, from_port);
|
from_addr, from_port);
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
sess = radius_server_get_new_session(data, client, msg);
|
sess = radius_server_get_new_session(data, client, msg,
|
||||||
|
from_addr);
|
||||||
if (sess == NULL) {
|
if (sess == NULL) {
|
||||||
RADIUS_DEBUG("Could not create a new session");
|
RADIUS_DEBUG("Could not create a new session");
|
||||||
radius_server_reject(data, client, msg, from, fromlen,
|
radius_server_reject(data, client, msg, from, fromlen,
|
||||||
|
@ -875,6 +941,10 @@ static int radius_server_request(struct radius_server_data *data,
|
||||||
|
|
||||||
if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
|
if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
|
||||||
is_complete = 1;
|
is_complete = 1;
|
||||||
|
if (sess->eap_if->eapFail)
|
||||||
|
srv_log(sess, "EAP authentication failed");
|
||||||
|
else if (sess->eap_if->eapSuccess)
|
||||||
|
srv_log(sess, "EAP authentication succeeded");
|
||||||
|
|
||||||
reply = radius_server_encapsulate_eap(data, client, sess, msg);
|
reply = radius_server_encapsulate_eap(data, client, sess, msg);
|
||||||
|
|
||||||
|
@ -889,10 +959,12 @@ static int radius_server_request(struct radius_server_data *data,
|
||||||
|
|
||||||
switch (radius_msg_get_hdr(reply)->code) {
|
switch (radius_msg_get_hdr(reply)->code) {
|
||||||
case RADIUS_CODE_ACCESS_ACCEPT:
|
case RADIUS_CODE_ACCESS_ACCEPT:
|
||||||
|
srv_log(sess, "Sending Access-Accept");
|
||||||
data->counters.access_accepts++;
|
data->counters.access_accepts++;
|
||||||
client->counters.access_accepts++;
|
client->counters.access_accepts++;
|
||||||
break;
|
break;
|
||||||
case RADIUS_CODE_ACCESS_REJECT:
|
case RADIUS_CODE_ACCESS_REJECT:
|
||||||
|
srv_log(sess, "Sending Access-Reject");
|
||||||
data->counters.access_rejects++;
|
data->counters.access_rejects++;
|
||||||
client->counters.access_rejects++;
|
client->counters.access_rejects++;
|
||||||
break;
|
break;
|
||||||
|
@ -1502,6 +1574,17 @@ radius_server_init(struct radius_server_conf *conf)
|
||||||
os_strdup(conf->subscr_remediation_url);
|
os_strdup(conf->subscr_remediation_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
if (conf->sqlite_file) {
|
||||||
|
if (sqlite3_open(conf->sqlite_file, &data->db)) {
|
||||||
|
RADIUS_ERROR("Could not open SQLite file '%s'",
|
||||||
|
conf->sqlite_file);
|
||||||
|
radius_server_deinit(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
#ifdef CONFIG_RADIUS_TEST
|
#ifdef CONFIG_RADIUS_TEST
|
||||||
if (conf->dump_msk_file)
|
if (conf->dump_msk_file)
|
||||||
data->dump_msk_file = os_strdup(conf->dump_msk_file);
|
data->dump_msk_file = os_strdup(conf->dump_msk_file);
|
||||||
|
@ -1589,6 +1672,12 @@ void radius_server_deinit(struct radius_server_data *data)
|
||||||
os_free(data->dump_msk_file);
|
os_free(data->dump_msk_file);
|
||||||
#endif /* CONFIG_RADIUS_TEST */
|
#endif /* CONFIG_RADIUS_TEST */
|
||||||
os_free(data->subscr_remediation_url);
|
os_free(data->subscr_remediation_url);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SQLITE
|
||||||
|
if (data->db)
|
||||||
|
sqlite3_close(data->db);
|
||||||
|
#endif /* CONFIG_SQLITE */
|
||||||
|
|
||||||
os_free(data);
|
os_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,11 @@ struct radius_server_conf {
|
||||||
*/
|
*/
|
||||||
char *client_file;
|
char *client_file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sqlite_file - SQLite database for storing debug log information
|
||||||
|
*/
|
||||||
|
const char *sqlite_file;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* conf_ctx - Context pointer for callbacks
|
* conf_ctx - Context pointer for callbacks
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue