-/***************************************************************************
-* sql_sybase.c rlm_sql - FreeRADIUS SQL Module *
-* *
-* Sybase (ctlibrary) routines for rlm_sql *
-* *
-* Error handling stolen from Sybase example code "firstapp.c" *
-* *
-* Mattias Sjostrom <mattias@nogui.se> *
-***************************************************************************/
-
-#include <stdio.h>
+/*
+ * sql_sybase.c Sybase (ctlibrary) routines for rlm_sql
+ * Error handling stolen from Sybase example code "firstapp.c"
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Mattias Sjostrom <mattias@nogui.se>
+ */
+
+#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_sybase.h"
+#include <ctpublic.h>
+#include "rlm_sql.h"
+
+
+typedef struct rlm_sql_sybase_sock {
+ CS_CONTEXT *context;
+ CS_CONNECTION *connection;
+ CS_COMMAND *command;
+ char **results;
+ int id;
+ int in_use;
+ struct timeval tv;
+} rlm_sql_sybase_sock;
+
#define MAX_DATASTR_LEN 256
* routine when it receives a message from the server.
************************************************************************/
-CS_RETCODE CS_PUBLIC
+static CS_RETCODE CS_PUBLIC
servermsg_callback(cp, chp, msgp)
CS_CONTEXT *cp;
CS_CONNECTION *chp;
* Client-Library error handler.
************************************************************************/
-CS_RETCODE CS_PUBLIC
+static CS_RETCODE CS_PUBLIC
clientmsg_callback(context, conn, emsgp)
CS_CONTEXT *context;
CS_CONNECTION *conn;
* when CS-Library has detected an error.
************************************************************************/
-CS_RETCODE CS_PUBLIC
+static CS_RETCODE CS_PUBLIC
csmsg_callback(context, emsgp)
CS_CONTEXT *context;
CS_CLIENTMSG *emsgp;
* Purpose: Establish connection to the db
*
*************************************************************************/
-int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
-
- rlm_sql_sybase_sock *sybase_sock;
+static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+ rlm_sql_sybase_sock *sybase_sock;
- sqlsocket->conn = (rlm_sql_sybase_sock *)rad_malloc(sizeof(rlm_sql_sybase_sock));
+ if (!sqlsocket->conn) {
+ sqlsocket->conn = (rlm_sql_sybase_sock *)rad_malloc(sizeof(rlm_sql_sybase_sock));
+ if (!sqlsocket->conn) {
+ return -1;
+ }
+ }
sybase_sock = sqlsocket->conn;
+ memset(sybase_sock, 0, sizeof(*sybase_sock));
sybase_sock->results=NULL;
}
return -1;
}
-
+
/* Allocate a ctlib connection structure */
if (ct_con_alloc(sybase_sock->context, &sybase_sock->connection) != CS_SUCCEED) {
cs_ctx_drop(sybase_sock->context);
}
return -1;
- }
+ }
/* Initialize inline error handling for the connection */
-
+
/* if (ct_diag(sybase_sock->connection, CS_INIT, CS_UNUSED, CS_UNUSED, NULL) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize error handling (ct_diag())");
if (sybase_sock->context != (CS_CONTEXT *)NULL) {
return -1;
}
- if (ct_con_props(sybase_sock->connection, CS_SET, CS_PASSWORD, config->sql_password,
+ if (ct_con_props(sybase_sock->connection, CS_SET, CS_PASSWORD, config->sql_password,
strlen(config->sql_password), NULL) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to set password for connection (ct_con_props())\n%s",
sql_error(sqlsocket, config));
* Purpose: Free socket and private connection data
*
*************************************************************************/
-int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
-
- /* Why bother, rlm_sql never calls sql_destroy_socket anyway */
-
+static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
+{
+ free(sqlsocket->conn);
+ sqlsocket->conn = NULL;
return 0;
}
* the database.
*
*************************************************************************/
-int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
+static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
sql_error(sqlsocket, config));
return -1;
}
-
+
if (ct_send(sybase_sock->command) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to send command (ct_send())\n%s",
sql_error(sqlsocket, config));
** we need returncode CS_SUCCEED
** and result_type CS_CMD_SUCCEED.
*/
-
+
if ((results_ret = ct_results(sybase_sock->command, &result_type)) == CS_SUCCEED) {
if (result_type != CS_CMD_SUCCEED) {
if (result_type == CS_ROW_RESULT) {
- radlog(L_ERR,"rlm_sql_sybase(sql_query): sql_query processed a query returning rows.
- Use sql_select_query instead!");
+ radlog(L_ERR,"rlm_sql_sybase(sql_query): sql_query processed a query returning rows. Use sql_select_query instead!");
}
radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected result type from query\n%s",
sql_error(sqlsocket, config));
return -1;
}
- }
+ }
else {
switch ((int) results_ret)
{
** we need returncode CS_SUCCEED
** and result_type CS_CMD_DONE.
*/
-
+
if ((results_ret = ct_results(sybase_sock->command, &result_type)) == CS_SUCCEED) {
if (result_type != CS_CMD_DONE) {
radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected result type from query\n%s",
sql_error(sqlsocket, config));
return -1;
}
- }
+ }
else {
switch ((int) results_ret)
{
** we need returncode CS_END_RESULTS
** result_type will be ignored.
*/
-
+
results_ret = ct_results(sybase_sock->command, &result_type);
switch ((int) results_ret)
*
* Purpose: Issue a select query to the database
*
- * Note: Only the first row from queries returning several rows
+ * Note: Only the first row from queries returning several rows
* will be returned by this function, consequitive rows will
* be discarded.
*
*************************************************************************/
-int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
-
+static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
+
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
CS_RETCODE ret, results_ret;
radlog(L_ERR, "Socket not connected");
return -1;
}
-
+
if (ct_cmd_alloc(sybase_sock->connection, &sybase_sock->command) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to allocate command structure (ct_cmd_alloc())\n%s",
sql_error(sqlsocket, config));
return -1;
}
-
+
if (ct_send(sybase_sock->command) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to send command (ct_send())\n%s",
sql_error(sqlsocket, config));
case CS_SUCCEED:
- switch (result_type) {
+ switch (result_type) {
case CS_ROW_RESULT:
/*
** Set up the DATAFMT structure that describes our target array
** and tells sybase what we want future ct_fetch calls to do.
- */
+ */
descriptor.datatype = CS_CHAR_TYPE; /* The target buffer is a string */
- descriptor.format = CS_FMT_NULLTERM; /* Null termination please */
+ descriptor.format = CS_FMT_NULLTERM; /* Null termination please */
descriptor.maxlength = MAX_DATASTR_LEN; /* The string arrays are this large */
descriptor.count = 1; /* Fetch one row of data */
descriptor.locale = NULL; /* Don't do NLS stuff */
for (i=0; i < colcount; i++) {
rowdata[i]=rad_malloc((MAX_DATASTR_LEN * sizeof(char))+1); /* Space to hold the result data */
-
+
/* Associate the target buffer with the data */
if (ct_bind(sybase_sock->command, i+1, &descriptor, rowdata[i], NULL, NULL) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_select_query): ct_bind() failed)\n%s",
break;
}
break;
-
- case CS_FAIL:
+
+ case CS_FAIL:
/*
** Serious failure, sybase requires us to cancel
break;
default:
-
+
radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unexpected return value from ct_results()\n%s",
sql_error(sqlsocket, config));
return -1;
* set for the query.
*
*************************************************************************/
-int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
- /*
+static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+ /*
** Not needed for Sybase, code that may have gone here is
** in sql_select_query and sql_fetch_row
*/
* of columns from query
*
*************************************************************************/
-int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
-
+static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
int num;
* query
*
*************************************************************************/
-int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
int num;
break;
case CS_ROW_FAIL:
-
+
radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Recoverable failure fething row data, try again perhaps?");
return -1;
default:
-
+
radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Unexpected returncode from ct_fetch");
return -1;
break;
* for a result set
*
*************************************************************************/
-int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
/*
** Not implemented, never called from rlm_sql anyway
** result buffer is freed in the finish_query functions.
- */
+ */
return 0;
* connection
*
*************************************************************************/
-char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
static char msg='\0';
/*
static char msgbuf[2048];
cmsg.msgstring);
}
-
+
if (ct_diag(sybase_sock->connection, CS_STATUS, CS_SERVERMSG_TYPE, CS_UNUSED, &msgcount) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to get number of pending Server messages");
return msgbuf;
return msgbuf;
*/
- return &msg;
+ return &msg;
}
* connection and cleans up any open handles.
*
*************************************************************************/
-int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
/*
rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
* Purpose: End the query, such as freeing memory
*
*************************************************************************/
-int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config)
+static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config)
{
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
* 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) {
+
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
int i=0;
free(sybase_sock->results);
sybase_sock->results=NULL;
}
-
+
return 0;
}
* or insert)
*
*************************************************************************/
-int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
+static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
return sql_num_rows(sqlsocket, config);