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:
Jouni Malinen 2014-02-28 14:11:13 +02:00 committed by Jouni Malinen
parent f3ef7a2640
commit 8a57da7e28
4 changed files with 123 additions and 20 deletions

View file

@ -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
);

View file

@ -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 */

View file

@ -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);
} }

View file

@ -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
* *