*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * Copyright 2000 The FreeRADIUS server project
+ * Copyright 2000,2006 The FreeRADIUS server project
* Copyright 2000 Mike Machado <mike@innercite.com>
* Copyright 2000 Alan DeKok <aland@ox.org>
*/
-#include <stdio.h>
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
#include <sys/stat.h>
-#include <stdlib.h>
-#include <string.h>
-#include "radiusd.h"
-#include "sql_mysql.h"
+#include "config.h"
+
+#ifdef HAVE_MYSQL_MYSQL_H
+#include <mysql/mysql_version.h>
+#include <mysql/errmsg.h>
+#include <mysql/mysql.h>
+#else
+#ifdef HAVE_MYSQL_H
+#include <mysql_version.h>
+#include <errmsg.h>
+#include <mysql.h>
+#endif
+#endif
+
+#include "rlm_sql.h"
+typedef struct rlm_sql_mysql_sock {
+ MYSQL conn;
+ MYSQL *sock;
+ MYSQL_RES *result;
+ SQL_ROW row;
+} rlm_sql_mysql_sock;
/*************************************************************************
*
* Purpose: Establish connection to the db
*
*************************************************************************/
-int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
-
+static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
+{
rlm_sql_mysql_sock *mysql_sock;
- sqlsocket->conn = (rlm_sql_mysql_sock *)rad_malloc(sizeof(rlm_sql_mysql_sock));
-
+ if (!sqlsocket->conn) {
+ sqlsocket->conn = (rlm_sql_mysql_sock *)rad_malloc(sizeof(rlm_sql_mysql_sock));
+ if (!sqlsocket->conn) {
+ return -1;
+ }
+ }
mysql_sock = sqlsocket->conn;
+ memset(mysql_sock, 0, sizeof(*mysql_sock));
+
+ radlog(L_INFO, "rlm_sql_mysql: Starting connect to MySQL server for #%d",
+ sqlsocket->id);
mysql_init(&(mysql_sock->conn));
- if (!(mysql_sock->sock = mysql_real_connect(&(mysql_sock->conn), config->sql_server, config->sql_login, config->sql_password,
- config->sql_db, 0, NULL, CLIENT_FOUND_ROWS))) {
- radlog(L_ERR, "rlm_sql: Couldn't connect socket to MySQL server %s@%s:%s", config->sql_login, config->sql_server, config->sql_db);
- radlog(L_ERR, "rlm_sql: Mysql error '%s'", mysql_error(&mysql_sock->conn));
+ mysql_options(&(mysql_sock->conn), MYSQL_READ_DEFAULT_GROUP, "freeradius");
+ if (!(mysql_sock->sock = mysql_real_connect(&(mysql_sock->conn),
+ config->sql_server,
+ config->sql_login,
+ config->sql_password,
+ config->sql_db,
+ atoi(config->sql_port),
+ NULL,
+ CLIENT_FOUND_ROWS))) {
+ radlog(L_ERR, "rlm_sql_mysql: Couldn't connect socket to MySQL server %s@%s:%s", config->sql_login, config->sql_server, config->sql_db);
+ radlog(L_ERR, "rlm_sql_mysql: Mysql error '%s'", mysql_error(&mysql_sock->conn));
mysql_sock->sock = NULL;
return -1;
}
* Purpose: Free socket and any private connection data
*
*************************************************************************/
-int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
-
- rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
-
- free(mysql_sock);
- free(sqlsocket);
+static int sql_destroy_socket(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config)
+{
+ free(sqlsocket->conn);
+ sqlsocket->conn = NULL;
return 0;
}
/*************************************************************************
*
- * Function: sql_query
+ * Function: sql_check_error
*
- * Purpose: Issue a query to the database
+ * Purpose: check the error to see if the server is down
*
*************************************************************************/
-int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr) {
-
- rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
-
- if (config->sqltrace)
- radlog(L_DBG,"query: %s", querystr);
- if (mysql_sock->sock == NULL) {
- radlog(L_ERR, "Socket not connected");
- return -1;
- }
- if (mysql_query(mysql_sock->sock, querystr) == 0) {
+static int sql_check_error(int error)
+{
+ switch(error) {
+ case CR_SERVER_GONE_ERROR:
+ case CR_SERVER_LOST:
+ case -1:
+ radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d, returning SQL_DOWN", error);
+ return SQL_DOWN;
+ break;
+ case 0:
return 0;
- } else {
+ break;
+ case CR_OUT_OF_MEMORY:
+ case CR_COMMANDS_OUT_OF_SYNC:
+ case CR_UNKNOWN_ERROR:
+ default:
+ radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d received", error);
return -1;
+ break;
}
}
/*************************************************************************
*
- * Function: sql_select_query
+ * Function: sql_query
*
- * Purpose: Issue a select query to the database
+ * Purpose: Issue a query to the database
*
*************************************************************************/
-int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
-
+static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
+{
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
if (config->sqltrace)
- radlog(L_DBG,querystr);
+ radlog(L_DBG,"rlm_sql_mysql: query: %s", querystr);
if (mysql_sock->sock == NULL) {
- radlog(L_ERR, "Socket not connected");
- return -1;
+ radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
+ return SQL_DOWN;
}
+
mysql_query(mysql_sock->sock, querystr);
- if (sql_store_result(sqlsocket, config) < 0 || sql_num_fields(sqlsocket, config) < 0)
- return -1;
- else
- return 0;
+ return sql_check_error(mysql_errno(mysql_sock->sock));
}
* set for the query.
*
*************************************************************************/
-int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_store_result(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
if (mysql_sock->sock == NULL) {
- radlog(L_ERR, "Socket not connected");
- return -1;
+ radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
+ return SQL_DOWN;
}
if (!(mysql_sock->result = mysql_store_result(mysql_sock->sock))) {
- radlog(L_ERR, "MYSQL Error: Cannot get result");
- radlog(L_ERR, "MYSQL Error: %s", mysql_error(mysql_sock->sock));
- return -1;
+ radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: Cannot get result");
+ radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: %s",
+ mysql_error(mysql_sock->sock));
+ return sql_check_error(mysql_errno(mysql_sock->sock));
}
return 0;
-
}
* of columns from query
*
*************************************************************************/
-int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
-
+static int sql_num_fields(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
int num = 0;
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
#else
if (!(num = mysql_num_fields(mysql_sock->sock))) {
#endif
- radlog(L_ERR, "MYSQL Error: Cannot get result");
- radlog(L_ERR, "MYSQL error: %s", mysql_error(mysql_sock->sock));
+ radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: No Fields");
+ radlog(L_ERR, "rlm_sql_mysql: MYSQL error: %s",
+ mysql_error(mysql_sock->sock));
}
return num;
}
/*************************************************************************
*
+ * Function: sql_select_query
+ *
+ * Purpose: Issue a select query to the database
+ *
+ *************************************************************************/
+static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config,
+ char *querystr)
+{
+ int ret;
+
+ ret = sql_query(sqlsocket, config, querystr);
+ if(ret)
+ return ret;
+ ret = sql_store_result(sqlsocket, config);
+ if (ret) {
+ return ret;
+ }
+
+ /* Why? Per http://www.mysql.com/doc/n/o/node_591.html,
+ * this cannot return an error. Perhaps just to complain if no
+ * fields are found?
+ */
+ sql_num_fields(sqlsocket, config);
+
+ return ret;
+}
+
+
+/*************************************************************************
+ *
* Function: sql_num_rows
*
* Purpose: database specific num_rows. Returns number of rows in
* query
*
*************************************************************************/
-int sql_num_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_num_rows(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
- return mysql_num_rows(mysql_sock->result);
+ if (mysql_sock->result)
+ return mysql_num_rows(mysql_sock->result);
+
+ return 0;
}
* Function: sql_fetch_row
*
* Purpose: database specific fetch_row. Returns a SQL_ROW struct
- * with all the data for the query
+ * with all the data for the query in 'sqlsocket->row'. Returns
+ * 0 on success, -1 on failure, SQL_DOWN if database is down.
*
*************************************************************************/
-SQL_ROW sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_fetch_row(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
- return mysql_fetch_row(mysql_sock->result);
-}
+ /*
+ * Check pointer before de-referencing it.
+ */
+ if (!mysql_sock->result) {
+ return SQL_DOWN;
+ }
+
+ sqlsocket->row = mysql_fetch_row(mysql_sock->result);
+ if (sqlsocket->row == NULL) {
+ return sql_check_error(mysql_errno(mysql_sock->sock));
+ }
+ return 0;
+}
/*************************************************************************
* for a result set
*
*************************************************************************/
-int sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_free_result(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
if (mysql_sock->result) {
mysql_free_result(mysql_sock->result);
+ mysql_sock->result = NULL;
}
return 0;
* connection
*
*************************************************************************/
-char *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static char *sql_error(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
+ if (mysql_sock == NULL || mysql_sock->sock == NULL) {
+ return "rlm_sql_mysql: no connection to db";
+ }
return mysql_error(mysql_sock->sock);
}
* connection
*
*************************************************************************/
-int sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_close(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
- mysql_close(mysql_sock->sock);
- mysql_sock->sock = NULL;
+ if (mysql_sock && mysql_sock->sock){
+ mysql_close(mysql_sock->sock);
+ mysql_sock->sock = NULL;
+ }
return 0;
}
* Purpose: End the query, such as freeing memory
*
*************************************************************************/
-int sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_finish_query(UNUSED SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
return 0;
}
* Purpose: End the select query, such as freeing memory or result
*
*************************************************************************/
-int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
+{
sql_free_result(sqlsocket, config);
return 0;
* Purpose: End the select query, such as freeing memory or result
*
*************************************************************************/
-int sql_affected_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
-
+static int sql_affected_rows(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
+{
rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
return mysql_affected_rows(mysql_sock->sock);
}
-/*************************************************************************
- *
- * Function: sql_escape_string
- *
- * Purpose: Esacpe "'" and any other wierd charactors
- *
- *************************************************************************
- * Unused. Now provided in rlm_sql main module.
- * But left in here just in case...
- *
-int sql_escape_string(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *to, char *from, int length) {
-
- mysql_escape_string(to, from, length);
- return 0;
-}
-*/
-
-
/* Exported to rlm_sql */
rlm_sql_module_t rlm_sql_mysql = {
"rlm_sql_mysql",