27 RCSID(
"$Id: 79bb8e20596127214fdbefce24aed84675523aef $")
29 #define LOG_PREFIX "sql - freetds"
31 #include <freeradius-devel/server/base.h>
32 #include <freeradius-devel/util/debug.h>
50 #define MAX_DATASTR_LEN 256
70 if (emsgp->severity == CS_SV_INFORM) {
71 INFO(
"%s", emsgp->msgstring);
76 if ((cs_config(
context, CS_GET, CS_USERDATA, &
this,
sizeof(
this), &len) != CS_SUCCEED) || !
this) {
77 ERROR(
"failed retrieving context userdata");
82 if (this->error) TALLOC_FREE(this->error);
84 this->error =
talloc_typed_asprintf(
this,
"client error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
85 (
long)CS_SEVERITY(emsgp->severity), (
long)CS_NUMBER(emsgp->msgnumber),
86 (
long)CS_ORIGIN(emsgp->msgnumber), (
long)CS_LAYER(emsgp->msgnumber),
89 if (emsgp->osstringlen > 0) {
90 this->error = talloc_asprintf_append(this->error,
". os error: number(%ld): %s",
91 (
long)emsgp->osnumber, emsgp->osstring);
114 if (emsgp->severity == CS_SV_INFORM) {
115 INFO(
"%s", emsgp->msgstring);
120 if ((cs_config(
context, CS_GET, CS_USERDATA, &
this,
sizeof(
this), &len) != CS_SUCCEED) || !
this) {
121 ERROR(
"failed retrieving context userdata");
126 if (this->error) TALLOC_FREE(this->error);
128 this->error =
talloc_typed_asprintf(
this,
"cs error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
129 (
long)CS_SEVERITY(emsgp->severity), (
long)CS_NUMBER(emsgp->msgnumber),
130 (
long)CS_ORIGIN(emsgp->msgnumber), (
long)CS_LAYER(emsgp->msgnumber),
133 if (emsgp->osstringlen > 0) {
134 this->error = talloc_asprintf_append(this->error,
". os error: number(%ld): %s",
135 (
long)emsgp->osnumber, emsgp->osstring);
158 if ((cs_config(
context, CS_GET, CS_USERDATA, &
this,
sizeof(
this), &len) != CS_SUCCEED) || !
this) {
159 ERROR(
"failed retrieving context userdata");
167 if (this->established) {
168 INFO(
"server msg from \"%s\": severity(%ld), number(%ld), origin(%ld), "
169 "layer(%ld), procedure \"%s\": %s",
170 (msgp->svrnlen > 0) ? msgp->svrname :
"unknown",
171 (
long)msgp->msgnumber, (
long)msgp->severity, (
long)msgp->state, (
long)msgp->line,
172 (msgp->proclen > 0) ? msgp->proc :
"none", msgp->text);
174 if (this->error) TALLOC_FREE(this->error);
177 "origin(%ld), layer(%ld), procedure \"%s\": %s",
178 (msgp->svrnlen > 0) ? msgp->svrname :
"unknown",
179 (
long)msgp->msgnumber, (
long)msgp->severity, (
long)msgp->state,
181 (msgp->proclen > 0) ? msgp->proc :
"none", msgp->text);
199 CS_RETCODE results_ret;
208 if (ct_cmd_alloc(conn->
db, &conn->
command) != CS_SUCCEED) {
209 ERROR(
"Unable to allocate command structure (ct_cmd_alloc())");
214 if (ct_command(conn->
command, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
215 ERROR(
"Unable to initialise command structure (ct_command())");
220 if (ct_send(conn->
command) != CS_SUCCEED) {
221 ERROR(
"Unable to send command (ct_send())");
234 if ((results_ret = ct_results(conn->
command, &result_type)) == CS_SUCCEED) {
235 if (result_type != CS_CMD_SUCCEED) {
236 if (result_type == CS_ROW_RESULT) {
237 ERROR(
"sql_query processed a query returning rows. "
238 "Use sql_select_query instead!");
240 ERROR(
"Result failure or unexpected result type from query");
245 switch (results_ret) {
247 ERROR(
"Failure retrieving query results");
249 if (ct_cancel(NULL, conn->
command, CS_CANCEL_ALL) == CS_FAIL) {
258 ERROR(
"Unexpected return value from ct_results()");
269 if (ct_res_info(conn->
command, CS_ROW_COUNT, &conn->
rows_affected, CS_UNUSED, NULL) != CS_SUCCEED) {
270 ERROR(
"rlm_sql_freetds: error retrieving row count");
279 if ((results_ret = ct_results(conn->
command, &result_type)) == CS_SUCCEED) {
280 if (result_type != CS_CMD_DONE) {
281 ERROR(
"Result failure or unexpected result type from query");
286 switch (results_ret) {
288 ERROR(
"Failure retrieving query results");
295 ERROR(
"Unexpected return value from ct_results()");
304 results_ret = ct_results(conn->
command, &result_type);
305 switch (results_ret) {
307 ERROR(
"Failure retrieving query results");
317 ERROR(
"Unexpected return value from ct_results()");
338 if (ct_res_info(conn->
command, CS_NUMDATA, &num, CS_UNUSED, NULL) != CS_SUCCEED) {
339 ERROR(
"Error retrieving column count");
362 if (ct_res_info(conn->
command, CS_NUMDATA, (CS_INT *)&fields, CS_UNUSED, NULL) != CS_SUCCEED) {
363 ERROR(
"sql_fields() Error retrieving column count");
370 MEM(
names = talloc_array(handle,
char const *, fields));
372 for (i = 0; i < fields; i++) {
380 if (ct_describe(conn->
command, col, &datafmt) != CS_SUCCEED) {
381 ERROR(
"sql_fields() Problems with ct_describe(), column %d", col);
386 if (datafmt.namelen > 0) {
387 MEM(p = talloc_array(
names,
char, (
size_t)datafmt.namelen + 1));
388 strlcpy(p, datafmt.name, (
size_t)datafmt.namelen + 1);
417 if (!conn->
error)
return 0;
429 ct_cancel(NULL, conn->
command, CS_CANCEL_ALL);
430 if (ct_cmd_drop(conn->
command) != CS_SUCCEED) {
431 ERROR(
"freeing command structure failed");
453 CS_RETCODE results_ret;
455 CS_DATAFMT descriptor;
461 ERROR(
"socket not connected");
466 if (ct_cmd_alloc(conn->
db, &conn->
command) != CS_SUCCEED) {
467 ERROR(
"unable to allocate command structure (ct_cmd_alloc())");
472 if (ct_command(conn->
command, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
473 ERROR(
"unable to initiate command structure (ct_command()");
478 if (ct_send(conn->
command) != CS_SUCCEED) {
479 ERROR(
"unable to send command (ct_send())");
483 results_ret = ct_results(conn->
command, &result_type);
484 switch (results_ret) {
486 switch (result_type) {
501 descriptor.datatype = CS_CHAR_TYPE;
502 descriptor.format = CS_FMT_NULLTERM;
504 descriptor.count = 1;
505 descriptor.locale = NULL;
509 rowdata = talloc_zero_array(conn,
char *, colcount + 1);
510 rowdata[colcount] = NULL;
512 for (i = 0; i < colcount; i++) {
517 if (ct_bind(conn->
command, i + 1, &descriptor, rowdata[i], NULL, NULL) != CS_SUCCEED) {
520 ERROR(
"ct_bind() failed)");
533 ERROR(
"query returned no data");
538 ERROR(
"unexpected result type from query");
551 ERROR(
"failure retrieving query results");
553 if (ct_cancel(NULL, conn->
command, CS_CANCEL_ALL) == CS_FAIL) {
554 ERROR(
"cleaning up");
563 ERROR(
"unexpected return value from ct_results()");
586 ret = ct_fetch(conn->
command, CS_UNUSED, CS_UNUSED, CS_UNUSED, &
count);
592 ERROR(
"failure fetching row data");
593 if (ct_cancel(NULL, conn->
command, CS_CANCEL_ALL) == CS_FAIL) {
594 ERROR(
"cleaning up");
610 ERROR(
"recoverable failure fetching row data");
615 ERROR(
"unexpected returncode from ct_fetch");
636 ct_cancel(NULL, conn->
command, CS_CANCEL_ALL);
637 if (ct_cmd_drop(conn->
command) != CS_SUCCEED) {
638 ERROR(
"freeing command structure failed");
656 DEBUG2(
"socket destructor called, closing socket");
659 ct_cancel(NULL, conn->
command, CS_CANCEL_ALL);
660 if (ct_cmd_drop(conn->
command) != CS_SUCCEED) {
661 ERROR(
"freeing command structure failed");
676 if (ct_close(conn->
db, CS_UNUSED) != CS_SUCCEED) {
677 ct_close(conn->
db, CS_FORCE_CLOSE);
680 ct_con_drop(conn->
db);
684 ct_exit(conn->
context, CS_UNUSED);
703 if (cs_ctx_alloc(CS_VERSION_100, &conn->
context) != CS_SUCCEED) {
704 ERROR(
"unable to allocate CS context structure (cs_ctx_alloc())");
712 if (ct_init(conn->
context, CS_VERSION_100) != CS_SUCCEED) {
713 ERROR(
"unable to initialize Client-Library");
718 if (ct_config(conn->
context, CS_GET, CS_LOGIN_TIMEOUT, (CS_VOID *)&timeout_ms, CS_UNUSED, NULL) != CS_SUCCEED) {
719 ERROR(
"Setting connection timeout failed");
727 if (cs_config(conn->
context, CS_SET, CS_MESSAGE_CB, (CS_VOID *)
csmsg_callback, CS_UNUSED, NULL) != CS_SUCCEED) {
728 ERROR(
"unable to install CS Library error callback");
733 if (cs_config(conn->
context, CS_SET, CS_USERDATA,
734 (CS_VOID *)&handle->
conn,
sizeof(handle->
conn), NULL) != CS_SUCCEED) {
735 ERROR(
"unable to set userdata pointer");
741 ERROR(
"unable to install client message callback");
747 ERROR(
"unable to install server message callback");
755 if (ct_con_alloc(conn->
context, &conn->
db) != CS_SUCCEED) {
756 ERROR(
"unable to allocate db structure");
767 if (ct_con_props(conn->
db, CS_SET, CS_USERNAME,
769 ERROR(
"unable to set username for db");
774 if (ct_con_props(conn->
db, CS_SET, CS_PASSWORD,
775 UNCONST(CS_VOID *,
config->sql_password), strlen(
config->sql_password), NULL) != CS_SUCCEED) {
776 ERROR(
"unable to set password for db");
784 if (ct_connect(conn->
db,
UNCONST(CS_CHAR *,
config->sql_server), strlen(
config->sql_server)) != CS_SUCCEED) {
785 ERROR(
"unable to establish db to symbolic servername %s",
820 .name =
"sql_freetds"
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
static fr_time_delta_t timeout
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
static const conf_parser_t config[]
Prototypes and functions for the SQL module.
char const * msg
Log message.
void * conn
Database specific connection handle.
sql_rcode_t
Action to take at end of an SQL query.
@ RLM_SQL_RECONNECT
Stale connection, should reconnect.
@ RLM_SQL_ERROR
General connection/server error.
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
rlm_sql_row_t row
Row data from the last query.
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, fr_time_delta_t timeout)
char ** results
Result strings from statement execution.
static CS_RETCODE CS_PUBLIC servermsg_callback(CS_CONTEXT *context, UNUSED CS_CONNECTION *conn, CS_SERVERMSG *msgp)
Server error handler.
static CS_RETCODE CS_PUBLIC csmsg_callback(CS_CONTEXT *context, CS_CLIENTMSG *emsgp)
Client error handler.
static sql_rcode_t sql_fetch_row(rlm_sql_row_t *out, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
CS_CONNECTION * db
Handle specifying a single connection to the database.
static int _sql_socket_destructor(rlm_sql_freetds_conn_t *conn)
static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
CS_COMMAND * command
A prepared statement.
static CS_RETCODE CS_PUBLIC clientmsg_callback(CS_CONTEXT *context, UNUSED CS_CONNECTION *conn, CS_CLIENTMSG *emsgp)
Client-Library error handler.
static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
static int sql_num_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
CS_INT rows_affected
Rows affected by last INSERT / UPDATE / DELETE.
bool established
Set to false once the connection has been properly established.
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, char const *query)
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, char const *query)
Execute a query when we expected a result set.
CS_CONTEXT * context
Structure FreeTDS uses to avoid creating globals.
static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
char * error
The last error string created by one of the call backs.
rlm_sql_driver_t rlm_sql_freetds
static sql_rcode_t sql_free_result(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Retrieves any errors associated with the connection handle.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
size_t strlcpy(char *dst, char const *src, size_t siz)
module_t common
Common fields for all loadable modules.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
static const char * names[8]
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
A time delta, a difference in time measured in nanoseconds.
static size_t char ** out