From: jcarneal Date: Tue, 16 Jan 2001 22:26:55 +0000 (+0000) Subject: The humble beginnings of ODBC support for FreeRadius. X-Git-Tag: release_0_1_0~275 X-Git-Url: http://www.project-moonshot.org/gitweb/?a=commitdiff_plain;h=96010d95b5bfea02519011a27fb330c78bb1f21f;p=freeradius.git The humble beginnings of ODBC support for FreeRadius. Currently it works for accounting only. Auth will be added shortly, after a much needed discussion on the list about the future of the SQL module. This driver requires libiodbc available from www.iodbc.org. However, it *should* be ODBC 2.5 compliant and require very minor changes to work with another ODBC library. --- diff --git a/src/modules/rlm_sql/drivers/rlm_sql_iodbc/sql_iodbc.c b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/sql_iodbc.c new file mode 100644 index 0000000..be3bac1 --- /dev/null +++ b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/sql_iodbc.c @@ -0,0 +1,298 @@ +/*************************************************************************** +* iODBC support for FreeRadius +* www.iodbc.org - iODBC info +* Jeff Carneal - Author +***************************************************************************/ +#include +#include +#include +#include + +#include "radiusd.h" +#include "rlm_sql.h" + +/************************************************************************* + * + * Function: sql_create_socket + * + * Purpose: Establish connection to the db + * + *************************************************************************/ +SQLSOCK *sql_create_socket(SQL_INST *inst) +{ + SQLSOCK *socket; + + if((socket = malloc(sizeof(SQLSOCK))) == NULL) { + radlog(L_CONS|L_ERR, "sql_create_socket: no memory"); + exit(1); + } + + if(SQLAllocEnv(&socket->env_handle) != SQL_SUCCESS) { + radlog(L_CONS|L_ERR, "sql_create_socket: SQLAllocEnv failed: %s", + sql_error(socket)); + exit(1); + } + + if(SQLAllocConnect(socket->env_handle, &socket->dbc_handle) != SQL_SUCCESS) { + radlog(L_CONS|L_ERR, "sql_create_socket: SQLAllocConnect failed: %s", + sql_error(socket)); + exit(1); + } + + if (SQLConnect(socket->dbc_handle, inst->config->sql_db, SQL_NTS, + inst->config->sql_login, SQL_NTS, inst->config->sql_password, + SQL_NTS) != SQL_SUCCESS) { + radlog(L_CONS|L_ERR, "sql_create_socket: SQLConnectfailed: %s", + sql_error(socket)); + exit(1); + } + + if(SQLAllocStmt(socket->dbc_handle, &socket->stmt_handle) != SQL_SUCCESS) { + radlog(L_CONS|L_ERR, "sql_create_socket: SQLAllocStmt failed: %s", + sql_error(socket)); + exit(1); + } + + return socket; +} + +/************************************************************************* + * + * Function: sql_query + * + * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to + * the database. + * + *************************************************************************/ +int sql_query(SQL_INST *inst, SQLSOCK *socket, char *querystr) +{ + if (inst->config->sqltrace) + DEBUG(querystr); + if (socket->dbc_handle == NULL) { + radlog(L_ERR, "sql_query: Socket not connected"); + return 0; + } + + if(SQLExecDirect(socket->stmt_handle, querystr, SQL_NTS) != SQL_SUCCESS) { + radlog(L_CONS|L_ERR, "sql_query: failed: %s", + sql_error(socket)); + return -1; + } + + return 0; +} + + +/************************************************************************* + * + * Function: sql_select_query + * + * Purpose: Issue a select query to the database + * + *************************************************************************/ +int sql_select_query(SQL_INST *inst, SQLSOCK *socket, char *querystr) +{ + return 0; +} + + +/************************************************************************* + * + * Function: sql_store_result + * + * Purpose: database specific store_result function. Returns a result + * set for the query. + * + *************************************************************************/ +int sql_store_result(SQLSOCK *socket) { + return 0; +} + + +/************************************************************************* + * + * Function: sql_num_fields + * + * Purpose: database specific num_fields function. Returns number + * of columns from query + * + *************************************************************************/ +int sql_num_fields(SQLSOCK *socket) { + return 0; +} + +/************************************************************************* + * + * Function: sql_num_rows + * + * Purpose: database specific num_rows. Returns number of rows in + * query + * + *************************************************************************/ +int sql_num_rows(SQLSOCK *socket) { + return 0; +} + + +/************************************************************************* + * + * Function: sql_fetch_row + * + * Purpose: database specific fetch_row. Returns a SQL_ROW struct + * with all the data for the query + * + *************************************************************************/ +SQL_ROW sql_fetch_row(SQLSOCK *socket) +{ + return 0; +} + + + +/************************************************************************* + * + * Function: sql_free_result + * + * Purpose: database specific free_result. Frees memory allocated + * for a result set + * + *************************************************************************/ +void sql_free_result(SQLSOCK *socket) { +} + + + +/************************************************************************* + * + * Function: sql_error + * + * Purpose: database specific error. Returns error associated with + * connection + * + *************************************************************************/ +char *sql_error(SQLSOCK *socket) +{ + SQLINTEGER errornum = 0; + SQLSMALLINT length = 0; + SQLCHAR state[256] = ""; + static SQLCHAR error[256] = ""; + + SQLError(socket->env_handle, socket->dbc_handle, socket->stmt_handle, + state, &errornum, error, 256, &length); + return error; +} + + +/************************************************************************* + * + * Function: sql_close + * + * Purpose: database specific close. Closes an open database + * connection and cleans up any open handles. + * + *************************************************************************/ +void sql_close(SQLSOCK *socket) +{ + + SQLFreeStmt(socket->stmt_handle, SQL_DROP); + SQLDisconnect(socket->dbc_handle); + SQLFreeConnect(socket->dbc_handle); + SQLFreeEnv(socket->env_handle); + + socket->stmt_handle = NULL; + socket->dbc_handle = NULL; + socket->env_handle = NULL; +} + + +/************************************************************************* + * + * Function: sql_finish_query + * + * Purpose: End the query, such as freeing memory + * + *************************************************************************/ +void sql_finish_query(SQLSOCK *socket) +{ +} + + + +/************************************************************************* + * + * Function: sql_finish_select_query + * + * Purpose: End the select query, such as freeing memory or result + * + *************************************************************************/ +void sql_finish_select_query(SQLSOCK *socket) +{ +} + + +/************************************************************************* + * + * Function: sql_affected_rows + * + * Purpose: Return the number of rows affected by the query (update, + * or insert) + * + *************************************************************************/ +int sql_affected_rows(SQLSOCK *socket) { + SQLINTEGER count; + + SQLRowCount(socket->stmt_handle, &count); + return (int)count; +} + + +/************************************************************************* + * + * Function: sql_escape_string + * + * Purpose: Esacpe "'" and any other wierd charactors + * + *************************************************************************/ +int sql_escape_string(char *to, char *from, int length) +{ + int x, y; + + for(x=0, y=0; (x < length) && (from[x]!='\0'); x++) { + switch (from[x]) { + case 0: + to[y++]= '\\'; + to[y++]= '0'; + break; + case '\n': + to[y++]= '\\'; + to[y++]= 'n'; + break; + case '\r': + to[y++]= '\\'; + to[y++]= 'r'; + break; + case '\\': + to[y++]= '\\'; + to[y++]= '\\'; + break; + case '\'': + to[y++]= '\\'; + to[y++]= '\''; + break; + case '"': + to[y++]= '\\'; + to[y++]= '"'; + break; + case '\032': + to[y++]= '\\'; + to[y++]= 'Z'; + break; + default: + to[y++]= from[x]; + } + } + to[y]=0; + + return 1; +} + diff --git a/src/modules/rlm_sql/drivers/rlm_sql_iodbc/sql_iodbc.h b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/sql_iodbc.h new file mode 100644 index 0000000..a84fe3e --- /dev/null +++ b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/sql_iodbc.h @@ -0,0 +1,76 @@ +/*************************************************************************** +* iODBC support for FreeRadius +* www.iodbc.org - iODBC info +* Jeff Carneal - Author +***************************************************************************/ +#if HAVE_PTHREAD_H +#include +#include +#endif +#include +#include +#include +#include "conf.h" + +typedef char** SQL_ROW; + +typedef struct sql_socket { + HENV env_handle; + HDBC dbc_handle; + HSTMT stmt_handle; + int id; +#if HAVE_PTHREAD_H + sem_t *semaphore; +#else + int in_use; +#endif + struct sql_socket *next; +} SQLSOCK; + +typedef struct sql_config { + char *sql_server; + char *sql_login; + char *sql_password; + char *sql_db; + char *sql_acct_table; + char *sql_authcheck_table; + char *sql_authreply_table; + char *sql_groupcheck_table; + char *sql_groupreply_table; + char *sql_usergroup_table; + char *sql_realm_table; + char *sql_realmgroup_table; + char *sql_nas_table; + char *sql_dict_table; + int sensitiveusername; + int sqltrace; + char *tracefile; + int deletestalesessions; + int num_sql_socks; +} SQL_CONFIG; + +typedef struct sql_inst { + int used; + SQLSOCK *sqlpool; + SQL_CONFIG *config; +#if HAVE_PTHREAD_H + pthread_mutex_t *lock; + pthread_cond_t *notfull; +#endif +} SQL_INST; + +SQLSOCK *sql_create_socket(SQL_INST *inst); +int sql_checksocket(const char *facility); +int sql_query(SQL_INST *inst, SQLSOCK *sqlsocket, char *querystr); +int sql_select_query(SQL_INST *inst, SQLSOCK *sqlsocket, char *querystr); +int sql_store_result(SQLSOCK *sqlsocket); +int sql_num_fields(SQLSOCK *sqlsocket); +int sql_num_rows(SQLSOCK *sqlsocket); +SQL_ROW sql_fetch_row(SQLSOCK *sqlsocket); +void sql_free_result(SQLSOCK *sqlsocket); +char *sql_error(SQLSOCK *sqlsocket); +void sql_close(SQLSOCK *sqlsocket); +void sql_finish_query(SQLSOCK *sqlsocket); +void sql_finish_select_query(SQLSOCK *sqlsocket); +int sql_affected_rows(SQLSOCK *sqlsocket); +int sql_escape_string(char *to, char *from, int length);